简体   繁体   中英

How to detect orientation change in home screen widget?

I am writing a home screen widget and want to update the home screen widget when the device orientation changes from portrait to landscape or the other way. How can I make it?

Currently, I tried to reigster to CONFIGURATION_CHANGED action like the code below, but the Android didn't allow me to do that by saying "IntentReceiver components are not allowed to register to receive intents". Can someone help me? Thanks.

public class MyWidget extends AppWidgetProvider {

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        this.registerReceiver(this, new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
    }

I know it's an old question but there's indeed an easier way to do this than delegating the update to an IntentService. The way to deal with orientation changes is to listen for configuration changes in the Application and broadcast an ACTION_APPWIDGET_UPDATE to the widget.

Add an Application class to your app

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, MyWidget.class);

        // retrieve all appWidgetIds for the widget & put it into the Intent
        AppWidgetManager appWidgetMgr = AppWidgetManager.getInstance(this);
        ComponentName cm = new ComponentName(this, MyWidget.class);
        int[] appWidgetIds = appWidgetMgr.getAppWidgetIds(cm);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);

        // update the widget
        sendBroadcast(intent);
    }
}

The method will be called whenever a configuration change occurs, one of them being an orientation change. You could improve the method by doing the broadcast only when it's an orientation change and not eg a change of the system language. The method basically sends an update broadcast to all instances of your widget.

Define the MyApplication in your manifest

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

You probably shouldn't need to do this. You can use layout and layout-land folders to provide different layouts in each orientation via xml without manually detecting rotation. However, you shouldn't do anything functionally different in each orientation as a lot of devices can't rotate the homescreen and whatever features you put in will be inaccessible for them.

While I sorta agree with jqpubliq's answer, so long as you think about what you're doing and design matters properly, you are welcome to implement different layouts for different orientations. It's just going to be complicated.

The error message you received should be self-explanatory: BroadcastReceivers (like AppWidgetProvider ) cannot register for other broadcasts. After all, a manifest-registered BroadcastReceiver instance should be in memory for milliseconds, not forever.

Hence, to implement this logic, you will need to:

  1. Create an IntentService that handles the actual app widget updates, and have your AppWidgetProvider delegate its work to that. Here is an example .
  2. Create a separate BroadcastReceiver implementation, registered in the manifest to receive CONFIGURATION_CHANGED broadcast Intents .
  3. Have that new BroadcastReceiver also use the IntentService (eg, call startService() ).
  4. Have IntentService handle the updates for both orientations, emanating from both receivers.

On Android 3.x and above, who has RemoteViewsService, can be used

@Override
public void onConfigurationChanged(Configuration newConfig) {
   super.onConfigurationChanged(newConfig);
   //call widget update methods/services/broadcasts 
}

in RemoteViewsService childs. If widget will not be updated, widget UI can be cleaned or just hangs and stop react on external events.

Since Android API 16, there is a new override that receives information about widget options changes, mainly min/max width/height.

@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions)

When this is called, one can check current device orientation and update widgets appropriately, or "simply" call the onUpdate() method which will have to get orientation information.

@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions)
{
    int width = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
    int height = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
    int orientation = context.getResources().getConfiguration().orientation;

    if (BuildConfig.DEBUG) logWidgetEvents("UPDATE " + width + "x" + height + " - " + orientation, new int[] { appWidgetId }, appWidgetManager);

    onUpdate(context, appWidgetManager, new int[] { appWidgetId });
}

The onUpdate() can do something like this:

int rotation = context.getResources().getConfiguration().orientation;
if (rotation == Configuration.ORIENTATION_PORTRAIT)
{
    ... portrait ...
}
else
{
    ... landscape ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM