AppWidget提供在 Launcher 中显示,诸如快捷操作,小工具等,如果只是提供快捷操作我想界面可以简洁,但如果AppWidget如果想提供类似广告和豆瓣电台那样效果的话,动态改变AppWidget,显示就显得很重要了,毕竟想在 Android 制胜的还是 UI 战争和用户体验~


Android 在 1.5 之后就取消了android:updatePeriodMillis="**" 的属性,有的说是30分钟,无从考证,除非看源代码,后续弄 ...


想要动态更新还是要自己写 Service 或者触发事件用 Receiver 更新都是可行的,后面文章会介绍AppWidget动态更新相关,现在比较澎湃想写关于 RemoteViews 在更新 AppWidget 中存在的问题!-。-,跟题目描述一样,我们都知道 AppWidget 更新是用 RemoteViews 来更新的,但你有没有发现一个问题:当你更新频繁的时候,你是不是用一个 RemoteViews 引用来动态更新,而不是每次在去栈中申请一个变量,如果是,这就对了这篇文章可以解决你的问题!


先说我的情况,为了节省 Android 资源,我用一个 RemoteViews 来动态绑定更新 AppWidget ,又为了动画效果,频繁使用addView,removeAllViews,导致后面程序使用 Android 设备运行缓慢,出现 ANR, 或者更新图片缓慢...


RemoteViews 介绍:

A class that describes a view hierarchy that can be displayed in another process. The hierarchy is inflated from a layout resource file, and this class provides some basic operations for modifying the content of the inflated hierarchy.

因为 RemoteViews 并不像 ViewsGroup 那样强大,所以动画效果就限制了, 可以用 layoutAnimation,网络也有介绍,-。- 后续补上


先看网络友友问题:多个 widget 换肤问题响应速度慢

下面是网友最好提出的回答:AppWidget 内存溢出

AppWidget RemoteViews 内存溢出这几天在开发AppWidget时遇到一个奇怪问题:AppWidget上有一个时钟,使用TIME_TICK每分钟更新一次时间,问题是在长时间待机后出现,AppWidget上的时间不能与系统时间同步(ERROR/JavaBinder(1847): !!! FAILED BINDER TRANSACTION !!!)。通过AIDL通信机制的流程找到这个Log出现在android_os_Binder.cpp文件中android_os_BinderProxy_transact函数内部,原本是一个OutOfMemoryError,这是AIDL Client端访问时传递的Parcelable包过大而引起的错误,而RemoteViews就是一个实现了Parcelable接口的类,它作为AppWidget视图组件传递的数据结构通过AIDL在AppWidget应用向Launcher传递。产生这个问题的原因主要在于,RemoteViews的set系列函数在其内部会转换成Action对象存放在在ArrayList<Action>中,而在RemoteViews中没有对这个ArrayList<Action>进行清理的操作。而由于更新频率比较高在设计这个应用时把updateAppWidget()操作放在了Service中,并且每次都在重复使用这个RemoteViews对象,这就造成RemoteViews中的ArrayList<Action>中的数据越来越大,造成内存溢出错误。所以每个RemoteViews对象最好不要重复使用

至于为什么,为什么单用一个 RemoteViews 就会出现这样的问题呢,ArrayList <Action> 又是什么?


先看RemoteViews Source里面都是 RemoteViews 的源代码:

/** 成员变量 */// The package name of the package containing the layout resource. (Added to the parcel)private String mPackage;// The resource ID of the layout file. (Added to the parcel)private int mLayoutId;// An array of actions to perform on the view tree once it has been inflatedprivate ArrayList<Action> mActions; // 要处理的 Action


看看 AddAction 方法, 其实就是 ArrayList 搞的鬼!

private void addAction(Action a) {        if (mActions == null) {             mActions = new ArrayList<Action>();        }         mActions.add(a); }

看看 RemoteViews 的构造方法,列比较常用:

public RemoteViews(String packageName, int layoutId) {        mPackage = packageName;        mLayoutId = layoutId;}

看到把,他并没有初始化 ArrayList,也就是说你用同一对象的时候, ArrayList 底层引用还是同一个,所以会导致 ArrayList 不d断膨胀,最后内存溢出!至于为什么是同一个 ArrayList ,自己面壁一下!


而当你频繁使用addView,removeAllViews 来实现动画,我们来看看这个代码:

public void addView(int viewId, RemoteViews nestedView) {         addAction(new ViewGroupAction(viewId, nestedView));}
public void removeAllViews(int viewId) {         addAction(new ViewGroupAction(viewId, null));}


都是调用到AddAction,并且每次 更新 AppWiget 的时候都会引起 GC(垃圾回收)工作,GC工作是很耗资源的,并且也需要事件,所以当你是线程在工作,源源不断的执行命令,又要等到 Android 设备反应,期间慢就正常了!


下面是自己的实验:使用单一 RemoteView 和每次新生成一个的区别




可以看到对比,GC 工作多么频繁啊~ 资源资源啊 -。-

下一篇补上 动态更新 Widget ...


更多相关文章

  1. Android(安卓)的HashMap介绍
  2. Android中Context的总结及其用法
  3. 利用Android(安卓)Studio、MAT对Android进行内存泄漏检测
  4. 【Android】学习笔记(6)――ListView(上)
  5. 【Android】学习笔记(9)――SQLite简单使用
  6. Android--GreenDao
  7. Android(安卓)ArrayList LinkedList Set HashMap的介绍
  8. Android实现监测网络变化以及无网络listview填充 简易新闻(十六
  9. 【Android(安卓)Training - 03】使用Fragments建立动态的UI [ Le

随机推荐

  1. android下为自己定义wifimanager类
  2. View 绘制机制 -- How Android(安卓)Draw
  3. 一维byte数组旋转
  4. 使用Notification发送消息通知
  5. Android(安卓)TextView 一些字体颜色、大
  6. Android录音,拍照,摄像
  7. 在ubuntu9.10下build android(转)
  8. Android(安卓)给圆形头像加边框
  9. android greenDao 编译问题总结
  10. Android可控图片旋转