android桌面小部件appwidget使用ListView或者StackView如何刷新
来源:互联网 发布:hadoop能用python吗 编辑:程序博客网 时间:2024/05/13 05:51
android的桌面小部件使用ListView和StackView刷新数据,找了半天网上了没个说明白的,自己研究了一上午,大概明白了小部件的整体机制。
如何实现StackView的小部件使用RemoteService,这些网上一堆,可以找一下。
如何刷新adapter中的数据先把结果贴上来。
使用如下方式,StackView的远端Adapter就会调用onDataSetChanged()
AppWidgetManager.getInstance(context).notifyAppWidgetViewDataChanged(entry.widgetId,R.id.appwidget_stack_view);
源码分析:
RemoteView是跑在系统进程中的,并没有在我们的App中,必须使用进程间通信才能通知真正的View来刷新。RemoteViews这个类只是个数据传输类同时还有些工具函数apply什么的,app调用upateWidget将数据传输到远端Service,之后远端就可以处理了。
OK,这里分析通知刷新,就不用反射一些方法了,直接远端调用onDataSetChanged()就可以了,看一下android是怎么调用的。
正文:
使用notifyAppWidgetViewDataChanged()方法,实际实现是在系统Service,AppWidgetServiceImpl.java中的notifyAppWidgetViewDataChanged()
@Override public void notifyAppWidgetViewDataChanged(String callingPackage, int[] appWidgetIds, int viewId) { final int userId = UserHandle.getCallingUserId(); if (DEBUG) { Slog.i(TAG, "notifyAppWidgetViewDataChanged() " + userId); } // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(callingPackage); if (appWidgetIds == null || appWidgetIds.length == 0) { return; } synchronized (mLock) { ensureGroupStateLoadedLocked(userId); final int N = appWidgetIds.length; for (int i = 0; i < N; i++) { final int appWidgetId = appWidgetIds[i]; // NOTE: The lookup is enforcing security across users by making // sure the caller can only access widgets it hosts or provides. Widget widget = lookupWidgetLocked(appWidgetId, Binder.getCallingUid(), callingPackage); if (widget != null) { scheduleNotifyAppWidgetViewDataChanged(widget, viewId); } } } }
在这个方法中查找到要刷新的widget,然后scheduleNotifyAppWidgetViewDataChanged(widget, viewId);看一下这个方法。
private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) { if (widget == null || widget.host == null || widget.host.zombie || widget.host.callbacks == null || widget.provider == null || widget.provider.zombie) { return; } SomeArgs args = SomeArgs.obtain(); args.arg1 = widget.host; args.arg2 = widget.host.callbacks; args.argi1 = widget.appWidgetId; args.argi2 = viewId; mCallbackHandler.obtainMessage( CallbackHandler.MSG_NOTIFY_VIEW_DATA_CHANGED, args).sendToTarget(); }
将查找到的widget的一些成员变量,通过Handler发送出去了。
case MSG_NOTIFY_VIEW_DATA_CHANGED: { SomeArgs args = (SomeArgs) message.obj; Host host = (Host) args.arg1; IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; final int appWidgetId = args.argi1; final int viewId = args.argi2; args.recycle(); handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId); } break;
找到Handler处理的部分,调用handleNotifyAppWidgetViewDataChanged来处理。
case MSG_NOTIFY_VIEW_DATA_CHANGED: { SomeArgs args = (SomeArgs) message.obj; Host host = (Host) args.arg1; IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2; final int appWidgetId = args.argi1; final int viewId = args.argi2; args.recycle(); handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId); } break;
最后绑定AppWidget的RemoteService这个Service就是为Widget的提供Adapter的Service,只要绑定成功就就回调方法onDataSetChangedAsync()代码如下
private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks, int appWidgetId, int viewId) { try { callbacks.viewDataChanged(appWidgetId, viewId); } catch (RemoteException re) { // It failed; remove the callback. No need to prune because // we know that this host is still referenced by this instance. callbacks = null; } // If the host is unavailable, then we call the associated // RemoteViewsFactory.onDataSetChanged() directly synchronized (mLock) { if (callbacks == null) { host.callbacks = null; Set<Pair<Integer, FilterComparison>> keys = mRemoteViewsServicesAppWidgets.keySet(); for (Pair<Integer, FilterComparison> key : keys) { if (mRemoteViewsServicesAppWidgets.get(key).contains(appWidgetId)) { final ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { IRemoteViewsFactory cb = IRemoteViewsFactory.Stub .asInterface(service); try { cb.onDataSetChangedAsync(); } catch (RemoteException e) { Slog.e(TAG, "Error calling onDataSetChangedAsync()", e); } mContext.unbindService(this); } @Override public void onServiceDisconnected(android.content.ComponentName name) { // Do nothing } }; final int userId = UserHandle.getUserId(key.first); Intent intent = key.second.getIntent(); // Bind to the service and call onDataSetChanged() bindService(intent, connection, new UserHandle(userId)); } } } } }
在RemoteViewsServices.java中
public synchronized void onDataSetChangedAsync() { onDataSetChanged(); }
回调了onDataSetChanged();刷新了数据。之后就是刷新了,没有继续分析stackView源码。
总结:appWidget,使用进程间通信的方式,来刷新其他进程的View,系统Service (AppWidgetServiceImpl)处理View更新,更新时将RemoteVeiws传输到系统Service中,通过WidgetId获得对应的实际View,调用RmoteView的apply,其实就是将RemoteView中的数据,使用反射的方式,应用到实际View的对应方法中。完成实际View的更新。
- android桌面小部件appwidget使用ListView或者StackView如何刷新
- 【Android】AppWidget桌面小部件
- Android桌面小部件AppWidget
- appwidget桌面小部件
- appwidget桌面小部件
- android 中的AppWidget(桌面小部件)
- Android桌面小部件AppWidget(1)
- Android桌面小部件AppWidget(2)
- Android中的AppWidget(桌面小部件)
- Android之AppWidget桌面小部件开发
- Android Widget 小部件(四---完结) 使用ListView、GridView、StackView、ViewFlipper展示Widget
- appWidget(桌面小部件)
- Android小部件AppWidget
- Android Launcher开发(二)AppWidget(桌面小部件)解析
- Android Launcher开发(二)AppWidget(桌面小部件)解析
- Android基础学习之AppWidget(桌面小部件)
- Android Launcher开发(二)AppWidget(桌面小部件)解析
- Android桌面小部件AppWidget:音乐播放器桌面控制部件Widget(3)
- 配置CORS解决跨域调用—反思思考问题的方式
- 谈谈对OS中的中间虚拟层的看法
- Struts网站基于Filter的XSS漏洞修复
- [leetcode]45. Jump Game II(Java)
- P1066 2^k进制数 NOIP 2006 提高组 第四题
- android桌面小部件appwidget使用ListView或者StackView如何刷新
- 响应式设计(responsive web design)的视图显示法
- TCP 握手与挥手
- color报错
- EJB学习笔记_10_依赖注入(beanname注入)
- BZOJ 1925: [Sdoi2010]地精部落 dp
- python的pygame涉猎
- zookeeper单机伪集群配置
- [leetcode]128. Longest Consecutive Sequence