我首先创建一个 LoadingSlice,然后在通过 Rest API 加载切片内容后,使用“sliceUri”刷新切片。
context.contentResolver.notifyChange(sliceUri, null)
我的代码在 App Action Test Tool 中运行良好,但无法通过 Google 助手运行。Google Assistent 正确创建了正在加载的 Slice,但在 API 调用后不会刷新已创建的 Slice 的内容。
动作.xml
<?xml version ="1.0" encoding ="utf-8"?>
<actions>
<action intentName="custom.actions.intent.CHECK_IN" queryPatterns="@array/ExampleInQueries">
<fulfillment
fulfillmentMode="actions.fulfillment.SLICE"
urlTemplate="content://com.myapp.v3.slices.provider/checkin">
</fulfillment>
</action>
</actions>
AndroidManifest.xml
<provider
android:name=".slices.MySliceProvider"
android:authorities="com.myapp.v3.slices.provider"
android:grantUriPermissions="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.app.slice.category.SLICE" />
</intent-filter>
</provider>
MySliceProvider.kt
class MySliceProvider: SliceProvider() {
private lateinit var contextNonNull: Context
override fun onCreateSliceProvider(): Boolean {
contextNonNull = context ?: return false
return true
}
companion object {
internal const val SLICE_AUTHORITY = "com.myapp.v3.slices.provider"
var contentLoaded = false
}
private val lastSlices = mutableMapOf<Uri, HCMSlice>()
override fun onBindSlice(sliceUri: Uri): Slice {
return lastSlices.getOrPut(sliceUri) { createNewSlice(sliceUri) }.getSlice()
}
private fun createNewSlice(sliceUri: Uri): HCMSlice {
loadEnabled = false
when (sliceUri.path) {
DeepLink.CHECKINP -> {
return MyCheckSlice(
context = contextNonNull,
sliceUri = sliceUri
)
}
else -> MySlice.Unknown(contextNonNull, sliceUri)
}
}
}
MyCheckSlice.kt
class MyCheckSlice(
context: Context,
sliceUri: Uri
) : MySlice(context, sliceUri), KodeinAware{
override val kodein by kodein(context)
private val authDataHandler: AuthDataHandler by instance()
private val authSettings: AuthSettings by instance()
private val dashboardRepository: DashboardRepository by instance()
override fun getSlice(): Slice {
fetchLeaveTypes()
return if (contentLoaded) {
createStatsSlice()
} else {
createLoadingSlice()
}
}
private fun createStatsSlice(): Slice {
return list(context, sliceUri, ListBuilder.INFINITY) {
row {
setTitle(context.getString(R.string.slice_success),false)
setSubtitle("", false)
primaryAction = createActivityAction()
}
}
}
private fun createLoadingSlice(): Slice = list(context, sliceUri, ListBuilder.INFINITY) {
row {
setTitle(context.getString(R.string.slice_processing),true)
setSubtitle("", true)
primaryAction = createActivityAction()
}
}
private fun fetchShift() {
authSettings.checkAuthorizationService(object :
AuthStateResultListener {
override fun onStateSuccess() {
Coroutines.main {
try {
val getCalculateLeaveHoursResponse = dashboardRepository.getShift(
getCurrentDate()!!
)
getCalculateLeaveHoursResponse.let {
val jObject = JSONObject(it.data.toString())
val jObjShift = jObject.getJSONObject("shift")
shiftCode = jObjShift.getInt("shiftCode")
contentLoaded = true
refresh()
return@main
}
} catch (e: ApiException) {
Log.e("TAG", "fetchShiftApiException")
saveTimeInOut()
} catch (e: NoInternetException) {
Log.e("TAG", "fetchShiftNoInternetException")
} catch (e: HTTPRequestException) {
Log.e("TAG", "fetchShiftHTTPRequestException")
} catch (e: ApiNocontentException) {
Log.e("TAG", "fetchShiftApiNocontentException")
saveTimeInOut()
}
}
}
override fun onStateFailure() {
Log.e("TAG", "fetchShiftonStateFailure")
}
override fun onStateSignout() {
Log.e("TAG", "fetchShiftonStateSignout")
}
})
}
}
我的切片.kt
abstract class MySlice(val context: Context, val sliceUri: Uri) {
protected val handler = Handler(Looper.getMainLooper())
abstract fun getSlice(): Slice
protected fun refresh() {
context.contentResolver.notifyChange(sliceUri, null)
}
protected fun createActivityAction(): SliceAction {
val intent = Intent(context, MainActivity::class.java)
return SliceAction.create(
PendingIntent.getActivity(context, 0, intent, 0),
IconCompat.createWithResource(context, R.drawable.ic_launcher),
ListBuilder.SMALL_IMAGE,
context.getString(R.string.slice_enter_app_hint)
)
}
class Unknown(context: Context, sliceUri: Uri) : MySlice(context, sliceUri) {
override fun getSlice(): Slice = list(context, sliceUri, ListBuilder.INFINITY) {
row {
title = context.getString(R.string.slice_uri_not_found)
primaryAction = createActivityAction()
}
setIsError(true)
}
}
}
使用 App Action Test 工具时的示例 LOG
2021-05-21 18:09:19.780 11102-11120/com.myapp.v3 E/TAG: onSlicePinned
2021-05-21 18:09:19.786 11102-11125/com.myapp.v3 E/TAG: onBindSlice
2021-05-21 18:09:19.786 11102-11125/com.myapp.v3 E/TAG: createNewSlice
2021-05-21 18:09:19.786 11102-11125/com.myapp.v3 E/TAG: content://com.myapp.v3.slices.provider/checkin
2021-05-21 18:09:20.029 11102-11125/com.myapp.v3 E/TAG: contentLoaded=false
2021-05-21 18:09:20.034 11102-11125/com.myapp.v3 E/TAG: createLoadingSlice
2021-05-21 18:09:29.743 11102-11102/com.myapp.v3 E/TAG: fetchShift
2021-05-21 18:09:29.752 11102-11125/com.myapp.v3 E/TAG: onBindSlice
2021-05-21 18:09:29.753 11102-11125/com.myapp.v3 E/TAG: contentLoaded=true
2021-05-21 18:09:29.753 11102-11125/com.myapp.v3 E/TAG: createStatsSlice
示例 LOG 使用 Google 助手时
2021-05-21 18:10:26.831 11102-11120/com.myapp.v3 E/TAG: onSlicePinned
2021-05-21 18:10:26.833 11102-11125/com.myapp.v3 E/TAG: onBindSlice
2021-05-21 18:10:26.833 11102-11125/com.myapp.v3 E/TAG: createNewSlice
2021-05-21 18:10:26.833 11102-11125/com.myapp.v3 E/TAG: content://com.myapp.v3.slices.provider/check?name=idcheckin
2021-05-21 18:10:26.864 11102-11125/com.myapp.v3 E/TAG: contentLoaded=false
2021-05-21 18:10:26.864 11102-11125/com.myapp.v3 E/TAG: createLoadingSlice
2021-05-21 18:10:26.929 11102-11125/com.myapp.v3 E/TAG: onSliceUnpinned
2021-05-21 18:10:27.542 11102-11102/com.myapp.v3 E/TAG: fetchShift