360 plug-in solution RePlugin learning: data persistence, 360 replugin
Data Persistence includes file storage, SharedPreferences, database storage, ContentProvider, and network storage.
1. File Storage (excluding cache directory storage) and network storage
2. Use SharedPreferences
Store in "host"
Val sharedPreferences = applicationContext. getSharedPreferences ("testReplugin", Context. MODE_PRIVATE) sharedPreferences. edit (). putString ("first", "test"). apply ()
In the plug-in, retrieve
Val sharedPreferences = RePlugin. getHostContext (). applicationContext. getSharedPreferences ("testReplugin", Context. MODE_PRIVATE) val s = sharedPreferences. getString ("first", "default") // The Toast prompt is displayed. makeText (this, s. toString (), Toast. LENGTH_SHORT ). show ()
The pop-up Toast should be"Test"If RePlugin. getHostContext () is removed"Default".
The storage in the cache directory is similar to that in the sp file. In the plug-in, you must obtain the Directory through RePlugin. getHostContext.
3. database storage
Create DatabaseOpenHelper. kt in the host project
class DatabaseOpenHelper(context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { companion object { private val DB_NAME = "person_list.db" val TABLE_NAME = "person" private val DB_VERSION = 1 } override fun onCreate(db: SQLiteDatabase) { val SQL_CREATE_TABLE = "create table if not exists $TABLE_NAME(_id integer primary key, name varchar(64), description TEXT)" db.execSQL(SQL_CREATE_TABLE) } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { }}
Use PersonDao. kt for testing
class PersonDao(private val context: Context) { private var helper: SQLiteOpenHelper? = null fun insert(person: Person) { helper = DatabaseOpenHelper(context) val db = helper!!.writableDatabase db.execSQL("insert into person(name, description) values(?,?)", arrayOf(person.name!!, person.description!!)) db.close() Log.e("dbDao", person.name + ":" + person.description) }}
Create a database storage object class, Person. kt
class Person { var name: String? = null var description: String? = null}
Insert data in the plug-in Project
// Obtain the host classloader val hostClassLoader = RePlugin. getHostClassLoader () // get the Person class val person = hostClassLoader. loadClass ("com. test. qby. myapplication. pojo. person ") // obtain the Person object val personInstance = person. newInstance () // obtain the set Method val nameMethod = person. getDeclaredMethod ("setName", String: class. java) val descriptionMethod = person. getDeclaredMethod ("setDescription", String: class. java) // call the set Method and pass the parameter nameMethod. invoke (personInstance, "Data haha") descriptionMethod. invoke (personInstance, "Try database haha") // get the PersonDao class val personDao = hostClassLoader. loadClass ("com. test. qby. myapplication. dao. personDao ") // obtain the parameter to construct val constructor = personDao. getConstructor (Context: class. java) // obtain the PersonDao object val daoInstance = constructor. newInstance (RePlugin. getHostContext () // obtain the insertion method val insertMethod = personDao. getDeclaredMethod ("insert", person) // call the insert method insertMethod. invoke (daoInstance, personInstance)
Perform database operations through reflection.
4. Use ContentProvider
In the host project, DatabaseOpenHelper. kt is the same as above, and then create PersonProvider. kt to inherit ContentProvider
Class PersonProvider: ContentProvider () {private val TAG = this. javaClass. simpleName private var mDatabase: SQLiteDatabase? = Null private var mContext: Context? = Null private var mTable: String? = Null override fun onCreate (): Boolean {initProvider () return false}/*** clear old data during initialization, insert a data entry */private fun initProvider () {mTable = DatabaseOpenHelper. TABLE_NAME mContext = context mDatabase = DatabaseOpenHelper (mContext !!). WritableDatabase Thread (Runnable {mDatabase !!. ExecSQL ("delete from" + mTable !!) }). Start ()} override fun query (uri: Uri, projection: Array
?, Selection: String ?, SelectionArgs: Array
?, SortOrder: String ?): Cursor? {Val tableName = getTableName (uri) showLog (tableName + "query data") when (mUriMatcher. match (uri) {TABLE_CODE_PERSON // query all records-> return mDatabase !!. Query (tableName, projection, selection, selectionArgs, null) TABLE_CODE_PERSON_SINGLE // query a specific record-> {val where = expendSelection (uri, selection) return mDatabase !!. Query (tableName, projection, where, selectionArgs, null, null)} else-> throw IllegalArgumentException ("wrong uri")} override fun insert (uri: Uri, values: contentValues ?): Uri? {Val tableName = getTableName (uri) showLog (tableName + "insert data") val insert = mDatabase !!. Insert (tableName, null, values) mContext !!. ContentResolver. policychange (uri, null) return Uri. parse (PERSON_CONTENT_URI.toString () + "/" + insert)} override fun delete (uri: Uri, selection: String ?, SelectionArgs: Array
?) : Int {val tableName = getTableName (uri) showLog (tableName + "delete data") when (mUriMatcher. match (uri) {TABLE_CODE_PERSON-> {val deleteCount = mDatabase !!. Delete (tableName, selection, selectionArgs) if (deleteCount> 0) {mContext !!. ContentResolver. policychange (uri, null)} return deleteCount} TABLE_CODE_PERSON_SINGLE // delete a specific id record-> {val where = expendSelection (uri, selection) val deleteCount2 = mDatabase !!. Delete (tableName, where, selectionArgs) if (deleteCount2> 0) {mContext !!. ContentResolver. policychange (uri, null)} return deleteCount2} else-> throw IllegalArgumentException ("wrong uri")} override fun update (uri: Uri, values: ContentValues ?, Selection: String ?, SelectionArgs: Array
?): Int {val tableName = getTableName (uri) showLog (tableName + "update data") when (mUriMatcher. match (uri) {TABLE_CODE_PERSON-> return mDatabase !!. Update (tableName, values, selection, selectionArgs) TABLE_CODE_PERSON_SINGLE // update a specific id record-> {val where = expendSelection (uri, selection) val updateCount = mDatabase !!. Update (tableName, values, where, selectionArgs) if (updateCount> 0) {mContext !!. ContentResolver. policychange (uri, null)} return updateCount} else-> throw IllegalArgumentException ("wrong uri")}/*** the CRUD parameter is Uri, obtain the corresponding table name ** @ param Uri * @ return table name */private fun getTableName (uri: URI) based on the uri ): string {var tableName = "" val match = mUriMatcher. match (uri) when (match) {TABLE_CODE_PERSON_SINGLE, TABLE_CODE_PERSON-> tableName = DatabaseOpenHelper. TABLE_NAME} showLog ("UriMatcher" + uri. toString () + ", result:" + match) return tableName} override fun getType (uri: Uri): String? {When (mUriMatcher. match (uri) {TABLE_CODE_PERSON_SINGLE-> return "vnd. android. cursor. item/person "TABLE_CODE_PERSON-> return" vnd. android. cursor. dir/person "} return null}/*** obtain the query clause based on URI and query conditions ** @ param uri URI * @ param selection query condition * @ return query clause */private fun expendSelection (uri: uri, selection: String ?): String {val split = uri. toString (). split ("/". toRegex ()). dropLastWhile {it. isEmpty ()}. toTypedArray () val id = java. lang. long. getLong (split [split. size-1])! Var where = "id =" + id if (! TextUtils. isEmpty (selection) {where + = "and" + selection !!} Return where} private fun showLog (s: String) {Log. d (TAG, s + ":" + Thread. currentThread (). name)} companion object {private val mUriMatcher = UriMatcher (UriMatcher. NO_MATCH) val AUTHORITY = "com. test. qby. myapplication. provider. personProvider "// authorize val PERSON_CONTENT_URI = Uri. parse ("content: // $ AUTHORITY/person") private val TABLE_CODE_PERSON_SINGLE = 1 private val TABLE_CODE_PERSON = 2 init {// associate different Uris and codes to facilitate subsequent getType mUriMatcher. addURI (AUTHORITY, "person", TABLE_CODE_PERSON) // match: content: // com. test. qby. myapplication. provider. personProvider/person/number. The returned value is 1 mUriMatcher. addURI (AUTHORITY, "person/#", TABLE_CODE_PERSON_SINGLE )}}}
Register in the inventory file
Operation Provider in the plug-in
// ContentProvider // content provider URI val uri = Uri. parse ("content: // com. test. qby. myapplication. provider. personProvider/person ") // data val values = ContentValues () values. put ("name", "yyy") values. put ("description", "You guess I don't guess who you are") // insert the val insert = PluginProviderClient. insert (RePlugin. getHostContext (), uri, values) Log. e (TAG, insert. toString () // query the operation to obtain the cursor val cursor = PluginProviderClient. query (RePlugin. getHostContext (), uri, arrayOf ("name", "description"), null, null, "DESC") Log. e (TAG, "Number of queried entries ". plus (cursor. count) // print the result if (cursor. moveToNext () {val name = cursor. getString (cursor. getColumnIndex ("name") val description = cursor. getString (cursor. getColumnIndex ("description") Log. e (TAG, "name = $ name, description = $ description")} // close the cursor. close ()
There are a lot of code written in the place where reflection is used. When it is actually used, We need to extract it into the tool class and optimize the code.