Getting started with Kotlin in one week (5)

This chapter mainly introduces the use of generics, common generic functions, SharedPreferences, enumeration, and other knowledge points

1. Generics

In java, generics are mainly used to constrain the type of data in the code. Common generics are generally in the definition of classes and functions.
For example, there is a function called doSomething in the following code, which needs to pass in a certain type of data K and return data of type T, then the generic is defined as follows:

class TypeClass {

    fun <K,T>doSomething(k: K): T? {
        return null
    }

}

Of course, in java, our types support upper and lower bounds (extends) and lower bounds (super), and kotlin simplifies this operation. For example, I think the above function can pass in any type, so it can also be written like this:

class TypeClass {

    fun <K:Any,T:Any>doSomething(k: K): T? {
        return null
    }

}

In this way, when the data we pass in is any type of subclass, it can be passed. For example, if I pass a parameter of type String and return data of type Int, it can also be compiled.

The above is that generics are defined in functions. What if they appear in types? The above code can become:

class TypeClass <K:Any,T:Any>{

    fun doSomething(k: K): T? {
        return null
    }

}

The above code shows that the class has 2 types that need to be qualified. This is the practice of Java, but sometimes we need to know which type of incoming parameter type and which parameter is the type of the returned parameter. Here we refer to the C# language, can be changed to:

class TypeClass <in K:Any,out T:Any>{

    fun doSomething(k: K): T? {
        return null
    }

}

In the above code, in represents the type of the incoming parameter, and out represents using this type as the return value type of a function. Different functions can be declared multiple times by type and only need to be separated by commas. Let's see how the following code works:

//1.创建一个type1对象
var type1 = TypeClass<Any, String>()
//2.表达式右边函数的返回值根据上面的判断返回的类型应该是String(假如是"Hello Android !")
//3.那么表达式应该类似于  val doSomething:Any = "Hello Android !"
//  这样符合Java的逻辑 因为String是Any的子类
val doSomething: Any? = type1.doSomething(22.2)
Log.i("IT520", "doSomething $doSomething")

2. Use of SharedPreferences

For an APP, it is often necessary to save some configuration information inside the phone. If it is a simple key-value pair, we can use SharedPreferences. Suppose now I want to pass a Long type data to SharedPreferences. My purpose is this, put the The stored data operation is set to an object as a property delegate. When a property is set, it is directly stored in sp. When a property is accessed, data is retrieved from sp. The code is as follows:

class LongPreference(val ctx: Context, val name: String, val default: Long)
    : ReadWriteProperty<Any, Long> {

    val prefs: SharedPreferences by lazy {
        //创建SharedPreferences对应保存文件
        ctx.getSharedPreferences("defaultfile", Context.MODE_PRIVATE)
    }

    //当获取某个值的时候 调用该方法 内部将数据从SharedPreferences文件中取出
    override fun getValue(thisRef: Any, property: KProperty<*>): Long {
        return prefs.getLong(name, default)
    }

    //当设置某个值的时候 调用该方法 内部将数据存储到SharedPreferences文件中
    override fun setValue(thisRef: Any, property: KProperty<*>, value: Long) {
        prefs.edit().putLong(name,value).commit()
    }

}

Next, we can declare an object using the object keyword and return the above delegate property object via a function:

object DelegatesExt {

    fun longPreference(ctx: Context, name: String, default: Long)
            = LongPreference2(ctx, name, default)

}

What if the delegate is used? The following code should be used in MainActivity:

class MainActivity : AppCompatActivity(){

    var testValue: Long by DelegatesExt.longPreference(this, "zipCode", 0L)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //设置该值 就会间接调用该委托将数据存储进SP
        testValue = 22L
        Log.i("IT520", "$testValue")
}

3. Combine generics and sp to make the code more generic

Earlier we mentioned how to let the property delegate implement data storage, but the storage can only store Long type data. Next we'll retrofit the code with generics:

class PreferenceDelegate<T>(val ctx: Context, val name: String, val default: T)
    : ReadWriteProperty<Any, T> {

    val prefs: SharedPreferences by lazy {
        ctx.getSharedPreferences("defaultfile", Context.MODE_PRIVATE)
    }

    override fun getValue(thisRef: Any, property: KProperty<*>): T {
        return findSharedPreference(name, default)
    }
    //根据传递数据类型决定取出数据
    fun findSharedPreference(name: String, default: T): T {
        with(prefs) {
            val result: Any = when (default) {
                is Long -> getLong(name, default)
                is Int -> getInt(name, default)
                is Float -> getFloat(name, default)
                is String -> getString(name, default)
                is Boolean -> getBoolean(name, default)
                else -> throw IllegalArgumentException()
            }
            return result as T
        }
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        putSharedPreference(name, value)
    }

    //根据传递数据类型决定存放数据
    fun putSharedPreference(name: String, value: T) {
        with(prefs.edit()) {
            when (value) {
                is Long -> putLong(name, value).apply()
                is Int -> putInt(name, value).apply()
                is Float -> putFloat(name, value).apply()
                is String -> putString(name, value).apply()
                is Boolean -> putBoolean(name, value).apply()
                else -> throw IllegalArgumentException()
            }
        }
    }

}

object DelegatesExt {
    fun <T : Any> preference(ctx: Context, name: String, default: T)
            = PreferenceDelegate(ctx, name, default)
}

4. Enumeration

The technology of enumeration is similar to that of java, but a little improvement has been made. How to create an enumeration class?

enum class Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FIRDAY, SATURDAY
}

The improvement of enumeration is that in addition to providing an enumeration value, you can also add the enumeration's subsidiary information to the enumeration value. The following Int is the subsidiary information I simulate, which can be one or more:

enum class Direction(val value:Int){
    EAST(1),
    WEST(2),
    SOUTH(3),
    NORTH(4)
}

Next we can use enum variables:

//定义一个枚举变量
var today = Day.FIRDAY
//获取枚举变量的名称
Log.i("IT520", "FIRDAY name ${today.name}")
//获取枚举变量的索引
Log.i("IT520", "FIRDAY ordinal ${today.ordinal}")
//获取该枚举概念中所有数据的个数
Log.i("IT520", "Day size ${Day.values().size}")

5. Anko provides a new way to launch a new interface

As we mentioned in the previous articles, anko is a lightweight additional development package for kotlin in Android. His commons package provides a framework class Intents.kt to facilitate the use of Intents.

5.1 Add anko dependency package

In the project's build.gradle file, add the following code:

buildscript {
    ...
    ext.ANKO_VERSION = '0.10.0'
}

In the app's build.gradle file, add the following code:

dependencies {
    ...
    compile "org.jetbrains.anko:anko-commons:$ANKO_VERSION"
}

5.2 Intent starts a new interface

Suppose we have an interface called MainActivity and want to start a new SecondActivity with 2 parameters, then the startup code of MainActivity should be like this:

startActivity<SecondActivity>(
                SecondActivity.USERNAME_KEY to "xiaoming",
                SecondActivity.PWD_KET to "123")

5.3 Source code analysis

inline fun <reified T: Activity> Context.startActivity(vararg params: Pair<String, Any>) {
    AnkoInternals.internalStartActivity(this, T::class.java, params)
}

object AnkoInternals {
    fun internalStartActivity(
           ctx: Context,
           activity: Class<out Activity>,
           params: Array<out Pair<String, Any>>) {
        ctx.startActivity(createIntent(ctx, activity, params))
    }
}

Of course, if you look at the source code, you will find that this is really a great class. In addition to starting a new interface, it can also start services, send SMS, start browsers, send emails, share, etc...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326009482&siteId=291194637