kotlin的Anko库

Anko库是一个很强大库,我们可以从官网上的一段话看出来

Have you ever been tired of parsing SQLite query results using Android cursors? You have to write lots of boilerplate code just to parse query result rows, and enclose it in countless try…finally blocks to properly close all opened resources.

本文不会很多废话,直接干货上

1,在启动Activity方面 Intent

普通的启动方式

val intent = Intent(this, SomeOtherActivity::class.java)
intent.putExtra("id", 5)
intent.setFlag(Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)

那么使用了Anko库之后是这样使用的

startActivity(intentFor<SomeOtherActivity>("id" to 5).singleTop())

相信有人对这个FLAG_ACTIVITY_SINGLE_TOP表示不理解,这里简单的做个介绍
这里读者可以联想到Android中Activity中的启动模式
四种:

启动模式名称作用
1standard被启动就会创建一个新的
2singleTop栈顶单实例(当该activity处于task栈顶时,可以复用,直接onNewIntent)
3singleTask栈中单实例(oncreate该activity并销毁在他之上的其他activity)
4singleInstance全局单实例(应用场景:地图,Activity初始化需要大量资源)

那么这里的 FLAG_ACTIVITY_SINGLE_TOP 表示什么意思呢,这个和singleTop的功能类似,会销毁当前Activity栈上面的Activity后再启动一个新的SomeOtherActivity,但是也不是一定是启动新的SomeOtherActivity,如果SomeOtherActivity这个activity的启动模式standard会重新创建一个,但是如果不想重新创建一个新的Activity而使用栈中的Activity呢

intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);

那就使用这个Flag,使用这个启动后,跳转到指定的Activity中后,不会调用OnCreate方法而是会调用下面的方法

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
    }

还有一种情况就是,我不想清除当前Activity上的Activity,比如我启动了 A B C 三个Activity,如果按照上面的操作,从C跳转到A后,B就销毁了,但是不想它销毁想形成 B C A这样的呢,那就需要更改FLAG了

intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

这种做法就是启动模式中的singleTask

以上是扩展的部分,下面我们继续讲解 Anko库的Intent部分

传递多个参数的写法,这个是不需要传递Flag的写法

startActivity<SomeOtherActivity>(
    "id" to 5,
    "city" to "Denpasar"
)

当然管网还提供了其他形式的写法,有兴趣的可以去阅览

Anko-Intent 点击阅览

2,在Sqlite数据操作方面

Anko在数据库操作方面的是非常简洁的,我先把GitHub源码链接贴上来,大家有兴趣可以参考

使用数据库那么首先是要创建数据库的,这就涉及到ManagedSQLiteOpenHelper这个类



/**
 * object 定义了一个类 创建了一个对象
 */
object ContactTable {
    val NAME = "contact"

    //定义字段
    val ID= "_id"
    val CONTACT = "name"
}


class MySqlHepler(ctx: Context):ManagerSQLiteOpenHelper(ctx,NAME, null, VERSION){
    //在这里需要传递的是上下文,数据库的名字一般是在这里写死的,也可以传递
    //使用伴生对象,也就是java中的static模式
    comapnion object{
        val NAME = "imdb" 
        val VERSION = 1
        //这是一个单例模式
        private val instance: MySqlHelper? = null
         @Synchronized
         fun getInstance(ctx: Context):MySqlHelper{
             if(instance == null){
                 instance = MySqlHepler(ctx.applicationContext)
             }
         }
         return instance!!
    }
    
    //创建数据库
    override fun onCreate(db: SQLiteDatabase?){
        db?.create(ContactTable.NAME,true, ContactTable.ID to INTEGER+PRIMARY_KEY+AUTOINCREMENT,ContactTable.CONTACT to TEXT)
    }
    //数据库的升级
    override fun onUpgrade(db:SQLiteDatabase?,oldVersion:Int, newVersion: Int){
        db?.dropTable(ContactTable.NAME, true)
        oncreate(db)
        
    }
}

讲到这里,我们对比下使用java操作sqlite数据库,同样是类似的结构

public class StuDBHelper extends SQLiteOpenHelper { 
   
private static final String TAG = "TestSQLite"; 
public static final int VERSION = 1; 
   
//必须要有构造函数 
public StuDBHelper(Context context, String name, CursorFactory factory, 
int version) { 
super(context, name, factory, version); 
} 
   
// 当第一次创建数据库的时候,调用该方法  
public void onCreate(SQLiteDatabase db) { 
String sql = "create table stu_table(id int,sname varchar(20),sage int,ssex varchar(10))"; 
//输出创建数据库的日志信息 
Log.i(TAG, "create Database------------->"); 
//execSQL函数用于执行SQL语句 
db.execSQL(sql); 
} 
   
//当更新数据库的时候执行该方法 
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
//输出更新数据库的日志信息 
Log.i(TAG, "update Database------------->"); 
} 
}

3,增删查改

数据库创建完成后 接下来的事情就是增删查改的任务了


class IMDatabase{
    //相当于java中的静态方法
    compaion object{
        val databaseHelper = DatabaseHelper()
        val instance = IMDatabase()
    }
    //报存数据
    fun saveContact(contact: Contact){
        databaseHelper.use{
            //SQL的扩展方法 *表示展开
            insert(Contactable.NAME, *contact.map.toVararArray())
        }
    }
    //获取数据
    fun getAllContact():List<Contact> = databaseHelper.use{
        select(ContactTable.name).parseList(object:MapRowParse<Contact>{
            override fun parseRow(columns: Map<String, Any?>):Contact{
                return Contact(columns.toMutableMap())
            }
        })
        
    }
    //删除所有的数据
    fun deleteAllContacts(){
        databaseHelper.use{
            delete(ContactTable.NAME,null,null)
        }
    }
    
}
//这个扩展方法是这样的
fun<K,V> MutableMap<K, V>.toVararArray():Array<Pair<K,V>>{
    //将 MutableMap转化为Pair类型的数组
    return map{
        Pair(it.key, it.value)
    }.toTypedArray()
}

anko提供的这种方式用起来比较费劲,不如直接执行SQL来的简洁。查询数据时,分为3种情况,1查询一行数据,对应的数据需要使用数据解析器的parseSingle(rowParser)来返回;2查询最多一行数据,使用parseOpt(rowParser)来返回结果;3查询多行,使用parseList(rowParser)来解析。对于复杂数据来说,一般需要自定义解析器。

方法描述
parseSingle(rowParser): T正好解析一行
parseOpt(rowParser): T?解析 0 行或者 1 行
parseList(rowParser): List解析 0 行或者多行
  • parseSingle
fun <T: Any> Cursor.parseSingle(parser: MapRowParser<T>): T = AnkoInternals.useCursor(this) {
    if (count != 1)
        throw SQLiteException("parseSingle accepts only cursors with getCount() == 1")
    moveToFirst()
    return parser.parseRow(readColumnsMap(this))
}
//可以看到源码,如果不是解析一行是会报错的
  • parseOpt
fun <T: Any> Cursor.parseOpt(parser: MapRowParser<T>): T? = AnkoInternals.useCursor(this) {
    if (count > 1)
        throw SQLiteException("parseSingle accepts only cursors with getCount() == 1 or empty cursors")
    if (count == 0)
        return null
    moveToFirst()
    return parser.parseRow(readColumnsMap(this))
}
//可以看到这个是解析一行或者0行的,不是这个的会报异常
  • parseList
fun <T: Any> Cursor.parseList(parser: MapRowParser<T>): List<T> = AnkoInternals.useCursor(this) {
    val list = ArrayList<T>(count)
    moveToFirst()
    while (!isAfterLast) {
        list.add(parser.parseRow(readColumnsMap(this)))
        moveToNext()
    }
    return list
}
//这个是解析0行或者多行的,并装在数组中,最后将整个数组返回
  • 自定义解析器
class MyRowParser : RowParser<Triple<Int, String, String>> {
    override fun parseRow(columns: Array<Any>): Triple<Int, String, String> {
        return Triple(columns[0] as Int, columns[1] as String, columns[2] as String)
    }
}

写到这里肯定很多都比较糊涂看不懂,说实话我刚开始接触也比较难受,先继续写

  • 删除表
dropTable("User", true)

源码

fun SQLiteDatabase.dropTable(tableName: String, ifExists: Boolean = false) {
    val escapedTableName = tableName.replace("`", "``")
    val ifExistsText = if (ifExists) "IF EXISTS" else ""
    execSQL("DROP TABLE $ifExistsText `$escapedTableName`;")
}

其实我们可以看到,这里其实就是拼接命名来执行而已,没什么难的,只不过大家对API不熟悉

注意 执行这些操作比如上面的 dropTable(“User”, true),都是需要放到database.use{}中来执行的,那么这个database.use{}中做了什么呢,我们来看一下源码

    fun <T> use(f: SQLiteDatabase.() -> T): T {
        try {
            return openDatabase().f()
        } finally {
            closeDatabase()
        }
    }

从上面我们呢可以知道kotlin是将这个函数传递进去然后openDatabase()后执行相关的操作,我们再挖一层,点到openDatabase()进去


    @Synchronized
    private fun openDatabase(): SQLiteDatabase {
        if (counter.incrementAndGet() == 1) {
            db = writableDatabase
        }
        return db!!
    }

还有剩下两个模块没来得及总结

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值