A Blog to Write about Everything

0%

人升开发日志#18 | 12/22 优化遇到的坑

这个系列好久没更新了(离目标日渐遥远

这段时间的开发其实遇到了不少问题,不过都没及时记录导致最后也忘记了。

这里记一下新鲜的优化遇到的坑吧。

桌面小部件

之前匆忙写的桌面小部件是不支持分别显示不同清单的,并且还只能显示“所有”。

需要实现在桌面小部件,点击可以直接选择清单。

这里选择了透明Activity+BottomSheetDialog的方案,看上去没打开应用就进行了选择。

实现清单选择功能

第一步:实现透明Activity

透明Style(其实是历史代码):

1
2
3
4
5
6
7
8
9
10
<style name="Transparent_Activity" parent="AppTheme.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowDisablePreview">true</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>

并且这个Activity应该是独立栈,所以将启动模式设置为singleInstance

并且在Activity处理Intent传递过来的appWidgetId参数,实现清单选择。

这里设计布局的时候遇到个小坑:

ImageButtonbackground不能直接设置为?attr/selectableItemBackgroundBorderless或者?attr/selectableItemBackground

当然,这不代表我们不能手动实现Ripple效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="oval">
<size android:width="20dp"

android:height="20dp" />
<solid android:color="#54cfcfcf" />
</shape>
</item>
<item>
<shape>
<solid android:color="#00000000" />
</shape>
</item>
</selector>

第二步:设置PendingIntent在点击按钮的时候启动Activity

大概代码:

1
2
3
4
5
6
7
8
val categoryChooseIntent = Intent(context, WidgetSelectCategoryActivity::class.java).apply {
putExtra("appWidgetId", appWidgetId)
}

/** 注意第二个参数是requestCode **/
val categoryChoosePendingIntent = PendingIntent.getActivity(context, appWidgetId * 10, categoryChooseIntent, PendingIntent.FLAG_UPDATE_CURRENT)

views.setOnClickPendingIntent(R.id.ib_category, categoryChoosePendingIntent)

一开始写没留意RequestCode,写死了一个数字。

然后导致Activity接收到的appWidgetId和触发事件的Widget对应不上。

解决方法也很简单,让每个Widget的PendingIntentRequestCode不一致即可。

第三步:持久化设置

我这里用的是字符串拼接appWidgetId为Key来持久化设置。

考虑到可能日积月累,增增删删桌面小部件可能导致插入了很多无用的K-V值,降低SP效率。

fun onDisabled(context: Context)方法里还对废弃的设置KV值进行了清理操作。

(该方法的调用时机是清空所有桌面小部件的时候)

第四步:调试失败

理应这样子应该就没问题了。

在Factory里再获取WidgetId然后去拿相应的设置信息,然后去查询对应的清单数据即可。

但是,实测还是失败。多个Widget还是只会显示同一个设置的清单。

摸索未果,祭出了StackOverflow也查询了半天,才在一个没什么人问津的问题找到了答案:

默认会复用Factory,所以需要在intent填充不同的Data,让其实例化多个Factory

文中用的方法是填充随机数据:

1
2
3
//set random data to initialize new Factory
Random rnd = new Random();
intent.setData(Uri.fromParts("content", String.valueOf(rnd.nextInt()), null));

其实直接用appWidgetId.toString()可能更高效:

1
intent.data = Uri.fromParts("content", (appWidgetId).toString(), null)

主题色功能

做完清单后,想到要实现将应用内的主题色适配到桌面小部件中:主要就是动态更改一个LinearLayout的背景颜色

如果只是需要改颜色的话,没什么大问题。

直接这样即可:

1
views.setInt(<View>, "setBackgroundResource", <ResId>)

但是我这里的布局用到了Shape实现圆角效果。

对应的类是GradientDrawable,查询一番,似乎没有什么好办法解决。

这里因为主题色是固定的,所以还能用比较基础的方法实现。

手动实现多个颜色的Shape XML,然后代码判断,用上述方法设置背景即可。

TextView设置android:autoLink后无法长按/滑动

解决办法可以参考: