当屏幕旋转时,小部件上的按钮单击事件丢失。

5
我有一个非常简单的小部件应用程序,它由一个带有背景和一个ImageButton的LinearLayout组成。
在AppWidgetProvider onUpdate()方法中,我注册按钮的点击以广播意图。当小部件首次加载时,一切都运行良好,并且可以捕获单击。问题发生在屏幕旋转时,即使屏幕旋转回来,点击也永远不会再次被捕获。
当屏幕旋转时,我需要做什么才能重新注册点击事件?
以下是我正在使用的一些代码段。
AppWidgetProvider
@Override
public void onReceive(Context context, Intent intent)    
{
    super.onReceive(context, intent);

    if(intent.getAction().equals("test.CLICK"))
    {
        CallTestMethod(context);
    }
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    int[] appWidgetIds) {
    final int N = appWidgetIds.length;

    // 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.widget);            
        Intent clickintent=new Intent("test.CLICK");
        PendingIntent pendingIntentClick=PendingIntent.getBroadcast(context, 0, clickintent, PendingIntent.FLAG_UPDATE_CURRENT);
        views.setOnClickPendingIntent(R.id.change_mode, pendingIntentClick);
        SetInitialLayout(context);
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }
    super.onUpdate(context, appWidgetManager, appWidgetIds);
}

清单

<receiver android:name=".Widget" android:label="@string/widget_name">
        <intent-filter>
            <action android:name="android.appwidget.action.ACTION_APPWIDGET_CONFIGURE" />
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            <action android:name="test.CLICK" />
        </intent-filter>
        <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_mode_switcher" />            
    </receiver>

布局

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/widget_layout"
    android:layout_width="140dip"
    android:layout_height="140dip"
    android:scaleType="fitCenter"
    android:orientation="vertical"
    android:background="@drawable/background">
    <ImageButton
        android:id="@+id/change_mode"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitCenter"
        android:orientation="vertical"
        android:src="@drawable/none_selected"
        android:background="@null"
        android:clickable="true" />
</LinearLayout>

感谢任何人的帮助!

5个回答

6

谢谢!我之前找不到一个对我来说有意义的答案,但是这个回答却是最容易理解的。我在另一个类中更新了我的小部件,但没有在那里包括setOnClickPendingIntent。现在我加上了,它可以工作了。 - hbustan
谢谢,我一年前就得找到这个答案,现在我正在创建一个新的小部件,又面临着同样的问题。我一直记不起来解决方法,直到我再次找到了相同的答案。 - sergi

1
我使用了一种解决方案,它需要在widgetapp上运行一个服务,因为它可以处理widgetapp的方向更改。不幸的是,onReceive或onUpdate不会被方向更改调用,但是服务的onConfigurationChanged会被调用。您需要让您的服务始终运行以检测这些方向更改。当服务检测到方向更改时,然后您可以继续更改远程视图。
 @Override
 public void onUpdate(Context context, AppWidgetManager appWidgetManager,
   int[] appWidgetIds) {
  context.startService(new Intent(context, MyUpdateService.class));
 }

这是您需要实现的服务类。如果您需要有关该服务的更多信息,可以查看此链接http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html

 public static class MyUpdateService extends Service 
 { 
  @Override
  public void onCreate() {
   super.onCreate();
  }

  @Override
  public void onDestroy() {
   super.onDestroy();
  }

  @Override 
  public void onStart(Intent intent, int startId) 
  { 
   super.onStart(intent, startId); 
   // Update the widget 
   RemoteViews remoteView = buildRemoteView(this); 

   // Push update to homescreen 
   pushUpdate(remoteView); 

             } 

  public RemoteViews buildRemoteView(Context context) 
  { 
   int layoutID = R.layout.widget;
   if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
    layoutID = R.layout.widget_landscape;
   }
                                    //Here is where you set your onclick listeners again since the remote views need to be refreshed/recreated
   RemoteViews updateView = new RemoteViews(context.getPackageName(),layoutID); 
   // Create an Intent to launch ExampleActivity
   Intent intent = new Intent(this, yourAndroidActivity.class);
   PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
     intent, 0);

   updateView.setOnClickPendingIntent(R.id.yourClickableViewHere, pendingIntent);

   return updateView; 
  } 

  @Override 
  public void onConfigurationChanged(Configuration newConfig) 
  { 
   RemoteViews remoteView = buildRemoteView(this); 
    // Push update to home screen 
   pushUpdate(remoteView); 
  } 

  private void pushUpdate(RemoteViews updateViews) 
  { 
   ComponentName myWidget = new ComponentName(this, YourAppWidget.class); 
   AppWidgetManager manager = AppWidgetManager.getInstance(this); 

                                    //This is where you can update your remoteViews
   updateViews.setTextViewText(R.id.YOUR_TEXTVIEW_ON_WIDGET, "" + "TEXT THAT WILL SHOW UP");
   manager.updateAppWidget(myWidget, updateViews); 
  }

 } 
}

0

据我所知,每次屏幕旋转时,Android实际上会杀死并重新创建您的活动。 呃,我知道。

总之,我怀疑如果您在所有各种生命周期回调中放置日志语句,您会发现更新仅被调用一次。 您可能需要在另一个回调中处理监听点击。 我不能告诉您哪个回调,而不检查一些参考资料。 我将把它留给读者作为练习。


1
我已经查看了可用于AppWidgetProvider的其他覆盖... Enabled,Disabled,Deleted,Receive,Update。我为每个添加了意图过滤器,并在调试时设置了断点,但当屏幕旋转时,它们都没有被触发,因此我无法找到在小部件生命周期中注册单击的位置。 - David
抱歉...不是小部件生命周期,而是Activity生命周期。对于混淆感到抱歉。 - Mark Storer

0

嗨,你在AndroidManifest文件中使用了android:configChanges="keyboardHidden|orientation"吗?


我对Android开发仍然很陌生,所以我还没有尝试所有的技巧和所需之物。但我现在正在开发一个小部件,我需要这样做吗?谢谢。 - David

-1

我是Android的新手,但我相当确定这种方法会起作用。

@Override
public void onReceive(Context context, Intent intent)    
{
    super.onReceive(context, intent);
    if(intent.getAction().equals("test.CLICK"))
    {
        getIntent().putExtra("Just received click", true);
        CallTestMethod(context);
    }
}

然后在onCreate中,您可以通过检查getIntent().getBooleanExtra("Just received click", false)来确定是否应重新创建单击事件(false是默认值)。如果该代码返回true,则上面的代码已经完成了它的工作,您应该重新创建单击事件。

这应该可以工作,因为意图对象(及其额外内容)会被保存,即使您的应用程序被暂时终止。该意图将接受任何可序列化的额外内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接