1. <nobr id="easjo"><address id="easjo"></address></nobr>

      <track id="easjo"><source id="easjo"></source></track>
      1. 
        

      2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
      3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>
          貴州做網站公司
          貴州做網站公司~專業!靠譜!
          10年網站模板開發經驗,熟悉國內外開源網站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等網站程序,可為您提供網站建設,網站克隆,仿站,網頁設計,網站制作,網站推廣優化等服務。我們專注高端營銷型網站,企業官網,集團官網,自適應網站,手機網站,網絡營銷,網站優化,網站服務器環境搭建以及托管運維等。為客戶提供一站式網站解決方案?。?!

          Android Remote Views

          來源:互聯網轉載 時間:2024-01-29 07:42:11

          聽名字就可以看出,remote views是一種遠程view,感覺有點像遠程service,其實remote views是view的一個結構,他可以在其他的進程中顯示,由于它可以在其他的進程中顯示,那么他就可以跨進程的更新其他進程的view,這聽起來有點不可思議,感覺有點像aidl,但是我要告訴你這確實不是,那它的原理是什么呢?且聽后面慢慢道來。

          remote views在Android中有兩個常見的應用場景:通知欄和桌面小部件。

          Remote Views的應用

          桌面部件與通知欄分別由AppWidgetManager 與 NotificationManager來管理.。分別與systemService進程中的AppWidgetServer的NotificationManagerServer進行通訊 ,所以,才需要RemoteView來更新界面.RemoteView實現了Paracelable,通過Bindler傳遞到 systemService進程中。

          RemoteViews的內部結構

          我們首先來看看RomoteViews的類圖:

          RemoteViews:中保存Remote端的mPackage和mLayoutId;并用mActions:ArrayList<RemoteViews.Action>保存各種Action。

          mPackagemLayoutId是在構造RemoteViews時傳進去的[上文圖中的seq#1];

          mActions是設置各種Remote端的響應Intent以及圖形元素的時候,保存到相應的Action中,然后把Action加入到這里保存的;

          mLayoutId里的各種控件通過setTextViewText()/ setImageViewResource() / setProgressBar(),等函數在remote端設置的。這些方法再調用setType()[Type可為Boolean / Byte / Short / Int/ Long / char / String / Uri / Bitmap/ Bundle, etc]保存到ReflectionAction中。

          SetOnClickPendingIntent是用來在local端用戶點擊viewId時,發出pendingIntent通知的。在SetOnClickPendingIntent的構造方法中保存viewId和pendingIntent。

          ReflectionAction用來在local端顯示時,通過Reflect機制執行獲得Remote端資源的。在ReflectionAction的構造方法中保存viewId,methodName,type以及value。

          ViewGroupActionSetDrawableParameters也是RemoteViews.Action的子類,在這個場景中并未用到,基本原理相似,讀者可自行分析。

          AppWidgetHostView(顯示RemoteViews內容)

          RemoteViews提供了內容之后,AppWidgetHost會通過IAppWidgetHost.updateAppWidget()被通知到Remote端有更新,本地端把RemoteViews提供的內容顯示在AppWidgetHostView上。

          我們來看下類圖:

          我們分析下流程:

          1.??????獲取RemoteViews里Remote端(AppWidgetProvider)的packageName和layoutId,通過packageName創建遠端的context——remoteContext。

          2.??????通過RemoteViews的apply()方法,真正開始執行偵聽Click操作的動作;通過遠端Layout獲得本地使用的View。

          2.1. ?克隆一個本地的LayoutInflater;[Seq#8]

          2.2. ?用克隆出的LayoutInflater對remote端的layoutId執行Inflate,獲得Layout所描述的View的Hierarchy,亦即后面用到的rootView;[Seq#9~ 10]

          2.3. ?對2.2中獲得的view執行performApply。[Seq#11~ 19]

          performApply()對所有mActions中的Action都執行apply()操作。這樣,

          2.3.1 對于setOnClickPendingIntent來說,[Seq#12~ 15]

          • ?通過rootView(2.2獲得的Remote端的Layout的總的View)的findViewById(viewId),找到要偵聽的View;[Seq#13]
          • ?對找到的要偵聽的View設置Click的Listener。[Seq#14]

          2.3.2對于ReflectionAction來說,[Seq#16~ 19]

          • ?通過rootView(2.2獲得的Remote端的Layout的總的View)的findViewById(viewId),找到要設置內容的對象View;[Seq#17]
          • ?然后通過Reflect機制,執行View實現類里的方法(比如這里是setImageResource()),把相應的資源的Id設置給它. [Seq#18]

          3.??????把獲得的View加入到本地的View系統中。[Seq#21]

          看一段關鍵代碼,通過Reflect機制設置內容的代碼片段:

          @Override  public void apply(View root) {      final View view = root.findViewById(viewId);      Class param = getParameterType();  // 通過this.type得到class:int.class      Class klass = view.getClass();     // 這個類在Remote的Layout中定義,這里為ImageView      Method method = klass.getMethod(this.methodName, param); // methodName是實現View類里的方法名:setImageResource(int)        try {          // 執行ImageView.setImageResource(value),value為resId           method.invoke(view, this.value);      } catch (Exception ex) {          throw new ActionException(ex);      }   }  

          應用實例:

          本文開始說過Android RemoteView主要兩個應用,其中一個就是桌面小控件。那么接下來說說AppWidget。

          AppWidget

          AppWidget也就是“窗口小部件”,當我們點擊桌面的小部件的時候,其實是觸發Remote端的AppWidgetProvider實現;具體顯示是Local的AppWidgetHost通過AppWidgetHostView實現。AppWidgetHost、AppWidgetProvider與AppWidgetService和AppWidgetManager按照特有的機制組合在一起,才能完整的實現AppWidget機制。接下來我們具體分析下他的實現流程。

          AppWidget系統框架

          AppWidget實現Remote端提供UI元素,Local端具體顯示。AppWidgetHost在AppWidget系統中是Local端;AppWidgetProvider端是Remote端。AppWidgetHost和AppWidgetProvider直接或通過IAppWidgetService或間接的通過AppWidgetManager,與AppWidgetService實現交互。AppWidgetService是所有元素的總管,負責協調其他各個部分。

          AppWidget簡要分析

          AppWidgetHost

          AppWidgetHost通過IAppWidgetService利用Binder機制實現與系統進程中的AppWidgetService通信;

          AppWidgetHost有IAppWidgetHost(通過Callbacks)的實現,并在AppWidgetHost.startListening()中注冊到AppWidgetService中,實現當Remote端的數據有更新時,通過IAppWidgetHost.updateAppWidget()通知AppWidgetHost更新本地的顯示;或者當Remote端的Provider改變時通知AppWidgetHost。

          AppWidgetHost創建本地AppWidgetHostView時,會以AppWidgetId和AppWidgetHostView加入mViews: HashMap<Interger,AppWidgetHostView>

          AppWidgetProvider

          AppWidgetProvider是AppWidget的Remote端內容提供方,并能注冊響應其所提供內容的某個View被點擊時,響應的Intent。

          AppWidgetProvider是一個抽象類,實現類需要實現抽象方法onUpdate() / onDeleted()/ onEnabled()和onDisabled()。這是AppWidgetProvider的一個模板模式實現,要求AppWidgetProvider的實現者:

          • ?在AndroidManefest.xml中聲明這個AppWidgetProvider是"android.appwidget.action.APPWIDGET_UPDATE"的Receiver,這樣AppWidgetProvider作為一個BroardcastReceiver才能接收到AppWidgetService發出的消息。而AppWidgetService查詢系統中已經安裝了哪些AppWidgetProvider也是通過查詢這個接收者的Intent來的實現。所以如果沒有這個Receiver,安裝的Provider里就沒有這個Provider,亦即,未加入到AppWidget系統中。
          • ?另外,這個Receiver的meta-data的name指定為“android.appwidget.provider”;resource中用xml定義appwidget-provider內的各種屬性。這些屬性按包被安裝時,檢索出來賦給AppWidgetProviderInfo。

          通常,對于應用開發來說不太注重AppWidget其他的部分,只是寫AppWidgetProvider,但一般也都稱AppWidgetProvider為AppWidget開發。

          AppWidgetService

          AppWidgetService通過IAppWidgetService提供方法給AppWidgetHost、AppWidgetProvider使用。

          在mInstalledProviders:AppWidgetService.Provider中保存AppWidgetProvider的信息;在mHost:AppWidgetService.Host中保存AppWidgetHost的信息;并用mAppWidgetIds:AppWidgetService.AppWidgetId保存AppWidgetHost與AppWidgetProvider的綁定關系。

          注意:

          AppWidgetService運行于三個各自不同的進程空間:

          • ?AppWidgetService運行于system_process進程;
          • ?AppWidgetHost運行于自己的進程空間,典型的桌面上的AppWidgetHost運行于Launcher中;
          • ?AppWidgetProvider也是運行于自己的進程空間,典型的如“電量控制”這個AppWidgetProvider運行于Settings中。

          AppWidgetHost和AppWidgetProvider要用到AppWidgetService的服務時,用Binder機制通過IAppWidgetService實現。AppWidgetService通過IAppWidgetHost通知AppWidgetHost;AppWidgetService通過發Broadcast通知AppWidgetProvider。

          講完概念,我們來兩個實用的例子:

          通知欄:

           Notification notification=new Notification();        notification.icon=R.drawable.ic_launcher;        notification.tickerText="hello world";        notification.when=System.currentTimeMillis();        notification.flags=Notification.FLAG_AUTO_CANCEL;        Intent intent=new Intent(this,NotificationActivity.class);        //定義延遲的意圖        PendingIntent pendingIntent=PendingIntent.getActivity(this,                 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);        notification.setLatestEventInfo(this, "我的標題","我的文本", pendingIntent);        RemoteViews remoteViews=new RemoteViews(getPackageName(),                R.layout.remoteview);        remoteViews.setTextViewText(R.id.title, "我的標題");        remoteViews.setTextViewText(R.id.content, "我的內容");        notification.contentView=remoteViews;        notification.contentIntent=pendingIntent;        NotificationManager manager=(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);        manager.notify(1, notification);

          桌面小控件:

          要完成桌面小控件需要如下幾個步驟:

          1 自定義布局? 2 定義配置文件? 3 自定義類繼承AppWidgetProvider? 4 功能清單注冊

          <?xml version="1.0" encoding="utf-8"?><appwidget-provider     xmlns:andro     android:minWidth="84dip"    android:minHeight="84dip"    android:initialLayout="@layout/widget"    android:updateperiodmillis="300000"    ></appwidget-provider>

          功能清單的配置:

           <receiver android:name="com.example.remoteviewfinal.MyAppWidgetProvider">            <intent-filter>                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>            </intent-filter>            <meta-data                android:name="android.appwidget.provider"                android:resource="@xml/provider_info"                ></meta-data>        </receiver>

          自定義類:

          public class MyAppWidgetProvider extends AppWidgetProvider {    @Override    public void onReceive(final Context context, Intent intent) {        // TODO 自動生成的方法存根        super.onReceive(context, intent);        /**         * 將圖片旋轉一圈         */        new Thread(new Runnable() {            @Override            public void run() {                Bitmap bitmap=BitmapFactory.decodeResource(context.getResources(),                        R.drawable.ic_launcher);                AppWidgetManager manager=AppWidgetManager.getInstance(context);                for(int i=0;i<37;i++){                    float degree=(i*10)%360;                    RemoteViews remoteViews=new RemoteViews(context.getPackageName(),                            R.layout.widget);                    remoteViews.setImageViewBitmap(R.id.imageview, rotateBitmap(context,bitmap,degree));                    componentname cn=new ComponentName(context, MyAppWidgetProvider.class);                    //更新界面                    manager.updateAppWidget(cn, remoteViews);                }            }        }).start();    }    @Override    public void onUpdate(Context context, AppWidgetManager appWidgetManager,            int[] appWidgetIds) {        // TODO 自動生成的方法存根        super.onUpdate(context, appWidgetManager, appWidgetIds);    }    /**     * 當第一個實例被添加的時候調用     */    @Override    public void onEnabled(Context context) {        // TODO 自動生成的方法存根        super.onEnabled(context);    }    /**     * 當實例被刪除的時候調用     */    @Override    public void onDeleted(Context context, int[] appWidgetIds) {        // TODO 自動生成的方法存根        super.onDeleted(context, appWidgetIds);    }    /**     * 當最后一個實例被刪除的時候調用     */    @Override    public void onDisabled(Context context) {        // TODO 自動生成的方法存根        super.onDisabled(context);    }    private Bitmap rotateBitmap(Context context,Bitmap bitmap,float degree){        Matrix matrix=new Matrix();        matrix.reset();        matrix.setRotate(degree);        Bitmap result=Bitmap.createBitmap(bitmap, 0, 0,bitmap.getWidth(),                bitmap.getHeight(), matrix,true);        return result;          }}

          更新不同進程的界面:?

          定義界面A 來更新不同進程的界面B. 我們可以將界面A中的remoteView 傳遞到界面B,界面B 獲取對象,調用控件的apply方法更新界面 修改A界面的process屬性,使其在不同的進程中運行。

          界面A:

          public void send(){        RemoteViews remoteViews=new RemoteViews(getPackageName(), R.layout.widget);        remoteViews.setTextViewText(R.id.msg, "我的信息");        PendingIntent pendingIntent=PendingIntent.getActivity(this,0,                new Intent(this,NotificationActivity.class),                 PendingIntent.FLAG_UPDATE_CURRENT);        remoteViews.setOnClickPendingIntent(R.id.btn, pendingIntent);        Intent intent=new Intent(Constant.ACTION);        intent.putExtra(Constant.VIEW, remoteViews);        sendBroadcast(intent);    }

          界面B:

           private BroadcastReceiver mRemoteBroadcastReceiver=new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            RemoteViews remoteViews=intent.getParcelableExtra(Constant.VIEW);            if(remoteViews!=null){                View view=remoteViews.apply(NotificationActivity.this, container);                container.addView(view);            }        }    };
          標簽:remoteview-

          網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...

          在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...

          在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...

          醒圖配方怎么分享?打開醒頭先打開醒頭在醒頭里面制做怎么制作模板擴建,然后把在里面有保存到多多分享功能,的或都可以不。qq版本7.1.5怎樣將個性名片變成默認?將手機個性名片設置為原來是系統默認的模板表就行,方法::手機登陸,將頁面向右滑動再看看,再再點擊左上角的頭像;直接點擊右下角的“個性名片”;將“個性名片”頁面來回滑動究竟有沒有下,然后點擊上面設置成的模板;在“選擇類型版式”的頁面上,點擊“立...

          honor 9 lite微信怎么設置夜間模式?首先需要手機自帶【黑暗模式】,因為本身沒有 "夜間模式和or "黑暗模式和,但只隨著系統黑暗模式的開啟而開啟;2.然后將手機中的版本升級到7.0.13以上版本,打開設置-關于-勾選要升級的新版本;3.打開手機中的【黑暗模式】;4.回到,可以看到已經自動切換到夜間模式;瀏覽器夜間模式是什么意思?傲游瀏覽器有 "夜間模式和。您可以在瀏覽器右上角的快速工具...

          我的IPHONE怎么升級ISO7?越獄后的iphone只能通過itunes來升級,截至2015/9/26,只能升級到IOS9,不能升級IOS7,升級步驟:1、iphone關機狀態,使用數據線連接電腦,打開電腦的iTunes軟件。2、按住Power鍵2秒。3、在不放開Power鍵的狀態下,按Home 鍵10秒,強制關機。4、不放開Home鍵,輕按Power鍵1次。保持不放開Home鍵15秒左右,手機...

          TOP
          国产初高中生视频在线观看|亚洲一区中文|久久亚洲欧美国产精品|黄色网站入口免费进人
          1. <nobr id="easjo"><address id="easjo"></address></nobr>

              <track id="easjo"><source id="easjo"></source></track>
              1. 
                

              2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
              3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>