AppWidget源码分析(2)---updateAppWidget过程分析.md

前面一篇文章,分析了AppWidgetProvider和RemoteView的源码,从中我们可以知道它们的实现原理,AppWidgetProvider是一个BroadcastReceiver,所以它是通过广播接收通知的,收到更新通知后,AppWidgetProvider需要去提供View供远程进程显示,而提供的View则是使用RemoteView来代替,通过RemoteView(是一个Parcelable,可跨进程传输数据类型)来作为媒介去传递给远程进程。由远程进程解析RemoteView,然后显示RemoteView表示的真正的View。在这篇文章将分析这个传输过程。

流程

还是先看一下上一篇给出的一个过程图示:

这里写图片描述

实际上,AppWidgetProvider是通过AppWidgetManager来更新View的,而AppWidgetManager里面是有一个IAppWidgetService,一看就知道这是一个idle生成的,是一个Binder通信。关于Binder通信我之前也写过一篇文章叫Android源码代理模式—Binder,可以参考一下。而服务端的AppWidgetService是AppWidgetServiceImpl,AppWidgetServiceImpl又会通过一个IAppWidgetHost来跨进程通知AppWidgetHost,AppWidgetHost内部的IAppWidgetHost是AppWidgetHost.Callback。这样就到了显示我们的AppWidget的进程(大部分是Launcher应用)。

分清楚每个部分是在什么进程运行的对于理解整个流程是非常有帮助的,AppWidgetProvider是在我们自己的应用程序进程当中,而AppWidgetService是运行在SystemServer进程,AppWidgetHost则是运行在显示AppWidget的进程中,比如Launcher应用(桌面)。整个流程相当于是跨越了三个进程。

updateAppWidgetIds过程分析

这是AppWidgetManager的一个接口函数,根据id来更新AppWidget。先把整个更新过程的时序图拿出来看一下:

这里写图片描述

从我们普通的调用AppWidgetManager的updateAppWidget看起吧:

    appWidgetManager.updateAppWidget(appwidgetids,remoteViews);
  1. 这里进入updateAppWidget方法:

public void updateAppWidget(int[] appWidgetIds, RemoteViews views) {
   if (mService == null) {
       return;
   }
   try {
       mService.updateAppWidgetIds(mPackageName, appWidgetIds, views);
   }
   catch (RemoteException e) {
       throw new RuntimeException("system server dead?", e);
   }
}

mService是一个IAppWidgetService类型,初始化是在SystemServiceRegistry(6.0才出现的,之前在ContextImpl里面)里面:


registerService(Context.APPWIDGET_SERVICE, AppWidgetManager.class,
       new CachedServiceFetcher<AppWidgetManager>() {
   @Override
   public AppWidgetManager createService(ContextImpl ctx) {
       IBinder b = ServiceManager.getService(Context.APPWIDGET_SERVICE);
       return new AppWidgetManager(ctx, IAppWidgetService.Stub.asInterface(b));
   }});

注册服务的时候获取APPWIDGET_SERVICE。所以mService.updateAppWidgetIds最后会调用到远程进程,而IAppWidgetService的实现者是AppWidgetServiceImpl,所以最终会调用AppWidgetServiceImpl的updateAppWidgetIds。

  1. AppWidgetServiceImpl中的updateAppWidgetIds:

@Override
public void updateAppWidgetIds(String callingPackage, int[] appWidgetIds,
       RemoteViews views) {
   if (DEBUG) {
       Slog.i(TAG, "updateAppWidgetIds() " + UserHandle.getCallingUserId());
   }

   updateAppWidgetIds(callingPackage, appWidgetIds, views, false);
}

这就是AppWidgetServiceImpl的updateAppWidgetIds方法。程序已经开始进入到AppWidgetServiceImpl所在的进程了,实际上是SystemServer进程。怎么看出AppWidgetServiceImpl是运行在SystemServer进程呢?AppWidgetService类new了一个AppWidgetServiceImpl,并且注册到ServiceManager中:


public class AppWidgetService extends SystemService {
   
   private final AppWidgetServiceImpl mImpl;

   public AppWidgetService(Context context) {
       super(context);
       mImpl = new AppWidgetServiceImpl(context);
   }

   @Override
   public void onStart() {
       publishBinderService(Context.APPWIDGET_SERVICE, mImpl); //注册mImpl到ServiceManager当中
       AppWidgetBackupBridge.register(mImpl);
   }

   @Override
   public void onBootPhase(int phase) {
       if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
           mImpl.setSafeMode(isSafeMode());
       }
   }
}

而AppWidgetService在SystemServer.java中使用:


private static final String APPWIDGET_SERVICE_CLASS =
       "com.android.server.appwidget.AppWidgetService";

SystemServer是通过反射的方式new一个AppWidgetService对象,然后调用它的start函数。很多service类都是这样启动的。

回到updateAppWidgetIds方

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值