召回 remoteView 而不是创建新的?
Recall remoteView instead of creating new one?
我有一个手电筒小部件在 launcher 重新启动后停止响应,例如,当系统中的日期更改时,launcher 在我的 phone 上重置。根据 SO 上的这个线程:Link,我需要更新 remoteView 而不是每次都创建一个新的。但是我不明白如何在我的代码中实现它。我有一个提供者和一个接收者。
注意:小部件在 30 分钟后再次开始工作,因为这是我的小部件在 appwidget-provider[=41= 中设置的更新时间] XML.
提供商:
public class WidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
receiver.setAction("COM_FLASHLIGHT");
receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.appwidget_layout);
views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);
//appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);
}
}
}
接收方:
public class FlashlightWidgetReceiver extends BroadcastReceiver {
private static boolean isLightOn = false;
private static Camera camera;
@Override
public void onReceive(Context context, Intent intent) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
if (isLightOn) {
views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_off);
} else {
views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_on);
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(new ComponentName(context, WidgetProvider.class),
views);
if (isLightOn) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
isLightOn = false;
}
} else {
// Open the default i.e. the first rear facing camera.
camera = Camera.open();
if (camera == null) {
Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
} else {
// Set the torch flash mode
Camera.Parameters param = camera.getParameters();
param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
try {
camera.setParameters(param);
camera.startPreview();
isLightOn = true;
} catch (Exception e) {
Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
}
}
}
}
}
我的一个小部件遇到了这个问题,我解决它的方法是存储对 RemoteViews 对象的静态引用。所以我添加了一个 class 来将每个 appWidgetId 与其 RemoteViews 对象相关联:
public class WidgetInfo {
int appWidgetId;
RemoteViews view;
boolean clickHandlersIntialized;
public WidgetInfo(int id, RemoteViews v){
appWidgetId = id;
view = v;
clickHandlersInitialized = false;
}
}
然后在提供程序中创建了这些对象的静态列表:
private static ArrayList<WidgetInfo> widgetList = new ArrayList<WidgetInfo>();
然后在provider中创建了这个方法,给定一个appWidgetId会return对应的WidgetInfo对象
public WidgetInfo getInfo(Context context, int id) {
for (int i = 0; i < widgetList.size(); i++) {
if (widgetList.get(i).appWidgetId == id) {
// if there is already a WidgetInfo object in the list
// with this id, return the object
return widgetList.get(i);
}
}
// otherwise, create a new WidgetInfo object with a new RemoteViews
// and add it to the list
WidgetInfo newInfo = new WidgetInfo(id, new RemoteViews(context.getPackageName(), R.layout.appwidget_layout));
widgetList.add(newInfo);
return newInfo;
}
然后在provider的onUpdate方法中,可以使用getInfo获取WidgetInfo对象,然后调用已有视图成员的方法。例如:
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
WidgetInfo info = getInfo(context, appWidgetId);
RemoteViews views = info.view;
// this prevents the click handlers from being initialized multiple times
if(!info.clickHandlersInitialized){
Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
receiver.setAction("COM_FLASHLIGHT");
receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);
views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);
info.clickHandlersInitialized = true;
}
//appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);
}
}
好的伙计们,我终于有时间一劳永逸地解决这个问题:)
我为提供程序创建了更多方法,而不是在 onUpdate 中做所有事情,需要一个重要方法:
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("COM_FLASHLIGHT");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
当使用下面的代码点击小部件时,通过接收器调用此方法:
private void turnFlash(Context context) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
views.setOnClickPendingIntent(R.id.imageButton, WidgetProvider.buildButtonPendingIntent(context));
}
就是这样,别再打嗝了!
我有一个手电筒小部件在 launcher 重新启动后停止响应,例如,当系统中的日期更改时,launcher 在我的 phone 上重置。根据 SO 上的这个线程:Link,我需要更新 remoteView 而不是每次都创建一个新的。但是我不明白如何在我的代码中实现它。我有一个提供者和一个接收者。
注意:小部件在 30 分钟后再次开始工作,因为这是我的小部件在 appwidget-provider[=41= 中设置的更新时间] XML.
提供商:
public class WidgetProvider extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
receiver.setAction("COM_FLASHLIGHT");
receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.appwidget_layout);
views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);
//appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);
}
}
}
接收方:
public class FlashlightWidgetReceiver extends BroadcastReceiver {
private static boolean isLightOn = false;
private static Camera camera;
@Override
public void onReceive(Context context, Intent intent) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
if (isLightOn) {
views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_off);
} else {
views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_on);
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
appWidgetManager.updateAppWidget(new ComponentName(context, WidgetProvider.class),
views);
if (isLightOn) {
if (camera != null) {
camera.stopPreview();
camera.release();
camera = null;
isLightOn = false;
}
} else {
// Open the default i.e. the first rear facing camera.
camera = Camera.open();
if (camera == null) {
Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
} else {
// Set the torch flash mode
Camera.Parameters param = camera.getParameters();
param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
try {
camera.setParameters(param);
camera.startPreview();
isLightOn = true;
} catch (Exception e) {
Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
}
}
}
}
}
我的一个小部件遇到了这个问题,我解决它的方法是存储对 RemoteViews 对象的静态引用。所以我添加了一个 class 来将每个 appWidgetId 与其 RemoteViews 对象相关联:
public class WidgetInfo {
int appWidgetId;
RemoteViews view;
boolean clickHandlersIntialized;
public WidgetInfo(int id, RemoteViews v){
appWidgetId = id;
view = v;
clickHandlersInitialized = false;
}
}
然后在提供程序中创建了这些对象的静态列表:
private static ArrayList<WidgetInfo> widgetList = new ArrayList<WidgetInfo>();
然后在provider中创建了这个方法,给定一个appWidgetId会return对应的WidgetInfo对象
public WidgetInfo getInfo(Context context, int id) {
for (int i = 0; i < widgetList.size(); i++) {
if (widgetList.get(i).appWidgetId == id) {
// if there is already a WidgetInfo object in the list
// with this id, return the object
return widgetList.get(i);
}
}
// otherwise, create a new WidgetInfo object with a new RemoteViews
// and add it to the list
WidgetInfo newInfo = new WidgetInfo(id, new RemoteViews(context.getPackageName(), R.layout.appwidget_layout));
widgetList.add(newInfo);
return newInfo;
}
然后在provider的onUpdate方法中,可以使用getInfo获取WidgetInfo对象,然后调用已有视图成员的方法。例如:
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
WidgetInfo info = getInfo(context, appWidgetId);
RemoteViews views = info.view;
// this prevents the click handlers from being initialized multiple times
if(!info.clickHandlersInitialized){
Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
receiver.setAction("COM_FLASHLIGHT");
receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);
views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);
info.clickHandlersInitialized = true;
}
//appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);
}
}
好的伙计们,我终于有时间一劳永逸地解决这个问题:)
我为提供程序创建了更多方法,而不是在 onUpdate 中做所有事情,需要一个重要方法:
public static PendingIntent buildButtonPendingIntent(Context context) {
Intent intent = new Intent();
intent.setAction("COM_FLASHLIGHT");
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
当使用下面的代码点击小部件时,通过接收器调用此方法:
private void turnFlash(Context context) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
views.setOnClickPendingIntent(R.id.imageButton, WidgetProvider.buildButtonPendingIntent(context));
}
就是这样,别再打嗝了!