onConfigurationChanged 在旋转时未调用 configChanges=“keyboardHidden|orientation”放?

发布于 2024-12-09 20:49:50 字数 5320 浏览 1 评论 0原文

我不是第一个在轮换时调用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ㄟ。诗瑗 2024-12-16 20:49:50

Jon,

onConfigurationChanged() 并不是真正用于服务。由于 Services 没有 UI,因此无法保证 onConfigurationChanged() 不会可靠地触发。最好将其粘贴到 Activity 中,因为 Activity 保证具有用户界面。如果您担心 Widget 会根据方向变化重新调整,那么这最终是包含 Activity 需要处理的工作。这意味着如果 Activity 不旋转,您的 Widget 将不会自行重新定向。

但是,如果您仍然需要自己管理配置更改,那么您需要针对 DefaultDisplay 进行手动检查,如果方向发生变化,DefaultDisplay 会自动更改。这个简单的检查工作原理如下:

Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getWidth() > display.getHeight())
    // In Landscape...
else if (display.getWidth() < display.getHeight())
    // In Portrait...

现在,您所描述的问题虽然在方向更改时表现出来,但它并不是专门的方向更改问题。如果您查看 onUpdate() 的代码,您会发现您一次只处理一个小部件。问题在于方向更改的默认行为会破坏所有 UI 并重新创建它们。由于对 Widget 的多个副本的所有更新都会同时发生,并且您无法确定保存您的 widget 的 Activity 将如何处理方向更改,因此您应该考虑所有可能的 appWidgetId。以下内容可能会有所帮助:

for (int i : appWidgetIds) {
    int widgetId = appWidgetIds[i];
// Set the RemoteViews for the Widget
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
// Set the Pending Intent
    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);  
// Update the individual widget
    appWidgetManager.updateAppWidget(widgetId, remoteViews);
}

希望这会有所帮助。

模糊逻辑

Jon,

onConfigurationChanged() is not really meant for Services. As Services do not have a UI, there is no guarantee that onConfigurationChanged() will not fire dependably. It is best to stick this in an Activity, as Activities 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:

Display display = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getWidth() > display.getHeight())
    // In Landscape...
else if (display.getWidth() < display.getHeight())
    // In Portrait...

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:

for (int i : appWidgetIds) {
    int widgetId = appWidgetIds[i];
// Set the RemoteViews for the Widget
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
// Set the Pending Intent
    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);  
// Update the individual widget
    appWidgetManager.updateAppWidget(widgetId, remoteViews);
}

Hope this helps.

FuzzicalLogic

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文