中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

理解與應用Android桌面組件AppWidget

發布時間:2020-07-30 17:58:02 來源:網絡 閱讀:1645 作者:xhmengmse 欄目:移動開發

轉自我的新浪博文

一、概念

    首先要區分widget和AppWidget這兩個概念。

1、Widget

    widget可以直譯為小部件,它在Android中代表視圖的概念,如TextView、Button、EditText等widget視圖控件,及LinearLayout等視圖布局。    

理解與應用Android桌面組件AppWidget

2、AppWidget

    AppWidget是放置在手機屏幕的桌面小組件應用,如時鐘、日歷、天氣等組件,與一般應用程序有所不同。一般應用雖也可以以圖標的形式(快捷方式)放在桌面,但必須點擊運行和查看;而AppWidget一般不須點擊即直觀呈現其主要內容。當然,AppWidget也可以被設置為點擊打開其它屏幕或應用等。

    而且,AppWidget可以被定時更新,如日歷每天更新,時鐘每分鐘更新等。當然,也可以在AppWidget的視圖界面中加入類似刷新的小按鈕,以進行實時更新,如天氣預報。

    一般在提到Widget部件或Widget程序時,指的是AppWidget;如果說到widget控件,則可能是指視圖控件,如Button等。

3、操作

    通過在桌面(HomeScreen)中長按,在彈出的對話框中選擇AppWidget部件來進行創建;或者在應用程序列表的AppWidget程序列表中選擇并長按來創建。同一個AppWidget部件可以在桌面同時創建多個。每新建一個,實際上是生成了一個新的AppWidget實例。

    要刪除桌面的Widget部件,只需長按并拖動到垃圾箱即可。

二、一個簡單的AppWidget應用

1、簡單AppWidget組成

    一個簡單的AppWidget應用只需包括以下部分:

AppWidgetProviderInfo對象

    這個對象為AppWidget提供元數據,包括布局、更新頻率等信息,這個對象定義在xml文件中,不需要自己編寫,由系統根據XML文件生成。

AppWidgetProvider類: 

理解與應用Android桌面組件AppWidget

    如圖所示,AppWidgetProvider類,繼承自BroadcastReceiver,可以接收并處理廣播事件。這個類定義了AppWidget的基本生命周期函數:

    onReceive(Context, Intent)   接收廣播事件。

    onUpdate(Context , AppWidgetManager, int[] appWidgetIds)  到達指定的更新時間或用戶向桌面添加widget時調用;實際是接受并處理“android.appwidget.action.APPWIDGET_UPDATE”廣播事件。appWidgetIds保存著已創建的各(桌面)AppWidget實例編號。在onUpdate方法中可以依次更新所有實例的界面內容。

    onEnabled(Context)  當AppWidget實例第一次被創建時調用

    onDeleted(Context, int[] appWidgetIds)  當一個AppWidget實例被刪除時調用

    onDisabled(Context)  當最后一個AppWidget實例被刪除時調用

2、一個簡單應用開發

    該應用很簡單,只是在桌面顯示一行文字。

    (1)應用的界面布局文件res/layout/appwidget_provider_layout.xml:

理解與應用Android桌面組件AppWidget

    (2)應用的元數據定義文件res/xml/appwidget_provider.xml:

理解與應用Android桌面組件AppWidget

    (3)Widget實例提供程序SimpleWidgetProvider.java文件:

    package com.example.simpleappwidget;

    import android.appwidget.AppWidgetManager;
    import android.appwidget.AppWidgetProvider;
    import android.content.Context;
    import android.util.Log;
    import android.widget.RemoteViews;

    import com.example.simpleappwidget.R;

    public class SimpleWidgetProvider extends AppWidgetProvider {

       private String TAG = "widgetexample";
       周期更新時調用
      public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
      {
         final int N = appWidgetIds.length;
         Log.i(TAG,String.valueOf(N));
         for (int i = 0; i < N; i++)
         {
            int appWidgetId = appWidgetIds[i];
            String message = "目前有"+N+"個AppWidget實例";
            構建RemoteViews對象來對桌面部件進行更新
            RemoteViews views = new RemoteViews(context.getPackageName(),

                       R.layout.appwidget_provider_layout);
            更新文本內容,指定布局的組件
            views.setTextViewText(R.id.appwidget_text, message);
            將RemoteViews的更新傳入AppWidget進行更新
            appWidgetManager.updateAppWidget(appWidgetId, views);
         }
      }
    }

    該應用比較簡單,只是為了說明程序的結構。Provider類中僅提供了更新事件處理方法。運行界面如下圖:

理解與應用Android桌面組件AppWidget

    可以創建多個實例:

理解與應用Android桌面組件AppWidget

    但并沒有如估計的顯示“目前有2個實例”。

    關閉模擬器并重新啟動打開,才顯示有兩個實例:

理解與應用Android桌面組件AppWidget


示例程序下載

 

問題解決:前面更新多個實例的問題,后面通過將以實例ID為參數逐一修改Widget組件實例的以下方法: 

           appWidgetManager.updateAppWidget(appWidgetId, views);
    改為調用組件管理器的修改所有小組件實例的方法:

           ComponentName myComponentName = new ComponentName(context, SimpleWidgetProvider.class);
           appWidgetManager.updateAppWidget(myComponentName,views);

 

3、為AppWidget程序添加按鈕事件處理

    天氣預報等桌面組件有類似功能,即點擊一個小圖標(按鈕)刷新數據顯示。這里只是簡單模擬一下類似功能。

    點擊按鈕刷新數據,可以有多種方式實現。如點擊按鈕打開一個Activity、點擊發送廣播消息、點擊啟動一個服務等。下面首先看一下點擊打開Activity的關鍵代碼實現:

    (1)按鈕事件處理可以在SimpleWidgetProvider類的onUpdate方法中實現:

    ......

    for (int i = 0; i < N; i++)
    {
       int appWidgetId = appWidgetIds[i];
       String message = "目前有"+N+"個AppWidget實例";
       RemoteViews views = new RemoteViews(context.getPackageName(),

                R.layout.appwidget_provider_layout);
       views.setTextViewText(R.id.appwidget_text, message);
       為按鈕綁定點擊事件處理器
       Intent intent = new Intent(context, MyActivity.class);
       intent.putExtra("appWidgetId", appWidgetId);
       Log.i(TAG,"ID:"+(intent.getExtras()).getInt("appWidgetId"));
       PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,

             PendingIntent.FLAG_CANCEL_CURRENT);
       views.setOnClickPendingIntent(R.id.mybutton, pendingIntent);
       將RemoteViews的更新傳入AppWidget進行更新
       appWidgetManager.updateAppWidget(appWidgetId, views);
    } 

    ...... 

    需要指出的是如圖所示的PendingIntent的幾個常量值(用于getActivity等方法的參數):

理解與應用Android桌面組件AppWidget    這里因為Intent帶有數據,使用了PendingIntent.FLAG_CANCEL_CURRENT。

    (2)MyActivity類的代碼:

    ......

    protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_my);
       Bundle bundle = getIntent().getExtras();
       int appWidgetID = bundle.getInt("appWidgetId");
       Log.i(TAG,"another ID:"+appWidgetID);

       final Context context = this;
       RemoteViews views = new RemoteViews(context.getPackageName(),

             R.layout.appwidget_provider_layout);
       更新文本內容,指定布局的組件
       views.setTextViewText(R.id.appwidget_text, "點擊按鈕更新內容");
       取得AppWidgetManager實例
       AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
       appWidgetManager.updateAppWidget(appWidgetID, views);
       this.finish();
    }

    ......

示例程序×××

    上述功能也可以通過廣播消息進行處理。因為AppWidgetProvider本身就繼承自BroadcastReceiver,所以可以在SimpleWidgetProvider類的onReceive方法中實現對自定義消息的處理。關鍵代碼如下:

    (1)SimpleWidgetProvider類代碼:

    ......

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
       final int N = appWidgetIds.length;
       Log.i(TAG,String.valueOf(N));
       for (int i = 0; i < N; i++)
       {
          int appWidgetId = appWidgetIds[i];
          ......   

          Intent intent = new Intent("update_appwidget_textview");
          intent.putExtra("appWidgetId", appWidgetId);
          PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,

                           PendingIntent.FLAG_CANCEL_CURRENT);
          點擊按鈕將觸發廣播,當前接收器將即時接收和處理廣播消息
          views.setOnClickPendingIntent(R.id.mybutton, pendingIntent);
          appWidgetManager.updateAppWidget(appWidgetId, views);
        }  
     }

     ......

     @Override
     public void onReceive(Context context, Intent intent)

     {
        String action = intent.getAction();
        if(action.equals("update_appwidget_textview"))
        {
           Log.i(TAG,"update_appwidget_textview");
           RemoteViews views = new RemoteViews(context.getPackageName(),

                          R.layout.appwidget_provider_layout);
           views.setTextViewText(R.id.appwidget_text, "點擊按鈕更新內容");
           AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
           int appWidgetId = (intent.getExtras()).getInt("appWidgetId");
           appWidgetManager.updateAppWidget(appWidgetId, views);
        }
        else
           super.onReceive(context, intent);
     }

     ......

    (2)AndroidManifest.xml文件:     

理解與應用Android桌面組件AppWidget

    (3)應用的界面布局文件res/layout/appwidget_provider_layout.xml:

理解與應用Android桌面組件AppWidget

   (4)應用的元數據定義文件res/xml/appwidget_provider.xml:

理解與應用Android桌面組件AppWidget

示例程序代碼下載

    另外,從資料中還查到一種利用ComponentName類修改AppWidget實例的方法,只需對上面代碼稍加改動:

    onUpdate方法:

    for (int i = 0; i < N; i++)
       {
          為了看到每次調用該方法時內容的變化

          String message = System.currentTimeMillis()+"";

          RemoteViews views = new RemoteViews(context.getPackageName(),

                        R.layout.appwidget_provider_layout);
          views.setTextViewText(R.id.appwidget_text, message);

          ......   

          Intent intent = new Intent("update_appwidget_textview");
          PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent,

                           PendingIntent.FLAG_CANCEL_CURRENT);
          views.setOnClickPendingIntent(R.id.mybutton, pendingIntent);
          appWidgetManager.updateAppWidget(appWidgetId, views);
        }  
    onReceive方法:

    ......

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    ComponentName componentName = new ComponentName(context, SimpleWidgetProvider.class);
    appWidgetManager.updateAppWidget(componentName, views); 

    ......  

    使用廣播消息處理的方式當然也可以另外創建一個接收器,不再具體分析。示例程序下載

使用本地Service服務更新Widget實例的代碼下載

4、一個較實用的例子

    例子比較簡單,只是在HomeScreen桌面實時顯示時間。

    (1)SimpleWidgetProvider類關鍵代碼(onUpdate方法):

     ......

     int appWidgetId = appWidgetIds[i];

     Intent intent = new Intent("com.example.updatetime");
     intent.putExtra("appWidgetId", appWidgetId);
     context.startService(intent);

     ......

    (2)ExampleService類代碼:

     ......

     static int appWidgetId;
     static RemoteViews views;
     static AppWidgetManager appWidgetManager;

     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
         views = new RemoteViews(this.getPackageName(),
                        R.layout.appwidget_provider_layout);
         appWidgetManager = AppWidgetManager.getInstance(this);
         appWidgetId = (intent.getExtras()).getInt("appWidgetId");        
         new TimeThread().start();

         return super.onStartCommand(intent, flags, startId);
     }

     class TimeThread extends Thread
     {
         @Override
         public void run ()
         {
            do{                
               try
               {                    
                  Thread.sleep(1000);
                  views.setTextViewText(R.id.appwidget_text, DateFormat.format("hh:mm:ss",

                          System.currentTimeMillis()));
                  appWidgetManager.updateAppWidget(appWidgetId, views);
               }
               catch (InterruptedException e)
               {
                  e.printStackTrace();
               }
             } while(true);
          }
      }

     ......

桌面顯示時鐘的示例程序下載

該程序的更有效的代碼

 

(5)時鐘顯示程序的另一種解決方法

    主要變化是使用android.content.Intent.ACTION_TIME_TICK時鐘服務,主要代碼如下:

    SimpleWidgetProvider類:

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
       final int N = appWidgetIds.length;
       Log.i(TAG,String.valueOf(N));
       String message = N+"個Widget實例";
       RemoteViews views = new RemoteViews(context.getPackageName(),    

               R.layout.appwidget_provider_layout);
       views.setTextViewText(R.id.appwidget_text, message);
       MyReceiver myReceiver = new MyReceiver();
       IntentFilter myFilter = new IntentFilter(); 
       myFilter.addAction(android.content.Intent.ACTION_TIME_TICK);
       context.getApplicationContext().registerReceiver(myReceiver, myFilter);
       ComponentName myComponentName = new ComponentName(context, SimpleWidgetProvider.class);
       appWidgetManager.updateAppWidget(myComponentName,views);
     }

     public static void updateWidget(Context context,RemoteViews views)
     {
        ComponentName myComponentName = new ComponentName(context, SimpleWidgetProvider.class);
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        appWidgetManager.updateAppWidget(myComponentName,views);
     }

    MyReceiver類:

    @Override
    public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if(action.equals("android.intent.action.TIME_TICK"))
       {
           RemoteViews views = new RemoteViews(context.getPackageName(),   

               R.layout.appwidget_provider_layout);
               views.setTextViewText(R.id.appwidget_text, DateFormat.format("hh:mm",
                    System.currentTimeMillis()));
               SimpleWidgetProvider.updateWidget(context, views);
       }
    }

示例程序×××

    需要說明的是ACTION_TIME_TICK這個廣播消息是系統時鐘消息,該消息只能由系統以每分鐘一次的形式發送。不能在自定義類中通過sendbroadcast方法發出,否則會拋出“Permission Denial: not allowed to send broadcast android.intent.action.TIME_TICK”異常。

    而且,程序中不能通過在manifest.xml里注冊的方式接收到這個廣播,只能在代碼里通過registerReceiver()方法注冊。

    SDK文檔原文內容:Broadcast Action: The current time has changed. Sent every minute. You can not receive this through components declared in manifests, only by exlicitly registering for it withContext.registerReceiver().

    通過測試,發現在配置文件中設置小組件更新周期不起作用。android:updatePeriodMillis="1000"設置一秒更新一次,完全沒有反應。只在長按程序生成桌面組件時,重新啟動模擬器后,才會調用onUpdate方法。

    以上測試驗證了其它資料中提到新版本的Android屏蔽了小組件更新周期設置的說法。如果需要修改組件界面,需要在程序中使用如updateAppWidget(componentName, views)語句主動更新。

參考文章:

App Widgets

Android—AppWidget技術路線

Appwidget深入 -- 按鈕事件

Android之桌面組件App Widget案例

Android Service學習之本地服務

TextView顯示系統時間

解析APP觸發Widget實例

android.content.ReceiverCallNotAllowedException: 解決方法

android之IntentFilter的用法_Intent.ACTION_TIME_TICK在manifest.xml不起作用


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

石狮市| 白玉县| 武宣县| 青神县| 专栏| 固阳县| 灵丘县| 安吉县| 繁峙县| 随州市| 黄浦区| 南安市| 泾源县| 新乡市| 永登县| 二手房| 江华| 通化县| 老河口市| 焉耆| 观塘区| 资溪县| 阿克苏市| 长海县| 宜州市| 苏州市| 盱眙县| 恩施市| 瑞金市| 乐平市| 焦作市| 淄博市| 漯河市| 梁山县| 壶关县| 霍城县| 长顺县| 玉林市| 彰武县| 宕昌县| 赤水市|