@

概述

官方参考

Build an App Widget

效果图

放张效果图,这是我玩的桌面 app 文件夹

AndroidManifest.xml

Receiver

切记里面的字母不要弄错,最好复制粘贴再修改相对应自定义的地方就好,一个字母的错误搞了我一天,吐血

  1. <receiver android:name=".desktop.DesktopWidget">
  2. <meta-data
  3. android:name="android.appwidget.provider"
  4. android:resource="@xml/widget_desktop_options" />
  5. <intent-filter>
  6. <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  7. </intent-filter>
  8. </receiver>

Service

如果小部件中使用到了列表项如 ListView,GridView 等,在绑定数据时需要使用 RemoteViewsService 并提供一个 RemoteViewsFactory 实例来填充数据 而非 Adapter

再提,这里面一定不能敲错字母,特别是那个 permission 也一定要有,不然无法绑定数据

  1. <service
  2. android:name=".desktop.DesktopViewsService"
  3. android:permission="android.permission.BIND_REMOTEVIEWS" />

Options

res/xml/

widget_desktop_options.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:minWidth="40dp"
  4. android:minHeight="40dp"
  5. android:initialLayout="@layout/widget_desktop"
  6. android:resizeMode="horizontal|vertical"
  7. android:widgetCategory="home_screen">
  8. </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

  1. public class DesktopWidget extends AppWidgetProvider {
  2. public String ACTION_START_ACTIVITY = "STARTACTIVITYACTION";
  3. public DesktopWidget() {
  4. super();
  5. }
  6. //当接收到广播的时候会被调用
  7. //onUpdate, onEnabled等时都会发送广播
  8. @Override
  9. public void onReceive(Context context, Intent intent) {
  10. super.onReceive(context, intent);
  11. pub.log("onReceive:" + intent.getAction());
  12. if (intent.getAction().equals(ACTION_START_ACTIVITY)) {
  13. String strPackage = intent.getStringExtra("app_package");
  14. Intent appIntent = context.getPackageManager().getLaunchIntentForPackage(strPackage);
  15. pub.log(appIntent.getPackage());
  16. if (appIntent != null) {
  17. appIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  18. pub.log("start activity");
  19. context.startActivity(appIntent);
  20. pub.log("finish");
  21. }
  22. }
  23. }
  24. //被添加或者被更新时调用
  25. @Override
  26. public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
  27. super.onUpdate(context, appWidgetManager, appWidgetIds);
  28. // There may be multiple widgets active, so update all of them
  29. for (int appWidgetId : appWidgetIds) {
  30. updateAppWidget(context, appWidgetManager, appWidgetId);
  31. }
  32. }
  33. private void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
  34. pub.log("onUpdate:" + appWidgetId);
  35. // Construct the RemoteViews object
  36. RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_desktop);
  37. //设定小部件上 TextView 值
  38. //views.setTextViewText(R.id.tv_widget_desktop_title, "ZGTools");
  39. //setRemoteAdapter设定Listivew,Gridview等复杂布局的adapter
  40. //第一个参数为要绑定的widget的Gridview的id,第二个参数为RemoteViewsService的intent
  41. Intent intent = new Intent(context, DesktopViewsService.class);
  42. intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  43. intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
  44. views.setRemoteAdapter(R.id.gv_app_group, intent);
  45. //绑定 item 的定点事件
  46. //Activity方式测试不成功,改用广播的方式进行发送并执行事件
  47. //此处不能是空的Intent 否则广播无法发送
  48. //定义Intent事件模板,相当于公用设定,再在fillIntent里面设定具体的 extra 值
  49. Intent templateIntent = new Intent(context, DesktopWidget.class);
  50. templateIntent.setAction(ACTION_START_ACTIVITY);
  51. templateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
  52. templateIntent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
  53. PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, templateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
  54. views.setPendingIntentTemplate(R.id.gv_app_group, pendingIntent);
  55. // Instruct the widget manager to update the widget
  56. appWidgetManager.updateAppWidget(appWidgetId, views);
  57. }
  58. //被添加或者更改大小时调用,在这个方法中可以选择性的根据界面大小显示或隐藏某些控件
  59. @Override
  60. public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
  61. super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
  62. updateAppWidget(context, appWidgetManager, appWidgetId);
  63. }
  64. @Override
  65. public void onEnabled(Context context) {
  66. super.onEnabled(context);
  67. // Enter relevant functionality for when the first widget is created
  68. }
  69. @Override
  70. public void onDisabled(Context context) {
  71. super.onDisabled(context);
  72. // Enter relevant functionality for when the last widget is disabled
  73. }
  74. }

RemoteViewsService

  1. public class DesktopViewsService extends RemoteViewsService {
  2. @Override
  3. public RemoteViewsFactory onGetViewFactory(Intent intent) {
  4. return new DesktopViewsFactory(this, intent);
  5. }
  6. }

RemoteViewsFactory

类型于 BaseAdapter,重点是 onCreate() 加载数据, getViewAt() 方法返回布局绑定数据

  1. public class DesktopViewsFactory implements RemoteViewsService.RemoteViewsFactory {
  2. private Context mContext;
  3. private int mAppWidgetId;
  4. private List<AppPackage> lstApps = new ArrayList<AppPackage>();
  5. public DesktopViewsFactory(Context context, Intent intent){
  6. this.mContext = context;
  7. this.mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
  8. }
  9. @Override
  10. public void onCreate() {
  11. DesktopDbHelper dbHelper = new DesktopDbHelper(mContext);
  12. SQLiteDatabase db = dbHelper.getReadableDatabase();
  13. String strSql = "Select * from tb_app";
  14. try {
  15. Cursor cursor = db.rawQuery(strSql, null);
  16. if (cursor != null && cursor.getCount() > 0) {
  17. lstApps.clear();
  18. while (cursor.moveToNext()) {
  19. byte[] blob = cursor.getBlob(cursor.getColumnIndex("app_icon"));
  20. Bitmap bmpIcon = BitmapFactory.decodeByteArray(blob, 0, blob.length);
  21. String strLabel = cursor.getString(cursor.getColumnIndex("app_label"));
  22. String strPackage = cursor.getString(cursor.getColumnIndex("app_package"));
  23. lstApps.add(new AppPackage(strLabel, strPackage, bmpIcon));
  24. }
  25. }
  26. if (cursor != null) {
  27. cursor.close();
  28. }
  29. } catch (Exception e) {
  30. db.close();
  31. e.printStackTrace();
  32. }
  33. db.close();
  34. }
  35. @Override
  36. public void onDataSetChanged() {
  37. //这里我加了重新加载数据的调用,用于更新小部件的列表内容
  38. onCreate();
  39. }
  40. @Override
  41. public void onDestroy() {}
  42. @Override
  43. public int getCount() {return 0;}
  44. @Override
  45. public RemoteViews getViewAt(int i) {
  46. if (i < 0 || i >= lstApps.size()) return null;
  47. //Construct a remote views item based on the app widget item XML file
  48. RemoteViews views = new RemoteViews(mContext.getPackageName(), R.layout.widget_desktop_item);
  49. views.setTextViewText(R.id.tv_widget_desktop_label, lstApps.get(i).getAppLabel());
  50. views.setImageViewBitmap(R.id.iv_widget_desktop_icon, lstApps.get(i).getAppIcon());
  51. Intent intent = new Intent();
  52. Bundle bundle = new Bundle();
  53. bundle.putString("app_package", lstApps.get(i).getAppPackage());
  54. intent.putExtras(bundle);
  55. views.setOnClickFillInIntent(R.id.iv_widget_desktop_icon, intent);
  56. views.setOnClickFillInIntent(R.id.tv_widget_desktop_label, intent);
  57. return views;
  58. }
  59. @Override
  60. public RemoteViews getLoadingView() { return null;}
  61. @Override
  62. public int getViewTypeCount() {return 0;}
  63. @Override
  64. public long getItemId(int i) { return 0;}
  65. @Override
  66. public boolean hasStableIds() { return false; }
  67. }

DesktopActivity

  1. //更新widget布局
  2. private void updateWidget(){
  3. AppWidgetManager widgetManager = AppWidgetManager.getInstance(this);
  4. ComponentName componentName = new ComponentName(this, DesktopWidget.class);
  5. int[] ids = widgetManager.getAppWidgetIds(componentName);
  6. widgetManager.notifyAppWidgetViewDataChanged(ids, R.id.gv_app_group);
  7. }

Android小部件Widget开发过程中的坑和总结的更多相关文章

  1. yii2小部件(widget)

    一.创建一个简单的小部件 namespace common\components; //common需要自己先设定一个别名 use yii\base\Widget; //小部件需要继承的基类 use ...

  2. 优质Android小部件:索尼滚动相册

    虽然骚尼手机卖的不怎么样,但是有些东西还是做的挺好的,工业设计就不用说了,索尼的相册的双指任意缩放功能也是尤其炫酷.其桌面小部件滚动相册我觉得也挺好的,比谷歌原生的相册墙功能好多了,网上搜了一下也没发 ...

  3. Android开发过程中的坑及解决方法收录(三)

    bug:应用出现了 不幸运的,应用已停止的错误提示 排除问题: 1.intent接收数据的字符串不匹配 2.java常见的NullPointerException(空指针错误),可能由三个原因引起,字 ...

  4. Android开发过程中的坑及解决方法收录(四)

    1.某个控件要放在Linearlayout布局的底部(底部导航条) <LinearLayout xmlns:android="http://schemas.android.com/ap ...

  5. Android开发过程中的坑及解决方法收录(六)

    1. file.listFiles 空指针异常 最近在弄个小项目,类似一个文件管理器,需要获得手机存储里的目录之后显示,但是运行过程中出现错误,搜索了资料,得出了以下的解决办法 问题产生的原因: an ...

  6. Android开发过程中的坑及解决方法收录(一)

    之前使用了Android Studio的插件直接为button绑定了监听器,并实现onClick方法(我的onClick方法无论点击哪一个都是要实现setcontentview这个方法设置layout ...

  7. Android开发过程中的坑及解决方法收录(二)

    bug 1: bug描述: 无法成功地将edittext中的内容传入数据库中 bug动图: 经过: 最近写了个项目,项目要使用到SQL数据库,由于没有相关知识,便是找到了各种资料开始了自学之旅,在de ...

  8. Android开发过程中的坑及解决方法收录(五)

    1. 导入依赖库出现错误 因为使用的sdk版本不同,使用下列代码强制使用最低版本,25.3.1就是我当前使用的版本号,根据自己的情况修改 configurations.all { resolution ...

  9. Android Widget开发过程中的一些问题汇总

    一.基本实现要点 布局文件 配置文件 控制文件 AndroidManifest.xml

随机推荐

  1. Hadoop的SecondaryNameNode的作用是什么?

    为节省篇幅,将SecondaryNameNode简称SNN,NameNode简称NN. NN与fsimage.edits文件 NN负责管理HDFS中所有的元数据,包括但不限于文件/目录结构.文件权限. ...

  2. Jeecg-Cloud学习之路(一)

    首先,Spring-Cloud目前是行业的潮流,貌似不会就落后了,笔者为了不脱离大部队只能深入学习一下了. 其次.跳槽到一家公司,给公司推荐了Jeecg-Boot的开发平台,那么为了后面扩展为clou ...

  3. PAT-B1009 说反话 - 字符串反转

    1009 说反话 (20分) 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串.字符串由若干单词和若干空格组 ...

  4. JDK源码分析-ArrayList

    ArrayList 储存结构 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; transient Objec ...

  5. Resharper 2020 免费破解版

    如果你是一名.NET开发人员,但是你却不使用ReSharper,那么你就不是一个合格的码农了,因为这是一个强大的神器,你值得拥有!当然,用它的代价是,启动VS会变得非常慢,非常卡,但是需要知道,磨刀不 ...

  6. 长沙做假证u

    长沙做假证[电/薇:187ヘ1184ヘ0909同号]办各类证件-办毕业证-办离婚证,办学位证书,办硕士毕业证,办理文凭学历,办资格证,办房产证不. 这是一个简单的取最大值程序,可以用于处理 i32 数 ...

  7. C# OWC11

    public void OcwChart(int[] Data,string[] DataName,string Yname,string Xname,string ChartName,string ...

  8. 深入了解Netty【八】TCP拆包、粘包和解决方案

    1.TCP协议传输过程 TCP协议是面向流的协议,是流式的,没有业务上的分段,只会根据当前套接字缓冲区的情况进行拆包或者粘包: 发送端的字节流都会先传入缓冲区,再通过网络传入到接收端的缓冲区中,最终由 ...

  9. Resis常用命令及数据类型

    1.下载Windows环境redis安装: 2.下载jar包: commons-pool2-2.4.2.jar jedis-2.9.0.jar 3.项目结构: 4.代码说明: package com. ...

  10. 时间选择器 element

    <el-date-picker type="datetime" placeholder="选择上线日期" :picker-options="st ...