Android笔记-ContentProvider call方法

  • ContentProvider call方法 使用.

  • 资料来源:

    https://developer.android.com/guide/topics/providers/content-providers
    https://juejin.im/entry/5a4c39605188257c4d1b8a4a

  • 更新

    1
    20.04.17 初始化

导语

  • 开始实现的 NoWakeLock 使用了 ContentProvider 标准的查询和插入,结果实在不尽如人意.太死板了.
  • 进入瓶颈,去翻 Xprivacylua 的源码,发现 Xprivacylua 也使用了 ContentProvider ,不过大段是自定义的 call 方法.
  • 从网上资料来看,call 方法确实灵活多了,也是同步的调用,底层与查询/插入都是一样的实现.传输数据一次不能超过 1M.传输的数据需要可序列化.

call 方法

  • 新建 ContentProvider 声明授权,就不加赘述了.

  • fun call(method: String, arg: String?, extras: Bundle?): Bundle? {}

    • method: String 一般是我们自定义 call 方法的方法名.
    • arg: String? 大概是可有可无的字段.
    • extras: Bundle? 传输数据的载体,需要从 Bundle 中取出对应数据.
  • 实际的例子也非常简单

    1
    2
    3
    4
    5
    6
    7
    override fun call(method: String, arg: String?, extras: Bundle?): Bundle? {
    //no need handler
    if (extras == null) {
    return null
    }
    return context?.let { ProviderHandler.getInstance(it).getMethod(method, extras) }
    }
  • 传入 method 到具体的 Handler,再根据具体的方法名,执行获取结果.(kt 真香😂)

  • 以一个 test 方法为例,因为 call 方法要求返回一个 Bundle? 这里直接返回了 “Test”.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @VisibleForTesting
    fun test(bundle: Bundle): Bundle? {
    val test = bundle.get("Test") as String?

    LogUtil.d(TAG, "$test")

    val tmp = Bundle()
    tmp.putString("Test", "Test")
    return tmp
    }
  • 调用 Test 方法

    1
    2
    3
    4
    5
    6
    fun getMethod(methodName: String, bundle: Bundle): Bundle? {
    return when (methodName) {
    "test" -> test(bundle)
    else -> null
    }
    }
  • AndroidTest 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    class NWLContentProviderTest {
    private var mContentResolver: ContentResolver? = null
    private val authority = "com.js.nowakelock"

    @Before
    fun setUp() {
    val context = ApplicationProvider.getApplicationContext<Context>()
    mContentResolver = context.contentResolver
    }

    @Test
    fun call() {
    val method = "test"
    val url = Uri.parse("content://$authority")

    val extras = Bundle()
    extras.putString("Test", "Test")

    val bundle = mContentResolver?.call(url, method, null, extras)
    //if (bundle != null) {
    // LogUtil.d("test1", bundle.toString())
    //}
    assertEquals(bundle!!.getString("Test"), "Test")
    }
    }
  • 执行测试,取回的结果也是 “Test”.

结语

  • 为了个 IPC 还折腾了 aidl + service. 还有 call 配合 service,加上之前的 XSharedPreferences ,几乎把android ipc 折腾全了..
  • 之后就是填坑了,希望能尽快填完.