移动开发笔记(十六) 高级技巧

全局获取Context的技巧

创建一个MyApplication

class MyApplication : Application(){
    companion object{
        @SuppressLint("StaticFieldLeak")
        lateinit var context: Context
    }

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

将Context设置成静态变量会产生内存泄露问题,但这里是Application的Context所以不用担心,加上注解让忽略警告。
修改AndroidManifest.xml设置程序启动时候初始化MyApplication类

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.viewmodeltest">

    <application
        android:name=".MyApplication"       <----------------------添加这里
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        ...
           </application>
</manifest>

我们可以直接获取全局Context,并直接使用了

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

使用Intent传递对象

1.Serializable方式
创建类实现Serializble这个接口

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

然后再Activity中可这样写

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

接下来在SecondActivity中获取这个对象

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

2.Parcelable方式
修改Person类

class Person : Parcelable{
    var name = ""
    var age =0
    override fun writeToParcel(dest: Parcel?, flags: Int) {
        dest?.writeString(name) //写出name
        dest?.writeInt(age) //写出age
    }
    override fun describeContents(): Int {
        return 0
    }    
    companion object CREATOR : Parcelable.Creator<Person>{
        override fun createFromParcel(source: Parcel?): Person {
           val person = Person()
            person.name = source?.readString() ?:"" //读取name
            person.age = source.readInt() //读取age
            return person
        }
        override fun newArray(size: Int): Array<Person?> {
           return arrayOfNulls(size)
        }
    }
 
}

其中descibeContents()方法直接返回0就可以了,除此之外我们还必须在Person类中提供一个CREATOR的匿名类实现。创建一个Parcelable.Creaator接口的一个实现,并将泛型指定为Person。
接下来在SecondActivity中获取这个对象
而newArray()方法中的实现,只需要调用arrayOfNulls()方法,并使用参数传入size作为数组大小,创建一个空的Person数组。

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

Kotlin提供了另一种更加简便的方法,前提所有数据必须封在对象主构造函数中

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

定制自己的日志工具

在编写项目时,上线后日志依旧会正常打印,这样不仅会降低程序效率,还可能会将一些机密数据泄露出去。

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.i(tag,msg)
        }
    }
    fun e(tag : String,msg : String){
        if(level <= ERROR){
            Log.i(tag,msg)
        }
    }

}

深色主题

1.强制转换深夜模式
右击res目录->New->Directory,创建一个values-v29目录,然后右击values-v29目录->New->Values resource file,创建一个styles.xml

<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:forceDarkAllowed">true</item>
    </style>
</resources>

除了forceDarkAllowed属性之外,其他内容都是从之前的styles.xml文件复制过来的。
2.手动修改
我们先删除values-v29目录
修改valuses/styles.xml中的代码

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>

但是标题栏和悬浮窗的颜色并没有改变
右击res目录->New-Directory创建一个values-night目录,右击values-night目录->New->Values resource file,创建一个colors.xml文件。

<resources>
    <color name="colorPrimary">#303030</color>
    <color name="colorPrimaryDark">#232323</color>
    <color name="colorAccent">#008577</color>
</resources>

3.
根据当前主题自动切换颜色的主题属性

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="?android:attr/colorBackground">    <---------------------------背景颜色

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:textColor="?android:attr/textColorPrimary"/>     <----------------------------字体颜色

</androidx.constraintlayout.widget.ConstraintLayout>

还可以根据深色主题和浅色主题执行不同的逻辑

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

猜你喜欢

转载自blog.csdn.net/q327192368/article/details/107683130