1、管理全局状态信息
还需要告知系统,当程序启动的时候应该初始化MyApplication类,而不是默认的Application类。这一步也很简单,在AndroidManifest.xml文件的标签下进行指定就可以了。
<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.JetpackApp"
tools:targetApi="31">
这样我们就实现了一种全局获取Context的机制,之后不管你想在项目的任何地方使用Context,只需要调用一下MyApplication.context就可以了。
例如,简化Toast
package com.jpc.jetpackapp
import android.widget.Toast
object ToastUtil {
fun String.showToast(duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(MyApplication.context, this, duration).show()
}
fun Int.showToast(duration: Int = Toast.LENGTH_SHORT){
Toast.makeText(MyApplication.context, this, duration).show()
}
}
// 调用
"hello".showToast()
2、使用Intent传递对象
(1)方式一 Serializable
Serializable是序列化的意思,表示将一个对象转换成可存储或可传输的状态。序列化后的对象可以在网络上进行传输,也可以存储到本地。至于序列化的方法非常简单,只需要让一个类去实现Serializable这个接口就可以了。
定义对象
package com.jpc.jetpackapp
import java.io.Serializable
class Person: Serializable {
// 需要默认值
var name: String = ""
var age: Int = 0
}
传递值
val person = Person()
person.name = "Tom"
person.age = 20
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra("person_data", person)
startActivity(intent)
获取值
val person = intent.getSerializableExtra("person_data") as Person // 就是反序列化
(2)方式二 Parcelable
也可以实现相同的效果,不过不同于将对象进行序列化,Parcelable方式的实现原理是将一个完整的对象进行分解,而分解后的每一部分都是Intent所支持的数据类型,这样就能实现传递对象的功能了。
package com.jpc.jetpackapp
import android.os.Parcel
import android.os.Parcelable
class Student: Parcelable {
var name = ""
var age = 0
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(name) // 写出Name
dest.writeInt(age)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR: Parcelable.Creator<Student>{
override fun createFromParcel(source: Parcel?): Student {
val student = Student()
// 里读取的顺序一定要和刚才写出的顺序完全相同
student.name = source?.readString() ?: "" // 读取Name
student.age = source?.readInt() ?: 0
return student
}
override fun newArray(size: Int): Array<Student?> {
return arrayOfNulls(size)
}
}
}
val person = intent.getParcelableExtra("person_data") as Person
Kotlin给我们提供了另外一种更加简便的用法,但前提是要传递的所有数据都必须封装在对象的主构造函数中才行。
@Parcelize
class Person(var name: String, var age: Int) : Parcelable
Serializable的方式较为简单,但由于会把整个对象进行序列化,因此效率会比Parcelable方式低一些,所以在通常情况下,还是更加推荐使用Parcelable的方式来实现Intent传递对象的功能。
3、定制日志工具
package com.jpc.jetpackapp
import android.util.Log
object LogUtil {
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)
}
}
}
这样就把一个自定义的日志工具创建好了,之后在项目里,我们可以像使用普通的日志工具一样使用LogUtil。比如打印一行DEBUG级别的日志可以这样写。
LogUtil.d("TAG", "debug log")
我们只需要通过修改level变量的值,就可以自由地控制日志的打印行为。比如让level等于VERBOSE就可以把所有的日志都打印出来,让level等于ERROR就可以只打印程序的错误日志。
使用了这种方法之后,刚才所说的那个问题也就不复存在了,你只需要在开发阶段将level指定成VERBOSE,当项目正式上线的时候将level指定成ERROR就可以了。
4、使用视图绑定
android {
...
buildFeatures {
viewBinding = true
}
}
如果某个xml布局不使用
<LinearLayout
...
tools:viewBindingIgnore="true" >
...
</LinearLayout>
private lateinit var binding: ResultProfileBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ResultProfileBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
}
binding.name.text = viewModel.name
binding.button.setOnClickListener { viewModel.userClicked() }