Android小部件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
小部件中使用列表项
官方参考
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开发过程中的坑和总结的更多相关文章
- yii2小部件(widget)
一.创建一个简单的小部件 namespace common\components; //common需要自己先设定一个别名 use yii\base\Widget; //小部件需要继承的基类 use ...
- 优质Android小部件:索尼滚动相册
虽然骚尼手机卖的不怎么样,但是有些东西还是做的挺好的,工业设计就不用说了,索尼的相册的双指任意缩放功能也是尤其炫酷.其桌面小部件滚动相册我觉得也挺好的,比谷歌原生的相册墙功能好多了,网上搜了一下也没发 ...
- Android开发过程中的坑及解决方法收录(三)
bug:应用出现了 不幸运的,应用已停止的错误提示 排除问题: 1.intent接收数据的字符串不匹配 2.java常见的NullPointerException(空指针错误),可能由三个原因引起,字 ...
- Android开发过程中的坑及解决方法收录(四)
1.某个控件要放在Linearlayout布局的底部(底部导航条) <LinearLayout xmlns:android="http://schemas.android.com/ap ...
- Android开发过程中的坑及解决方法收录(六)
1. file.listFiles 空指针异常 最近在弄个小项目,类似一个文件管理器,需要获得手机存储里的目录之后显示,但是运行过程中出现错误,搜索了资料,得出了以下的解决办法 问题产生的原因: an ...
- Android开发过程中的坑及解决方法收录(一)
之前使用了Android Studio的插件直接为button绑定了监听器,并实现onClick方法(我的onClick方法无论点击哪一个都是要实现setcontentview这个方法设置layout ...
- Android开发过程中的坑及解决方法收录(二)
bug 1: bug描述: 无法成功地将edittext中的内容传入数据库中 bug动图: 经过: 最近写了个项目,项目要使用到SQL数据库,由于没有相关知识,便是找到了各种资料开始了自学之旅,在de ...
- Android开发过程中的坑及解决方法收录(五)
1. 导入依赖库出现错误 因为使用的sdk版本不同,使用下列代码强制使用最低版本,25.3.1就是我当前使用的版本号,根据自己的情况修改 configurations.all { resolution ...
- Android Widget开发过程中的一些问题汇总
一.基本实现要点 布局文件 配置文件 控制文件 AndroidManifest.xml
随机推荐
- Asp.net Core启动流程讲解(四)
Asp.net Core内 DI(DependencyInjection)贯穿了项目的始终,要学习Asp.net Core就无法越过DI. 下面讲解一下DI在Asp.Net Core内的流程 asp. ...
- 多线程std::cout 深入研究
1.研究背景 在测试时发现mingw版本的gcc编译出来的程序,一个主程序新建20个线程,每个线程都循环向cout输出信息,几分钟程序就崩了,而用msvc和gcc-linaro版gcc交叉编译器编译出 ...
- C语言基础练习——打印菱形
C语言基础练习--打印菱形 JERRY_Z. ~ 2020 / 8 / 26 转载请注明出处! 代码: /* * @Author: JERRY_Z. * @Date: 2020-08-26 17:17 ...
- mq本机上能用,其他机子上连上不mq
有一次遇到了记录下.原因是suse11重启后会自动开防火墙. 关了防火墙. rcSuSEfirewall2 stopShutting down the Firewall done
- Apache 软件基金会顶级项目 Pulsar 达成新里程碑:全球贡献者超 300 位!
各位 Pulsar 社区小伙伴们: 今天我们高兴地宣布Pulsar 达成新里程碑,全球贡献者超 300 位! 距离 Pulsar 实现 200 位贡献者里程碑,仅仅间隔 8 个月! 作为 Apache ...
- 这应该是最适合国内用户的K3s HA方案
前 言 在面向生产环境的实践中,高可用是我们无法避免的问题,K3s本身也历经多个版本的迭代,HA方案也进行了不断优化,形成了目前的比较稳定的HA方案. 目前官方提供两种HA方案: 嵌入式DB的高可用( ...
- HTML-CSS-JS Prettify 代码格式化插件
前提:已经安装 node.js.安装插件 HTML-CSS-JS Prettify,修改node路径,即可通过单击右键 HTML-CSS-JS Prettify 中的 Prettify Code 使用 ...
- 渣渣的Leetcode之旅(Python3)_1.两数之和
题目:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标.你可以假设每种输入只会对应一个答案.但是,数组中同一个元素不能使用两遍 ...
- oracle之dblink
当用户要跨本地Oracle数据库,访问另外一个数据库表中的数据时,本地数据库中必须创建了远程数据库的dblink,通过dblink本地数据库可以像访问本地数据库一样访问远程数据库表中的数据.下面讲介绍 ...
- 原来写插件还可以选MEF
MEF是微软提供的一个轻量级的ICO容器,可以轻易的解除程序集的依赖关系,最近想写个类似插件试的软件所以搜索了一下,终于淘到宝了. 下面我们看看MEF是如何解耦的 新建一个控制台项目两个类库 Ites ...