Android小部件Widget开发过程中的坑和问题小结

 更新时间:2020年10月1日 00:40  点击:1507

概述

官方参考

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, appWidgetManager, appWidgetId);
 }
 }
 private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, 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, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
 super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
 updateAppWidget(context, appWidgetManager, 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, 0, 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内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
  • Android开发中布局中的onClick简单完成多控件时的监听的利与弊

    本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20
  • Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤

    Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20
  • Android实现简单用户注册案例

    这篇文章主要为大家详细介绍了Android实现简单用户注册案例,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-05-26