Button click lost on widget when screen is rotated

2019-04-09 03:42发布

问题:

I have a very simple widget application which consists of a LinearLayout with a background and an ImageButton.

In the AppWidgetProvider onUpdate() method, I register the click of the button to broadcast an intent. When the widget first loads, everything runs fine and the click is captured. The problem occurs when the screen is rotated, and the click is never captured again even if the screen is rotated back.

What do I have to do to re-register the click when the screen rotates?

below is some segments of code I am using.

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);
}

Manifest

<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>

Layout

    <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>

Thank you anyone for your help!

回答1:

This helped me: Android widget ImageButton loses image when screen is rotated

In short, you have to register the clicks (views.setOnClickPendingIntent) before EVERY call to awm.updateAppWidget



回答2:

I used a solution which requires a service on the widgetapp because it can handle orientation changes to the widgetapp. Unfortunately onReceive or onUpdate doesn't get called by orientation changes, but the service's onConfigurationChanged does get called. You need to have your service constantly running to detect these orientations as well. When the service detects the orientation change, then you proceed to change the remote view.

 @Override
 public void onUpdate(Context context, AppWidgetManager appWidgetManager,
   int[] appWidgetIds) {
  context.startService(new Intent(context, MyUpdateService.class));
 }

This is the service class that you need to implement. You can look at this if you need more information about the service. 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); 
  }

 } 
}


回答3:

As I understand it, Android actually kills and recreates your activity every time the screen is rotated. Yuck, I know.

So anyway, I suspect if you put log statements in all the various lifecycle callbacks, you'll find that update is only called the one time. You probably need to handle listening for clicks in another callback. I couldn't tell you which one without checking some reference material. I'll leave that as an exercise to the reader.



回答4:

hay have you use
android:configChanges="keyboardHidden|orientation"
with your Activity in Androidmanifest file.



回答5:

I am new to android, but I am fairly certain that this way of doing it will work.

@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);
    }
}

Then in the onCreate you can see if it should recreate the click event by checking getIntent().getBooleanExtra("Just received click", false) (false refers to the default value. If that code returns true, then the above code did it's job and you should recreate the click event)

This should work because the intent object (and it's extras) are saved, even if your app is temporarily killed. The intent will accept any Serializable extra.