Android小部件Widget開發過程中的坑和問題小結
阿新 • • 發佈:2020-10-02
概述
官方參考
Build an App Widget
效果圖
放張效果圖,這是我玩的桌面 app 資料夾
AndroidManifest.xml
Receiver
切記裡面的字母不要弄錯,最好複製貼上再修改相對應自定義的地方就好,一個字母的錯誤搞了我一天,吐血
<receiver android:name=".desktop.DesktopWidget"> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_desktop_options" /> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> </receiver>
Service
如果小部件中使用到了列表項如 ListView,GridView 等,在繫結資料時需要使用 RemoteViewsService 並提供一個 RemoteViewsFactory 例項來填充資料 而非 Adapter
再提,這裡面一定不能敲錯字母,特別是那個 permission 也一定要有,不然無法繫結資料
<service android:name=".desktop.DesktopViewsService" android:permission="android.permission.BIND_REMOTEVIEWS" />
Options
res/xml/
widget_desktop_options.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="40dp" android:minHeight="40dp" android:initialLayout="@layout/widget_desktop" android:resizeMode="horizontal|vertical" android:widgetCategory="home_screen"> </appwidget-provider>
常用引數
Size
- 尺寸大小最終以單元格資料來顯示,但定義時為 dp
- 單元格數轉換基本工式 size = 70 x cells - 30
- 如:1格 = 70 x 1 - 30 = 40dp
- 最小尺寸定義時最好不要超過 4 個單元格就是 250dp
updatePeriodMillis
更新時間毫秒數,即間隔多少時間呼叫一次 onUpdate() 方法
initialLayout
載入佈局檔案
Using App Widgets with Collections
小部件中使用列表項
官方參考
Google Develper
AppWidgetProvider
public class DesktopWidget extends AppWidgetProvider { public String ACTION_START_ACTIVITY = "STARTACTIVITYACTION"; public DesktopWidget() { super(); } //當接收到廣播的時候會被呼叫 //onUpdate,onEnabled等時都會發送廣播 @Override public void onReceive(Context context,Intent intent) { super.onReceive(context,intent); pub.log("onReceive:" + intent.getAction()); if (intent.getAction().equals(ACTION_START_ACTIVITY)) { String strPackage = intent.getStringExtra("app_package"); Intent appIntent = context.getPackageManager().getLaunchIntentForPackage(strPackage); pub.log(appIntent.getPackage()); if (appIntent != null) { appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); pub.log("start activity"); context.startActivity(appIntent); pub.log("finish"); } } } //被新增或者被更新時呼叫 @Override public void onUpdate(Context context,AppWidgetManager appWidgetManager,int[] appWidgetIds) { super.onUpdate(context,appWidgetManager,appWidgetIds); // There may be multiple widgets active,so update all of them for (int appWidgetId : appWidgetIds) { updateAppWidget(context,appWidgetId); } } private void updateAppWidget(Context context,int appWidgetId) { pub.log("onUpdate:" + appWidgetId); // Construct the RemoteViews object RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.widget_desktop); //設定小部件上 TextView 值 //views.setTextViewText(R.id.tv_widget_desktop_title,"ZGTools"); //setRemoteAdapter設定Listivew,Gridview等複雜佈局的adapter //第一個引數為要繫結的widget的Gridview的id,第二個引數為RemoteViewsService的intent Intent intent = new Intent(context,DesktopViewsService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId); intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); views.setRemoteAdapter(R.id.gv_app_group,intent); //繫結 item 的定點事件 //Activity方式測試不成功,改用廣播的方式進行傳送並執行事件 //此處不能是空的Intent 否則廣播無法傳送 //定義Intent事件模板,相當於公用設定,再在fillIntent裡面設定具體的 extra 值 Intent templateIntent = new Intent(context,DesktopWidget.class); templateIntent.setAction(ACTION_START_ACTIVITY); templateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId); templateIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); PendingIntent pendingIntent = PendingIntent.getBroadcast(context,appWidgetId,templateIntent,PendingIntent.FLAG_UPDATE_CURRENT); views.setPendingIntentTemplate(R.id.gv_app_group,pendingIntent); // Instruct the widget manager to update the widget appWidgetManager.updateAppWidget(appWidgetId,views); } //被新增或者更改大小時呼叫,在這個方法中可以選擇性的根據介面大小顯示或隱藏某些控制元件 @Override public void onAppWidgetOptionsChanged(Context context,int appWidgetId,Bundle newOptions) { super.onAppWidgetOptionsChanged(context,newOptions); updateAppWidget(context,appWidgetId); } @Override public void onEnabled(Context context) { super.onEnabled(context); // Enter relevant functionality for when the first widget is created } @Override public void onDisabled(Context context) { super.onDisabled(context); // Enter relevant functionality for when the last widget is disabled } }
RemoteViewsService
public class DesktopViewsService extends RemoteViewsService { @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { return new DesktopViewsFactory(this,intent); } }
RemoteViewsFactory
型別於 BaseAdapter,重點是 onCreate() 載入資料, getViewAt() 方法返回佈局繫結資料
public class DesktopViewsFactory implements RemoteViewsService.RemoteViewsFactory { private Context mContext; private int mAppWidgetId; private List<AppPackage> lstApps = new ArrayList<AppPackage>(); public DesktopViewsFactory(Context context,Intent intent){ this.mContext = context; this.mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,AppWidgetManager.INVALID_APPWIDGET_ID); } @Override public void onCreate() { DesktopDbHelper dbHelper = new DesktopDbHelper(mContext); SQLiteDatabase db = dbHelper.getReadableDatabase(); String strSql = "Select * from tb_app"; try { Cursor cursor = db.rawQuery(strSql,null); if (cursor != null && cursor.getCount() > 0) { lstApps.clear(); while (cursor.moveToNext()) { byte[] blob = cursor.getBlob(cursor.getColumnIndex("app_icon")); Bitmap bmpIcon = BitmapFactory.decodeByteArray(blob,blob.length); String strLabel = cursor.getString(cursor.getColumnIndex("app_label")); String strPackage = cursor.getString(cursor.getColumnIndex("app_package")); lstApps.add(new AppPackage(strLabel,strPackage,bmpIcon)); } } if (cursor != null) { cursor.close(); } } catch (Exception e) { db.close(); e.printStackTrace(); } db.close(); } @Override public void onDataSetChanged() { //這裡我加了重新載入資料的呼叫,用於更新小部件的列表內容 onCreate(); } @Override public void onDestroy() {} @Override public int getCount() {return 0;} @Override public RemoteViews getViewAt(int i) { if (i < 0 || i >= lstApps.size()) return null; //Construct a remote views item based on the app widget item XML file RemoteViews views = new RemoteViews(mContext.getPackageName(),R.layout.widget_desktop_item); views.setTextViewText(R.id.tv_widget_desktop_label,lstApps.get(i).getAppLabel()); views.setImageViewBitmap(R.id.iv_widget_desktop_icon,lstApps.get(i).getAppIcon()); Intent intent = new Intent(); Bundle bundle = new Bundle(); bundle.putString("app_package",lstApps.get(i).getAppPackage()); intent.putExtras(bundle); views.setOnClickFillInIntent(R.id.iv_widget_desktop_icon,intent); views.setOnClickFillInIntent(R.id.tv_widget_desktop_label,intent); return views; } @Override public RemoteViews getLoadingView() { return null;} @Override public int getViewTypeCount() {return 0;} @Override public long getItemId(int i) { return 0;} @Override public boolean hasStableIds() { return false; } }
DesktopActivity
//更新widget佈局 private void updateWidget(){ AppWidgetManager widgetManager = AppWidgetManager.getInstance(this); ComponentName componentName = new ComponentName(this,DesktopWidget.class); int[] ids = widgetManager.getAppWidgetIds(componentName); widgetManager.notifyAppWidgetViewDataChanged(ids,R.id.gv_app_group); }
總結
到此這篇關於Android小部件Widget開發過程中的坑和總結的文章就介紹到這了,更多相關Android小部件Widget內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!