全局获取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
}