单击小部件时配置 activity 不起作用
Configuration activity not working when widget is clicked
多年来我一直在努力解决这个问题,并尝试了至少 10 种关于堆栈溢出的解决方案,但都没有成功。
我创建了一个小部件 class,它在每 5 分钟更新一次的主屏幕上显示一些数字。 Widget 是一个按钮,当用户单击它时,配置 activity 会加载,以便可以更新 widget。
当我第一次创建小部件时,配置 activity 打开,用户可以在文本框中键入。配置完成后,小部件将更新 - 一切都按预期工作。但是,当按下按钮时,配置 activity 不会再次启动。奇怪的是,当我通过 android studio 重新 运行 应用程序或重新启动 phone 时,activity 可以启动。我认为这与它由于某种原因没有更新按下的按钮有关,但我找不到修复它的地方。
我看到有几个类似的问题有我的问题并尝试了他们的解决方案,但它根本不起作用。我在 android 编程方面还很陌生,所以我可能忽略了一些东西。我对一些需要更改的变量进行了非常糟糕的硬编码,但我认为这不会影响 activity.
的启动
这是我的 WidgetProvider、配置 Activity classes 和清单。
LPWidget.java
public class LPWidget extends AppWidgetProvider {
private static final String LOG_TAG = "ExampleWidget";
static int nowLP = LPWidgetConfigureActivity.currentLP ;
static int maxNowLP = LPWidgetConfigureActivity.maxLP;
static boolean notfirstTime = false;
/**
* Custom Intent name that is used by the AlarmManager to tell us to update the clock once per second.
*/
public static String CLOCK_WIDGET_UPDATE = "doingitnow.simplelptracker.CLOCK_WIDGET_UPDATE";
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (CLOCK_WIDGET_UPDATE.equals(intent.getAction())) {
Log.d(LOG_TAG, "Clock update");
// Get the widget manager and ids for this widget provider, then call the shared
// clock update method.
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName());
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
for (int appWidgetID: ids) {
updateAppWidget(context, appWidgetManager, appWidgetID);
}
}
}
private PendingIntent createClockTickIntent(Context context) {
Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Log.d(LOG_TAG, "Widget Provider disabled. Turning off timer");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(createClockTickIntent(context));
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
Log.d(LOG_TAG, "Widget Provider enabled. Starting timer to update widget every second");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 10000, createClockTickIntent(context));
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
Log.d(LOG_TAG, "Updating Example Widgets.");
// Perform this loop procedure for each App Widget that belongs to this
// provider
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.lpwidget);
Intent configIntent = new Intent(context, LPWidgetConfigureActivity.class);
configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
configIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
configIntent.setData(Uri.parse(configIntent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
// Update The clock label using a shared method
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
if (notfirstTime) { //if it is not the first time, update
if (nowLP < maxNowLP) { //if the nowLP less than the max, add one.
nowLP = nowLP + 1;
}
}
notfirstTime = true;
String StringNowLP = "LP: " + Integer.toString(nowLP) + "/" + Integer.toString(maxNowLP);
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.lpwidget);
updateViews.setTextViewText(R.id.button, StringNowLP);
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
}
LPWidgetConfigureActivity.java
public class LPWidgetConfigureActivity extends Activity {
static int currentLP = 20;
static int maxLP = 50;
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
public LPWidgetConfigureActivity() {
super();
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED);
setContentView(R.layout.lpwidget_configure);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
final EditText currentLPText = (EditText) findViewById(R.id.currentLPText);
final EditText MaxLPText = (EditText) findViewById(R.id.MaxLPText);
Button applyButton = (Button) findViewById(R.id.add_button);
applyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = LPWidgetConfigureActivity.this;
try { //No empty text - update all
String intcurrentLP = currentLPText.getText().toString();
String intMaxLP = MaxLPText.getText().toString();
currentLP = Integer.parseInt(intcurrentLP);
maxLP = Integer.parseInt(intMaxLP);
LPWidget.nowLP = currentLP;
LPWidget.maxNowLP = maxLP;
} catch (NumberFormatException e) {
try { //Empty currentLP text - update MaxLP
String intMaxLP = MaxLPText.getText().toString();
maxLP = Integer.parseInt(intMaxLP);
LPWidget.maxNowLP = maxLP;
Context toastcontext = getApplicationContext();
CharSequence text = "Max LP is updated only";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
} catch (NumberFormatException e1) {
try { //empty MaxLP text - update currentLP
String intcurrentLP = currentLPText.getText().toString();
currentLP = Integer.parseInt(intcurrentLP);
LPWidget.nowLP = currentLP;
Context toastcontext = getApplicationContext();
CharSequence text = "Current LP is updated only";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
} catch (NumberFormatException e2) { //All empty text - No changes
Context toastcontext = getApplicationContext();
CharSequence text = "No Text Inputted - No Changes done";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
}
}
}
LPWidget.notfirstTime = false;
// It is the responsibility of the configuration activity to update the app widget
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
LPWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
});
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="doingitnow.simplelptracker" >
<application
android:allowBackup="true"
android:label="@string/app_name"
android:theme="@android:style/Theme.WallpaperSettings" >
<activity
android:name=".LPMainPage"
android:label="@string/title_activity_lpmain_page"
android:theme="@android:style/Theme.WallpaperSettings" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".LPWidgetConfigureActivity"
android:theme="@android:style/Theme.WallpaperSettings" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name=".LPWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="doingitnow.simplelptracker.CLOCK_WIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/lpwidget_info" />
</receiver>
<activity
android:name=".LPUpdateActivity"
android:label="@string/title_activity_lpupdate"
android:theme="@android:style/Theme.WallpaperSettings">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
经历了很多痛苦之后,我设法弄清楚了为什么配置 activity 从来没有 运行。
首先,calendar.add(Calendar.SECOND, 10);
表示设置闹钟后,等待10秒直到触发闹钟。这意味着如果我要在 10 秒之前完成我的配置 activity,它不会触发警报和更新,直到 10 秒结束。如果 activity 在警报后 10 秒完成,activity 将正常工作。
然而,当配置 activity 更新小部件时 LPWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);
只会更新屏幕上的内容而不会为按钮创建远程视图,因为它位于 onUpdate()
功能。由于我将信息提供程序中的 updateperiodmillis
设置为 0,因此该功能永远不会更新,因此远程视图将在警报更新后启动。此外,制作了两个远程视图,这会引起更多混乱,因此合并我拥有的两个远程视图并将其放置在 updateAppWidget(context, appWidgetManager, mAppWidgetId);
中意味着可以按下按钮并在屏幕上更新小部件。
多年来我一直在努力解决这个问题,并尝试了至少 10 种关于堆栈溢出的解决方案,但都没有成功。
我创建了一个小部件 class,它在每 5 分钟更新一次的主屏幕上显示一些数字。 Widget 是一个按钮,当用户单击它时,配置 activity 会加载,以便可以更新 widget。
当我第一次创建小部件时,配置 activity 打开,用户可以在文本框中键入。配置完成后,小部件将更新 - 一切都按预期工作。但是,当按下按钮时,配置 activity 不会再次启动。奇怪的是,当我通过 android studio 重新 运行 应用程序或重新启动 phone 时,activity 可以启动。我认为这与它由于某种原因没有更新按下的按钮有关,但我找不到修复它的地方。
我看到有几个类似的问题有我的问题并尝试了他们的解决方案,但它根本不起作用。我在 android 编程方面还很陌生,所以我可能忽略了一些东西。我对一些需要更改的变量进行了非常糟糕的硬编码,但我认为这不会影响 activity.
的启动这是我的 WidgetProvider、配置 Activity classes 和清单。
LPWidget.java
public class LPWidget extends AppWidgetProvider {
private static final String LOG_TAG = "ExampleWidget";
static int nowLP = LPWidgetConfigureActivity.currentLP ;
static int maxNowLP = LPWidgetConfigureActivity.maxLP;
static boolean notfirstTime = false;
/**
* Custom Intent name that is used by the AlarmManager to tell us to update the clock once per second.
*/
public static String CLOCK_WIDGET_UPDATE = "doingitnow.simplelptracker.CLOCK_WIDGET_UPDATE";
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (CLOCK_WIDGET_UPDATE.equals(intent.getAction())) {
Log.d(LOG_TAG, "Clock update");
// Get the widget manager and ids for this widget provider, then call the shared
// clock update method.
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName());
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
for (int appWidgetID: ids) {
updateAppWidget(context, appWidgetManager, appWidgetID);
}
}
}
private PendingIntent createClockTickIntent(Context context) {
Intent intent = new Intent(CLOCK_WIDGET_UPDATE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pendingIntent;
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
Log.d(LOG_TAG, "Widget Provider disabled. Turning off timer");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(createClockTickIntent(context));
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
Log.d(LOG_TAG, "Widget Provider enabled. Starting timer to update widget every second");
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 10);
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), 10000, createClockTickIntent(context));
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
Log.d(LOG_TAG, "Updating Example Widgets.");
// Perform this loop procedure for each App Widget that belongs to this
// provider
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.lpwidget);
Intent configIntent = new Intent(context, LPWidgetConfigureActivity.class);
configIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
configIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
configIntent.setData(Uri.parse(configIntent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
// Update The clock label using a shared method
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {
if (notfirstTime) { //if it is not the first time, update
if (nowLP < maxNowLP) { //if the nowLP less than the max, add one.
nowLP = nowLP + 1;
}
}
notfirstTime = true;
String StringNowLP = "LP: " + Integer.toString(nowLP) + "/" + Integer.toString(maxNowLP);
RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.lpwidget);
updateViews.setTextViewText(R.id.button, StringNowLP);
appWidgetManager.updateAppWidget(appWidgetId, updateViews);
}
LPWidgetConfigureActivity.java
public class LPWidgetConfigureActivity extends Activity {
static int currentLP = 20;
static int maxLP = 50;
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
public LPWidgetConfigureActivity() {
super();
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Set the result to CANCELED. This will cause the widget host to cancel
// out of the widget placement if the user presses the back button.
setResult(RESULT_CANCELED);
setContentView(R.layout.lpwidget_configure);
// Find the widget id from the intent.
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
}
// If this activity was started with an intent without an app widget ID, finish with an error.
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
final EditText currentLPText = (EditText) findViewById(R.id.currentLPText);
final EditText MaxLPText = (EditText) findViewById(R.id.MaxLPText);
Button applyButton = (Button) findViewById(R.id.add_button);
applyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Context context = LPWidgetConfigureActivity.this;
try { //No empty text - update all
String intcurrentLP = currentLPText.getText().toString();
String intMaxLP = MaxLPText.getText().toString();
currentLP = Integer.parseInt(intcurrentLP);
maxLP = Integer.parseInt(intMaxLP);
LPWidget.nowLP = currentLP;
LPWidget.maxNowLP = maxLP;
} catch (NumberFormatException e) {
try { //Empty currentLP text - update MaxLP
String intMaxLP = MaxLPText.getText().toString();
maxLP = Integer.parseInt(intMaxLP);
LPWidget.maxNowLP = maxLP;
Context toastcontext = getApplicationContext();
CharSequence text = "Max LP is updated only";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
} catch (NumberFormatException e1) {
try { //empty MaxLP text - update currentLP
String intcurrentLP = currentLPText.getText().toString();
currentLP = Integer.parseInt(intcurrentLP);
LPWidget.nowLP = currentLP;
Context toastcontext = getApplicationContext();
CharSequence text = "Current LP is updated only";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
} catch (NumberFormatException e2) { //All empty text - No changes
Context toastcontext = getApplicationContext();
CharSequence text = "No Text Inputted - No Changes done";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(toastcontext, text, duration);
toast.show();
}
}
}
LPWidget.notfirstTime = false;
// It is the responsibility of the configuration activity to update the app widget
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
LPWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);
// Make sure we pass back the original appWidgetId
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
});
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="doingitnow.simplelptracker" >
<application
android:allowBackup="true"
android:label="@string/app_name"
android:theme="@android:style/Theme.WallpaperSettings" >
<activity
android:name=".LPMainPage"
android:label="@string/title_activity_lpmain_page"
android:theme="@android:style/Theme.WallpaperSettings" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".LPWidgetConfigureActivity"
android:theme="@android:style/Theme.WallpaperSettings" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<receiver android:name=".LPWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="doingitnow.simplelptracker.CLOCK_WIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/lpwidget_info" />
</receiver>
<activity
android:name=".LPUpdateActivity"
android:label="@string/title_activity_lpupdate"
android:theme="@android:style/Theme.WallpaperSettings">
<intent-filter>
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
经历了很多痛苦之后,我设法弄清楚了为什么配置 activity 从来没有 运行。
首先,calendar.add(Calendar.SECOND, 10);
表示设置闹钟后,等待10秒直到触发闹钟。这意味着如果我要在 10 秒之前完成我的配置 activity,它不会触发警报和更新,直到 10 秒结束。如果 activity 在警报后 10 秒完成,activity 将正常工作。
然而,当配置 activity 更新小部件时 LPWidget.updateAppWidget(context, appWidgetManager, mAppWidgetId);
只会更新屏幕上的内容而不会为按钮创建远程视图,因为它位于 onUpdate()
功能。由于我将信息提供程序中的 updateperiodmillis
设置为 0,因此该功能永远不会更新,因此远程视图将在警报更新后启动。此外,制作了两个远程视图,这会引起更多混乱,因此合并我拥有的两个远程视图并将其放置在 updateAppWidget(context, appWidgetManager, mAppWidgetId);
中意味着可以按下按钮并在屏幕上更新小部件。