Launcher widget追加プロセス分析



http://blog.csdn.net/vinuslong/article/details/6633946
AndroidのAppWidgetとgoogle widgetと中移動のwidgetは概念ではありません.ここでのAppWidgetは、1つのプロセスのコントロールを別のプロセスのウィンドウに埋め込む方法にすぎません.Viewは別のプロセスで表示されますが、イベントの処理方法は元のプロセスにあります.これはXウィンドウの埋め込みウィンドウに似ています.
 
AppWidgetは最初は09年からやっていましたが、当時はよく知らなかったので、Memo Widgetを作りました.その後もAppWidgetのソースコードを見て実現しただけですが、コードを整理するのはよくありませんでした.
よく见て忘れて、忘れてから见て、気がふさいで、今特别にドキュメントを整理して、后で调べることができます
主に3つの部分に分かれています.
一つは序曲
二つ目はLauncherからAppWidgetの追加過程を分析することである.
三つ目は、AppWidgetServiceの起動と内部実装を分析することです.
 
 まず、RemoteView、AppWidgetHost、AppWidgetHost、AppWidgetHostViewなどの概念を理解する必要があります.
RemoteView:本物のViewではなく、Viewのインタフェースを実装していないが、Viewを記述するためのエンティティにすぎない.たとえば、Viewに必要なリソースIDと各コントロールのイベントレスポンスメソッドを作成します.RemoteViewは、プロセス間通信メカニズムを介してAppWidgetHostに渡されます.
AppWidgetHost
AppWidgetHostはAppWidgetを本当に収容する場所で、その主な機能は2つあります.
o AppWidgetServiceからのイベントをリスニングする:
class Callbacks extends IAppWidgetHost.Stub { public void updateAppWidget(int appWidgetId,RemoteViews views) { Message msg = mHandler.obtainMessage(HANDLE_UPDATE); msg.arg1 = appWidgetId;msg.obj = views; msg.sendToTarget(); }   public void providerChanged(int appWidgetId,AppWidgetProviderInfo info) { Message msg = mHandler.obtainMessage(HANDLE_PROVIDER_CHANGED);msg.arg1 = appWidgetId; msg.obj = info; msg.sendToTarget(); } }

これは主にupdateとproviderを処理します.changedは2つのイベントで、この2つのイベントに基づいてwidgetを更新します.
class UpdateHandler extends Handler { public UpdateHandler(Looper looper) { super(looper); }   public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_UPDATE: {updateAppWidgetView(msg.arg1, (RemoteViews)msg.obj); break; } case HANDLE_PROVIDER_CHANGED: {onProviderChanged(msg.arg1, (AppWidgetProviderInfo)msg.obj); break; } } } }

oもう一つの機能はAppWidgetHostViewを作成することです.前にRemoteViewは本当のViewではなく、Viewの説明にすぎず、AppWidgetHostViewこそ本当のViewだと言いました.ここでまずAppWidgetHostViewを作成し、AppWidgetServiceでappWidgetIdに対応するRemoteViewを検索し、最後にRemoteViewをAppWidgetHostViewに渡してupdateAppWidgetに向かいます.
public final AppWidgetHostView createView(Context context, int appWidgetId, AppWidgetProviderInfo appWidget) { AppWidgetHostView view = onCreateView(context, appWidgetId, appWidget);view.setAppWidget(appWidgetId, appWidget); synchronized (mViews) { mViews.put(appWidgetId, view); }RemoteViews views = null; try { views = sService.getAppWidgetViews(appWidgetId); } catch(RemoteException e) { throw new RuntimeException("system server dead?", e); }view.updateAppWidget(views); return view; }

AppWidgetHostView
AppWidgetHostViewは本物のViewですが、実際のAppWidgetのViewを収容するためのコンテナにすぎません.このAppWidgetのViewはRemoteViewの説明に従って作成されます.これはupdateAppWidgetで行いました.
public void updateAppWidget(RemoteViews remoteViews) { ... if (content == null && layoutId ==mLayoutId) { try { remoteViews.reapply(mContext, mView); content = mView; recycled = true; if(LOGD) Log.d(TAG, "was able to recycled existing layout"); } catch (RuntimeException e) { exception= e; } }   // Try normal RemoteView inflation if (content == null) { try { content =remoteViews.apply(mContext, this); if (LOGD) Log.d(TAG, "had to inflate new layout"); } catch(RuntimeException e) { exception = e; } } ... if (!recycled) { prepareView(content);addView(content); }   if (mView != content) { removeView(mView); mView = content; } ... }

remoteView.applyは実際のViewを作成しました.次のコードは次のとおりです.
public View apply(Context context, ViewGroup parent) { View result = null;   Context c =prepareContext(context);   Resources r = c.getResources(); LayoutInflater inflater =(LayoutInflater) c .getSystemService(Context.LAYOUT_INFLATER_SERVICE);   inflater =inflater.cloneInContext(c); inflater.setFilter(this);   result = inflater.inflate(mLayoutId,parent, false);   performApply(result);   return result; }

Hostの実現者
AppWidgetHostとAppWidgetHostViewは、フレームワークで定義された2つのベースクラスです.アプリケーションはこの2つのクラスを利用して自分のHostを実現することができます.Launcherはデフォルトのデスクトップで、Hostの実装者です.
LauncherAppWidgetHostViewはAppWidgetHostViewを拡張し、長押しイベントの処理を実現した.
LauncherAppWidgetHostはAppWidgetHostを拡張し、ここではonCreateViewをリロードし、LauncherAppWidgetHostViewのインスタンスを作成するだけです.
AppWidgetService
AppWidgetServiceの目的は、主にAppWidgetProviderとAppWidgetHostの結合を解くことです.AppWidgetProviderとAppWidgetHostの関係が固定されていると、AppWidgetは任意のプロセスで表示できません.AppWidgetServiceがあれば、AppWidgetProviderは自分のAppWidgetがどこに表示されているかを知る必要はありません.