onConfigurationChanged 在旋转时未调用 configChanges=“keyboardHidden|orientation”放?
我不是第一个在轮换时调用 onConfigurationChanged 时遇到问题的人。但由于常见的解决方案是设置 configChanges="keyboardHidden|orientation" 在清单中,这对我没有帮助,我发布这个问题,不管有成千上万的“类似”问题。
这是一个简单的小部件,单击时可以打开和关闭铃声音量。它工作正常,直到屏幕旋转,之后单击时没有任何反应。
为了解决这个问题,我想捕获 onConfigurationChanged,但它永远不会被调用! 我从来没有看到来自 onConfigurationChanged 的日志消息,但是我在日志中看到另一条消息“I/ActivityManager( 63): Config Changed: ”,表明配置已更改,并且期望调用 onConfigurationChanged 是合理的。
请帮助:)
清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="aa.android.x10.mini.mywidget" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<receiver android:name="MyWidgetProvider" android:label="My Widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.ACTION_BATTERY_CHANGED" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
<service android:name=".UpdateWidgetService"
android:configChanges="keyboardHidden|orientation"></service>
<activity android:name=".Test"></activity>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>
WidgetProvider: 包aa.android.x10.mini.mywidget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
public class MyWidgetProvider extends AppWidgetProvider
{
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
Log.i("MyWidgetProvider onUpdate", "#### CALLED!");
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
context.startService(intent);
}
}
服务: 包aa.android.x10.mini.mywidget;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;
public class UpdateWidgetService extends Service
{
@Override
public void onStart(Intent intent, int startId)
{
Log.i("UpdateWidgetService", "#### CALLED!");
String state = null;
AudioManager mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL )
{
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
mAudioManager.setStreamVolume(AudioManager.STREAM_RING,mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING),AudioManager.VIBRATE_SETTING_ON);
state = "ON";
}
else
{
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
mAudioManager.setStreamVolume(AudioManager.STREAM_RING,0,AudioManager.VIBRATE_SETTING_ON);
state = "OFF";
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext());
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds.length > 0)
{
for (int widgetId : appWidgetIds)
{
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.widget_layout);
remoteViews.setTextViewText(R.id.TextView01, "\n" +" "+ state);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
}
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
Log.i("onConfigurationChanged", "##### CALLED! #####");
super.onConfigurationChanged(newConfig);
}
}
旋转屏幕时记录:
I/WindowManager( 63): Setting rotation to 1, animFlags=0
I/ActivityManager( 63): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/1 nav=3/1 orien=2 layout=17}
I/UsageStats( 63): Unexpected resume of com.android.launcher while already resumed in com.android.launcher
I'm not the first one to have problems with getting onConfigurationChanged called at rotation. But since the common solution is to set configChanges="keyboardHidden|orientation"
in the manifest, and that does not help me, I posting this question regardless of the thousands of “similar” ones.
This is a simple widget that turns the ringer volume on and off when clicked. It works fine until the screen is rotated, after that nothing happens on click.
To deal with this issue I want to catch onConfigurationChanged, but it never gets called!
I never get to see the log message from onConfigurationChanged, I do however see another message in the log “I/ActivityManager( 63): Config changed: ” indicating that the configuration gets changed and that it would be reasonable to expect a call to onConfigurationChanged.
Please help :)
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="aa.android.x10.mini.mywidget" android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon"
android:label="@string/app_name">
<receiver android:name="MyWidgetProvider" android:label="My Widget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.ACTION_BATTERY_CHANGED" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
<service android:name=".UpdateWidgetService"
android:configChanges="keyboardHidden|orientation"></service>
<activity android:name=".Test"></activity>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>
WidgetProvider:
package aa.android.x10.mini.mywidget;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
public class MyWidgetProvider extends AppWidgetProvider
{
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
Log.i("MyWidgetProvider onUpdate", "#### CALLED!");
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widget_layout);
Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getService(context.getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.TextView01, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
context.startService(intent);
}
}
Service:
package aa.android.x10.mini.mywidget;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.IBinder;
import android.util.Log;
import android.widget.RemoteViews;
public class UpdateWidgetService extends Service
{
@Override
public void onStart(Intent intent, int startId)
{
Log.i("UpdateWidgetService", "#### CALLED!");
String state = null;
AudioManager mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL )
{
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
mAudioManager.setStreamVolume(AudioManager.STREAM_RING,mAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING),AudioManager.VIBRATE_SETTING_ON);
state = "ON";
}
else
{
mAudioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
mAudioManager.setStreamVolume(AudioManager.STREAM_RING,0,AudioManager.VIBRATE_SETTING_ON);
state = "OFF";
}
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this.getApplicationContext());
int[] appWidgetIds = intent.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
if (appWidgetIds.length > 0)
{
for (int widgetId : appWidgetIds)
{
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.widget_layout);
remoteViews.setTextViewText(R.id.TextView01, "\n" +" "+ state);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
stopSelf();
}
super.onStart(intent, startId);
}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public void onConfigurationChanged(Configuration newConfig)
{
Log.i("onConfigurationChanged", "##### CALLED! #####");
super.onConfigurationChanged(newConfig);
}
}
Log when rotating the screen:
I/WindowManager( 63): Setting rotation to 1, animFlags=0
I/ActivityManager( 63): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/1 nav=3/1 orien=2 layout=17}
I/UsageStats( 63): Unexpected resume of com.android.launcher while already resumed in com.android.launcher
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Jon,
onConfigurationChanged()
并不是真正用于服务
。由于Services
没有 UI,因此无法保证onConfigurationChanged()
不会可靠地触发。最好将其粘贴到Activity
中,因为Activity
保证具有用户界面。如果您担心 Widget 会根据方向变化重新调整,那么这最终是包含 Activity 需要处理的工作。这意味着如果 Activity 不旋转,您的 Widget 将不会自行重新定向。但是,如果您仍然需要自己管理配置更改,那么您需要针对
DefaultDisplay
进行手动检查,如果方向发生变化,DefaultDisplay 会自动更改。这个简单的检查工作原理如下:现在,您所描述的问题虽然在方向更改时表现出来,但它并不是专门的方向更改问题。如果您查看
onUpdate()
的代码,您会发现您一次只处理一个小部件。问题在于方向更改的默认行为会破坏所有 UI 并重新创建它们。由于对 Widget 的多个副本的所有更新都会同时发生,并且您无法确定保存您的 widget 的 Activity 将如何处理方向更改,因此您应该考虑所有可能的 appWidgetId。以下内容可能会有所帮助:希望这会有所帮助。
模糊逻辑
Jon,
onConfigurationChanged()
is not really meant forServices
. AsServices
do not have a UI, there is no guarantee thatonConfigurationChanged()
will not fire dependably. It is best to stick this in anActivity
, asActivities
are guaranteed to have a User Interface. If you are concerned about your Widget realigning to an orientation change, that is ultimately a job for the containing Activity to handle. This means if the Activity does not rotate, your Widget will not reorient itself.If, however, you still need to manage configuration changes yourself, then you need to do your checks manually against the
DefaultDisplay
which automatically changes if the orientation changes. This simple check works as follows:Now, the issue you describe, while it manifests itself when the Orientation changes, it is not specifically an Orientation Change problem. If you look at the code for your
onUpdate()
, you will see that you are only handling one widget at a time. The issue with this is that the default behavior of an orientation change destroys all UIs and recreates them. Since all updates to multiple copies of a Widget happen at once and you cannot determine how the Activity that holds your widget is going to handle orientation changes, you should account for all of your possible appWidgetIds. The following may help:Hope this helps.
FuzzicalLogic