应用程序的快速说明。这是一个简单的小部件,其中4个值通过SharedPreferences保存。唯一的活动视图是设置首选项的位置。完成后,将保存变量,并更新窗口小部件。小部件每90,000ms更新一次。这一切都很好。我遇到的问题是方向改变时。发生这种情况时,窗口小部件将被销毁,然后重新制作。我得到的是原始XML,其中变量Text fields设置为default。它会保持这样,直到下一次手动或自动更新。
修改 这个问题现在已大大改变了。我得到的两个回答指出了一些错误的事情。阅读所有评论,看看所有这些。在最后一次尝试(尝试在清单中实现标记)之后,我得到了更糟糕的结果。该程序根本无法运行。
我在提出这个想法的同一个答案中说了最后一句话。我的onUpdate()一定有问题。以下是整个班级的代码:
public class WatchWidget extends AppWidgetProvider
{
public void onCreate(Context context, Bundle savedInstanceState)
{
RemoteViews remoteViews;
remoteViews = new RemoteViews( context.getPackageName(), R.layout.main );
remoteViews.setTextViewText( R.id.widget_elapsedtime, "Time");
}
@Override
public void onUpdate( Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
super.onUpdate(context, appWidgetManager, appWidgetIds);
RemoteViews remoteViews;
ComponentName watchWidget;
DateFormat format = SimpleDateFormat.getTimeInstance( SimpleDateFormat.MEDIUM, Locale.getDefault() );
remoteViews = new RemoteViews( context.getPackageName(), R.layout.main );
watchWidget = new ComponentName( context, WatchWidget.class );
//remoteViews.setTextViewText( R.id.widget_textview, "" + format.format( new Date()));
//widget_date
Calendar c = Calendar.getInstance();
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
String formattedDate = df.format(c.getTime());
//remoteViews.setTextViewText( R.id.widget_date, formattedDate);
SharedPreferences prefs = context.getSharedPreferences("qsPrefs", context.MODE_PRIVATE);
String sdayTextEdit = prefs.getString("dayTextEdit", "23");
//String sdayTextEdit ="23";
String smonthTextEdit = prefs.getString("monthTextEdit", "3");
String syearTextEdit = prefs.getString("yearTextEdit", "2014");
String scostTextEdit = prefs.getString("costTextEdit", "8.5");
String spacksTextEdit = prefs.getString("packsTextEdit", ".95");
//Starting day
Calendar pastdate = Calendar.getInstance();
//int inputDay = 25;
int inputDay = Integer.valueOf(sdayTextEdit);
int inputMonth = 2; //starts at 0
inputMonth = Integer.valueOf(smonthTextEdit);
int inputMonthAdj = inputMonth-1;
int inputYear = 2014;
inputYear = Integer.valueOf(syearTextEdit);
pastdate.set(Calendar.DAY_OF_MONTH, inputDay);
pastdate.set(Calendar.MONTH, inputMonthAdj);
pastdate.set(Calendar.YEAR, inputYear);
double packsPer = .95;
packsPer = Double.parseDouble(spacksTextEdit.toString());
double perPack = 8.57;
perPack = Double.parseDouble(scostTextEdit.toString());
inputMonthAdj = inputMonth;
remoteViews.setTextViewText( R.id.widget_date, "From: " + inputMonthAdj +"/"+ inputDay +"/"+ inputYear );
SfinalDate = "From: " + inputMonthAdj +"/"+ inputDay +"/"+ inputYear;
Calendar today = Calendar.getInstance();
DecimalFormat dform = new DecimalFormat("0.00");
long dateDiff = today.getTimeInMillis() - pastdate.getTimeInMillis();
long resultDays = dateDiff / (24*60*60*1000);
remoteViews.setTextViewText( R.id.widget_elapsedtime, ""+ resultDays);
double savedmoney = packsPer * perPack * resultDays;
String finalMoney = dform.format(savedmoney);
remoteViews.setTextViewText( R.id.widget_savedmoney, "$"+ finalMoney);
double notSmoked = resultDays * 20 * packsPer;
int finalNotSmoked = (int) Math.round(notSmoked);
remoteViews.setTextViewText( R.id.widget_cigsnot, ""+ finalNotSmoked);
SfinalMoney = "$"+ finalMoney;
SfinalNS = ""+ finalNotSmoked;
SfinalDays = ""+ resultDays;
appWidgetManager.updateAppWidget( watchWidget, remoteViews );
//Show Prefs screen
Intent intent = new Intent(context, preferences.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.LinearLayout01, pendingIntent);
appWidgetManager.updateAppWidget( watchWidget, views );
}
}
发布了......可能会有一些额外的行试图设置不再相关的东西。但代码是有效的。 onUpdate()以自动间隔(90000ms)激发。并且启动以设置首选项的活动也会在关闭时进行调用,这也会更新它。这就是让我相信整个空白必须正常的原因。但一定有些不妥。因为当屏幕方向更改时,onUpdate()不会运行。而且,根据第二个答案,它无论如何都不应该,因为系统应该保留它自己的UI。但事实并非如此。
答案 0 :(得分:4)
您尝试执行的操作适用于活动但不适用于BroadcastReceiver。 AppWidgetProvider是BroadcastReceiver,没有您尝试覆盖的方法(onSaveInstanceState,onRestoreInstanceState)。如果将@Override注释添加到它告诉您的方法
YourWidgetProvider类型的方法xyz()必须覆盖或实现 超类型方法
那是因为AppWidgetProvider类没有onSaveInstanceState或onRestoreInstanceState方法,你不能覆盖那里没有的东西。只是删除@Override注释将摆脱编译错误,但你只需要添加一个永远不会被调用的方法(除非你自己自己做,但这没有意义)。
解决此问题的方法是在应用程序中侦听配置更改,并向窗口小部件广播ACTION_APPWIDGET_UPDATE。
将应用类添加到您的应用
public class MyApplication extends Application {
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// create intent to update all instances of the widget
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidgetProvider.class);
// retrieve all appWidgetIds for the widget & put it into the Intent
AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(this);
ComponentName cm = new ComponentName(this, MyWidgetProvider.class);
int[] appWidgetIds = appWidgetMgr.getAppWidgetIds(cm);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
// update the widget
sendBroadcast(intent);
}
}
只要发生配置更改,就会调用该方法,其中一个是方向更改。您可以通过仅在方向改变时进行广播而不是例如广播来改进方法。改变系统语言。 该方法基本上向您的窗口小部件的所有实例发送更新广播(将您用于窗口小部件提供程序的名称替换为MyWidgetProvider)。
在清单中定义MyApplication
<application
android:name="yourpackagename.MyApplication"
android:description="@string/app_name"
android:label="@string/app_name"
android:icon="@drawable/app_icon">
<!-- here go your Activity definitions -->
</application>
重要只有在横向和纵向使用不同的布局时才需要这样做。这不是必需的,因为Android负责保存和恢复小部件的ui状态。如果你得到一个带有默认值的小部件,那么你在onUpdate方法中做错了什么。 现在我看看你的onUpdate方法,有一个主要问题(还有其他问题,但我只会指出一个肯定会破坏你的小部件的方法)。
在使用已初始化的TextViews调用updateAppWidget后,您将创建新的RemoteView:
appWidgetManager.updateAppWidget( watchWidget, remoteViews );
//Show Prefs screen
Intent intent = new Intent(context, preferences.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
// this line gets rid of all the work you have done above
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.LinearLayout01, pendingIntent);
appWidgetManager.updateAppWidget( watchWidget, views );
因此,在创建视图并设置值之后,您将它全部抛弃并创建新的RemoteViews,它们显然具有空/未初始化的TextView。也没必要两次调用appWidgetManager.updateAppWidget,每次onUpdate调用就足够了。 所以你要做的就是:
remoteViews.setTextViewText( R.id.widget_cigsnot, ""+ finalNotSmoked);
SfinalMoney = "$"+ finalMoney;
SfinalNS = ""+ finalNotSmoked;
SfinalDays = ""+ resultDays;
//Show Prefs screen
Intent intent = new Intent(context, preferences.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.LinearLayout01, pendingIntent);
appWidgetManager.updateAppWidget( appWidgetIds, remoteViews );
请注意我正在使用updateAppWidget(int [] appWidgetIds,RemoteViews视图)而不是updateAppWidget(ComponentName提供程序,RemoteViews视图),因为它允许您仅更新某些窗口小部件实例,而您不需要保存的ComponentName你是另一行代码。
答案 1 :(得分:0)
onCreate()
的{{1}}。小部件应该在AppWidgetProvider
中更新,而不是在活动中更新。
小部件的生命周期与Activity的生命周期无关。
onUpdate()