Android之常见的使用技巧

news2025/1/4 16:09:26

文章目录

      • 1.全局获取Context的技巧
      • 2.使用Intent传递对象
        • Serializable方式
        • Parcelable方式
      • 3.定制自己的日志工具
      • 4.深色主题
      • 5.Java和Kotlin代码之间的转换

1.全局获取Context的技巧

在Android中,你会发现有很多地方都需要用到Context,例如:弹出Toast,启动Activity,发送广播,操作数据库,使用通知。
这个时候如果我们需要在项目的任何地方都能够获取到Context,Android提供了一个Application类,每当应用程序启动的时候,系统就会自动将这些类进行初始化。而我们可以定制一个自己的Application类,以便于管理程序内的一些全局的状态信息,比如全局Context
首先创建一个MyApplication

class MyApplication : Application() {
    companion object{
        lateinit var context: Context
    }

    override fun onCreate() {
        super.onCreate()
        context=this.applicationContext
    }
}

可以看到,MyApplication中的代码非常简单。这里我们在companion object中定义了一个context变量,然后重写父类的onCreate()方法,并将调用getApplicationContext()方法得到的返回值赋值给context变量,这样我们就可以以静态变量的形式获取context对象了。
接下来在AndroidManifest.xml文件中的< application >标签下进行指定就可以了。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.kotlintext">
 <application
        android:name="com.example.MyApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.KotlinText">
        ...
    </application>
</manifest>

这样我们就实现了一种全局获取Context的机制。
接下来比如我们定义的showToast()方法就可以这样写

fun String.showToast(duration:Int=Toast.LENGTH_SHORT){
Toast.makeText(MyApplication.context,this,duration).show()
}

现在只需要使用如下用法就能弹出一段文字提示:

"This is Toast".showToast()

2.使用Intent传递对象

使用Intent来传递对象有两种方式:Serializable和Parcelable。

Serializable方式

Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。至于序列化的方法非常简单,只需要让一个类去实现Serializable这个接口就可以了。
比如有一个Person类,其中包含了name和age这两个字段,如果想要将它序列化,就可以这样写:

class Person :Serializable{
    var name=""
    var age=0
}

这里我们让Person类实现了Serializable接口,这样所有的Person对象都是可序列化的。

        var person=Person()
        person.name="Tom"
        person.age=20
        val intent=Intent(this,SecondActivity::class.java)
        intent.putExtra("person_data",person)
        startActivity(intent)

可以看到,这里我们创建了一个Person的实例,并将它直接传入Intent的putExtra()方法中。由于Person类实现了Serializable接口,所以才可以这样写。
接下来在SecondActivity中获取这个对象也很简单,写法如下:

 val person= intent.getSerializableExtra("person_data") as Person

这里调用了Intent的getSerializableExtra()方法来获取通过参数传递过来的序列化对象,接着再将它向下转型为Person对象,这样我们就成功实现了使用Intent传递对象的功能。
需要注意的是,这种传递对象的工作原理是先将一个对象序列化成可存储或可传输的状态,传递给另外一个Activity后再将其反序列化成一个新的对象。虽然这两个对象中存储的数据完全一致,但他们实际上是不同的对象。

Parcelable方式

除了Serializable之外,使用Parcelable也可以实现相同的效果,不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样就能实现传递对象的功能了
修改Person中的代码,如下所示

class Person() :Parcelable{
    var name=""
    var age=0

    override fun describeContents(): Int {
        return 0
    }

    override fun writeToParcel(dest: Parcel?, flags: Int) {
        dest?.writeString(name)//写出name
        dest?.writeInt(age)//写出age
    }

    companion object CREATOR : Parcelable.Creator<Person> {
        override fun createFromParcel(parcel: Parcel): Person {
            val person=Person()
            person.name=parcel.readString() ?:""//读取name
            person.age=parcel.readInt()//读取age
            return person
        }

        override fun newArray(size: Int): Array<Person?> {
            return arrayOfNulls(size)
        }
    }

}

Parcelable的实现方式要稍微复杂一些。可以看到,首先我们让Person类实现了Parcelable接口,这样就必须重写describeContents()和writeToParcel()这两个方法。其中describeContents()方法返回0就可以了,而writeToParcel()方法,我们需要调用Parcel的writeXxx()方法,将Person类中的字段一一写出。
除此之外,我们还必须在Person类中提供一个名为CREATOR的匿名类实现。这里创建了 Parcelable.Creator接口的一个实现,并将泛型指定为了Person。接着需要重写createFromParcel()和newArray()这两个方法,在createFromParcel()方法中,我们要创建一个Person对象进行返回,并读取刚才写出name和age字段。其中name和age都是调用Parcel的readXxx()方法读取到的(注意这里读取的顺序一定要和刚才写出的顺序完全相同)而newArray()方法中的实现,只需要调用arrayOfNulls()方法,并使用参数中传入的size作为数组大小,创建一个空的Person数组即可。
接下来我们可以使用之前的代码传递Person对象,只不过在获取对象的时候需要稍加修改一下:

  val person = intent.getParcelableExtra<Person>("person_data")

但是这种方式实现起来比较复杂,为此Kotlin提供了另外一种更加简便的用法,但前提是要传递的所有数据都必须封装在对象的主构造函数中才行。
修改Person类中的代码,如下所示

@Parcelize
class Person(var name:String,var age:Int) :Parcelable{
}

对比一下,Serializable的方式较为简单,但是就将整个对象进行序列化,因此效率会比Parcelable方式低一些。

3.定制自己的日志工具

当我们编写一个比较庞大的项目,期间为了方便调试,在代码的多个地方打印了大量日志,当项目正式上线的时候仍然会照常打印,这样会降低程序的运行效率,还有可能将一些数据泄露出去。这个时候最理想的情况时能够自由地控制日志的打印,当程序处于开发阶段让日志打印出来,当程序上线之后就把日志屏蔽掉。
新建一个LogUtil单例类

object LogUtil {
    //const val 可见性为public final static
    private const val VERBOSE=1
    private const val DEBUG=2
    private const val INFO=3
    private const val WARN=4
    private const val ERROR=5
    private var level= VERBOSE
    fun v(tag:String,msg:String){
        if(level<= VERBOSE){
            Log.v(tag,msg)
        }
    }
    fun d(tag: String,msg: String){
        if(level<= DEBUG){
            Log.d(tag,msg)
        }
    }
    fun i(tag: String,msg: String){
        if(level<= INFO){
            Log.i(tag,msg)
        }
    }
    fun w(tag: String,msg: String){
        if(level<= WARN){
            Log.w(tag,msg)
        }
    }
    fun e(tag: String,msg: String){
        if(level<= ERROR){
            Log.e(tag,msg)
        }
    }

}

这样就把一个自定义的日志工具创建好了,比如打印一行DEBUG级别的日志就可以这样写:

 LogUtil.d("TAG","debug log")

打印一行WARN级别的日志就可以这样写:

LogUtil.w("TAG","warn log")

我们只需要通过修改level变量的值,就可以自由地控制日志的打印行为。比如让level等于VERBOSE就可以把所有的日志打印出来,让level等于ERROR就可以只打印程序的错误日志。

4.深色主题

深色主题除了让眼部在夜间使用时更加舒适之外,还可以减少电量消耗,从而延长手机续航。Android10.0及以上系统的手机,都可以在Settings→Display→Dark theme中对深色主题进行开启和关闭。开启深色主题后,系统的界面风格包括一些内置应用都会变成深色主题的色调。
在这里插入图片描述
但是你打开我们自己编写的应用程序,你会发现目前界面的风格还是使用的浅色主题模式,这就和系统的主题风格不同了,说明我们需要对此进行适配。
最简单的一种适配方式就是使用Force Dark,它是一种让应用程序快速适配深色主题,并且不用编写额外代码的方式。Force Dark的工作原理是系统会分析浅色主题应用下的每一层View,并且在这些View绘制到屏幕之前,自动将它们的颜色转换成更加适合深色主题的颜色。(注意,只有原本使用浅色主题的应用才能使用这种方式,如果你的应用原本使用的就是深色主题,Force Dark将不会起作用)。
启用Force Dark需要借助android:forceDarkAllowed属性

<item name="android:forceDarkAllowed">true</item>

这里android:forceDarkAllowed属性设置为true,说明现在我们是允许系统使用Force Dark将应用强制转换成深色主题的。
除此之外,还有另外一种实现方式,我们知道AppCompat库内置的主题恰好主要分为浅色主题和深色主题两类,比如Theme.AppCompat.Light.NoActionBar就是浅色主题,而Theme.AppCompat.NoActionBar就是深色主题。选用不同的主题,在控件的默认颜色等方面会有完全不同的效果。
而现在我们多了一个DayNight主题。使用了这个主题后,当用户在系统设置中打开了深色主题,应用程序会自动使用深色主题,反之使用浅色主题。
新建一个values-night

<resources xmlns:tools="http://schemas.android.com/tools">
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <!-- Primary brand color. -->
        <item name="colorPrimary">@color/purple_200</item>
        <item name="colorPrimaryVariant">@color/purple_700</item>
        <item name="colorOnPrimary">@color/black</item>
        <!-- Secondary brand color. -->
        <item name="colorSecondary">@color/teal_200</item>
        <item name="colorSecondaryVariant">@color/teal_200</item>
        <item name="colorOnSecondary">@color/black</item>
        <!-- Status bar color . -->
        <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
        <!-- Customize your theme here. -->
    </style>
</resources>

可以看到,这里我们将AppTheme的parent主题指定成了Theme.AppCompat.DayNight.NoActionBar,这是一种DayNight主题。因此,在普通情况下应用程序仍然会使用浅色主题,但一旦用户在系统设置中开启了深色主题,应用程序会自动使用深色主题。
我们应该更多地使用能够根据当前主题自动切换颜色的主题属性。比如说黑色的文字通常应该衬托在白色背景下,反之白色的文字通常应该衬托在黑色的背景下。那么此时我们可以使用主题属性来指定背景以及文字的颜色,写法如下:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="?android:attr/colorBackground"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World"
        android:layout_gravity="center"
        android:textSize="40sp"
        android:textColor="?android:attr/textColorPrimary"
        />
</FrameLayout>

在这里插入图片描述
在这里插入图片描述
另外当你需要在浅色主题和深色主题下分别执行不同的代码逻辑,可以使用如下代码在任何时候判断当前系统是否是深色主题:

    fun isDarkTheme(context: Context):Boolean{
        val flag=context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
        return flag==Configuration.UI_MODE_NIGHT_YES
    }

调用isDarkTheme()方法,判断当前系统时浅色主题还是深色主题,然后根据返回值执行不同代码逻辑即可。

5.Java和Kotlin代码之间的转换

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
点击窗口左上角的Decompile按钮,就可以将之前Kotlin代码编译成Java代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/189813.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式在项目中的运用

一、如何管理庞大而复杂的项目开发&#xff1f;1、从设计原则和思想的角度来看&#xff0c;如何应对庞大而复杂的项目开发&#xff1f;① 封装与抽象&#xff1a;“一切皆文件”:封装了不同类型设备的访问细节&#xff0c;抽象为统一的文件访问方式&#xff0c;更高层的代码就能…

windows下解决Git报错: LF will be replaced by CRLF the next time Git touches it

问题 在命令行执行git add *的时候&#xff0c;提示Warning&#xff1a; 通常情况下是在 Windows环境中才会遇到。 原因 Uinx/Linux采用换行符LF表示下一行&#xff08;LF&#xff1a;LineFeed&#xff0c;中文意思是换行&#xff09;&#xff0c;即&#xff1a;\n&#xff1…

Visual Transformer开端——ViT及其代码实现

深度学习知识点总结 专栏链接: https://blog.csdn.net/qq_39707285/article/details/124005405 此专栏主要总结深度学习中的知识点&#xff0c;从各大数据集比赛开始&#xff0c;介绍历年冠军算法&#xff1b;同时总结深度学习中重要的知识点&#xff0c;包括损失函数、优化器…

购买和登录Linux云服务器

目录 云服务器的购买 SSH登录云服务器 云服务器的购买 我们以腾讯云为例, 其他的服务器厂商也是类似。 1. 进入腾讯云官方网站&#xff1a;学生云服务器_云校园特惠套餐 - 腾讯云 (tencent.com) 2. 登陆网站(可以使用微信登陆) 3.购买云服务器 购买最低级即可&#xff0c;对于…

36/365 java 类的加载 链接 初始化 ClassLoader

1.类的加载&#xff0c;链接&#xff0c;初始化 注意点&#xff1a; Class对象是在类的加载过程中生成的&#xff08;类的数据&#xff08;static,常量&#xff0c;代码&#xff09;在方法区&#xff0c;Class类对象在堆中&#xff09;&#xff0c;这个Class类对象作为方法区中…

Canvas 实现台球假想球精准定位

1. 前言 台球是一个让人非常着迷的运动项目&#xff0c;充满了各种计算逻辑&#xff0c;十分有趣。 对于初学者&#xff0c;母球、目标球、袋口三者在一条线上的时候&#xff0c;是非常容易进球的&#xff0c;但对于三者不在一条线上时&#xff0c;就是需要假想球的帮助&…

Windows 上安装 Insomnia 代替 Postman

Windows 上安装 Insomnia 代替 PostmanInsomnia 概述官网地址下载和安装 Insomnia使用 InsomniaInsomnia 概述 Insomnia 是一个开源桌面应用程序&#xff0c;它提供了设计、调试和测试API的简单方法。 通过对开发者友好的界面、内置的自动化和可扩展的插件生态系统&#xff0…

自动驾驶中间件:量产落地的关键技术

/ 导读 /对于初入自动驾驶行业的人来说&#xff0c;各色各样的新型传感器、线控系统、芯片域控制器、算法软件似乎是自动驾驶未来实现的重中之重&#xff0c;对于中间件大多数人可能都不太熟悉&#xff0c;有些甚至从未听说过其存在。但中间件却也是极为重要的一环&#xff0c;…

设计模式-创建型模式

目录 4.创建型模式 4.1 单例设计模式 4.1.1 单例模式的结构 4.1.2 单例模式的实现 4.1.3 存在的问题 4.1.4 JDK源码解析-Runtime类 4.2 工厂模式 4.2.1 概述 4.2.2 简单工厂模式 4.2.3 工厂方法模式 4.2.4 抽象工厂模式 4.2.5 模式扩展 4.2.6 JDK源码解析-Collecti…

Kotlin~生成器模式

介绍 主要作用 逐步构造复杂对象&#xff0c;该对象的属性更多的扩展属性&#xff0c;如Glide的使用。 组成 Builder&#xff1a;提供逐步创建产品的步骤 Director&#xff1a;创建可复用的特定产品&#xff08;规定Builder规定一系列的步骤创建产品&#xff0c;非必须&…

21新版FL Studio水果电音编曲Daw宿主软件好不好用?

首先是FL Studio&#xff08;以下简称FL&#xff09;的逻辑和其它宿主软件都不太一样&#xff0c;FL的逻辑就与众不同。FL的逻辑也可以分为三部分&#xff1a;通道机架、混音台和播放列表。在Live里每个发送轨都可以插入一个乐器以及若干个效果器。你有200个发送轨&#xff0c;…

vcenter 起不来报错VMware ESX 找不到虚拟磁盘“vCenter Server 7.0U3_12.vmdk”。请确认路径有效并重试

针对无快照时丢失.vmdk描述符文件&#xff1a;基础磁盘文件为-flat.vmdk是存在的 那个可以进行恢复操作步骤如下1.确定 flat.vmdk基础磁盘文件的大小&#xff08;字节&#xff09;2.创建与flat.vmdk相同大小的新的空虚拟磁盘。3.重命名新创建的.vmdk磁盘的描述符文件匹配原始虚…

如何运行一个py项目

在pycharm中打开项目文件确保安装python环境此时是使用python3.7版本&#xff0c;没有的话需要添加环境&#xff1a;add interpreter在anaconda&#xff08;安装参考https://blog.csdn.net/m0_67357141/article/details/123633490&#xff09;中选择基础环境&#xff08;base&a…

Python中的列表

1.创建列表 使用中括号把要添加的元素括起来&#xff0c;不同元素用逗号隔开。 >>> rhyme [1, 2, 3, 4, 5, "上山打老虎"] >>> print(rhyme) [1, 2, 3, 4, 5, 上山打老虎]2.访问列表中的元素 &#xff08;1&#xff09;希望顺序访问列表中的元…

博弈论入门

分类 要素 常见博弈 完全信息静态博弈 纳什均衡 囚徒困境 古诺双寡头模型 古诺双寡头模型的条件 市场中有且仅有两家公司策略为同质商品的量&#xff0c;qiq_iqi​边际成本为c&#xff0c;生产成本就为c*q&#xff0c;在这里我们的边际成本是常数。需求曲线&#xff1a;Pa−b∗…

2009-01-从学校毕业步入社会

在一间坐满学生的教室中&#xff0c;台上同学正在对自己毕业答辩项目进行介绍&#xff0c;台下第一排坐着打分的老师&#xff0c;这群人正在进行计算机专业的毕业答辩&#xff0c;台下人群中一个叫刘文轩的同学紧张又期盼的看着前面正在进行答辩的同学&#xff0c;看着同学们优…

react中useReduer和useEffect

相信很多人对于变成中reduce、reducer命名都存在困惑&#xff0c;为了更好理解useRedecuer&#xff0c;我们不妨先来说说reduce。 如何理解reduce和reducer reduce&#xff1a;函数式编程当中的一个术语&#xff0c;reduce操作被称为Fold折叠 // 通过reduce&#xff0c;数组…

公司内部有奖知识答题活动怎么做

公司年会趣味问答、员工业务知识考核、消防安全、党史等知识测试......公司内部的答题活动已经成了众多管理者、HR日常工作中一部分。如何让组织者更轻松、更公平公正地举办答题活动&#xff1f;如何让员工更积极参与呢&#xff1f;试试答题小博士的有奖答题。有奖答题活动形式…

中晶FileScan 3222扫描仪 Code:-206,卡纸或滚筒出错

中晶FileScan 3222是中晶品牌下的一款扫描仪。 型号 3222 产品类型 平板式+馈纸式 扫描光源 LED

机器人中的数值优化之BFGS(convex and smooth)

本文ppt来自深蓝学院《机器人中的数值优化》 目录 1 Why Quasi-Newton Methods 2 Rate of convergence 3 Quasi-Newton Methods 3.1 Quasi-Newton approximation 3.2 preserve descent direction 3.3 secant condition 3.4 iterate B 3.5 Parsed solution B 4 Cont…