安卓 - 屏幕方向切换导致页面重新加载

8
我要重新提出这个问题,因为有太多错误信息存在了,真的很沮丧。简而言之,当设备方向改变时,我不希望发生任何更改或事件。针对此问题,最流行的两种“解决方法”是:
1.通过在清单文件中添加android:screenOrientation =“portrait”(或“landscape”)来锁定活动的一个方向。 2.将android:configChanges =“screenOrientation”指定到标签中,告诉系统你想要自己处理屏幕变化。这样,活动将不会重新创建,但将接收回调(你可以忽略它,因为对你没有用)。
以上两种都无法解决我的问题。因此,让我更详细地解释我的特殊问题...
我正在尝试使用一款非常简单的应用程序作为学习练习。我在服务器上有一个文本文件,文件中只有一个内容:单行整数。这个数字是同样存储在服务器上的图像文件数量,图像都命名为0.jpg、1.jpg、2.jpg等。
我的所有代码都在活动的onCreate方法中(正如我所说,这是一个简单的应用程序)。
当应用程序运行时,它会执行以下操作: 读取文本文件中的数字。 从零到文件中的数字生成随机数。 使用URL中的随机数将随机图像加载到ImageView中。
当屏幕旋转时,我不希望所有这些都再次发生。我只想要什么也不发生...除了屏幕显然旋转并且图像应该被缩放以适合屏幕,这确实发生了。但是每次屏幕旋转时,所有代码都会运行,并选择一个新的随机图像。请问有人能够给出一个简单的解决方案和有效的代码来解决这个问题吗?我通过看见代码学习,如果您不能提供代码示例,那将没用。
提前感谢您。
顺便说一下......我不寻求以不同方式完成我的工作,这不是重点。我想要修复当前的方法。

啊,你的代码一定是哪里出了问题:“android:configChanges=”screenOrientation“”就是你想要处理的方式。如果你已经正确配置了它,你的“onCreate”方法将不会被重新运行。如果它被重新运行,那么你的配置就是错误的。请在问题正文中提供你的代码,我猜答案应该很简单。 - Femi
1
嗯嗯嗯...你在说我配置错了?如果你唯一要我做的事情就是在清单文件中添加那一行,我怎么可能做错呢? - Jimmy D
这就是我不确定的地方,也是为什么我要求看你的代码的原因。我有一份可行的代码,每次更改方向时都不会触发onCreate() - Femi
这是什么参数?android:configChanges="orientation" 还是 android:configChanges="screenOrientation" - auraham
5个回答

11

使用android:configChanges="orientation"解决方案只适用于应用程序 API 级别为 12 或更低级别的情况。

在 API 级别 13 或更高级别中,当方向改变时屏幕大小也会改变,因此仍然会导致活动在方向更改时被销毁并重新启动。

只需像下面一样添加"screenSize"属性即可:

<activity>
    android:name=".YourActivityName"
    android:configChanges="orientation|screenSize">
</activity>
现在,当你改变方向(屏幕大小也会改变)时,活动保留其状态并调用onConfigurationChanged()。这将使屏幕上的任何内容(例如WebView中的网页)在方向更改时保持不变。
从这个网站学到的:http://developer.android.com/guide/topics/manifest/activity-element.html 此外,这显然是一个不好的做法,所以请阅读下面关于处理运行时更改的链接: http://developer.android.com/guide/topics/resources/runtime-changes.html

嗨!我在竖屏和横屏模式下使用不同的布局,所以不能使用android:configChanges,有其他解决方案吗? - Shajeel Afzal

3

这里有一个非常相似的问题:当方向改变时不要重新加载应用程序

首先,您应该将代码从onCreate更改为另一个方法,并将其分为“创建随机数和从网络加载图像”以及“将图像设置到视图”两个部分。

在活动中有一个位图,您需要每次启动活动时都检查它是否为空。

如果是,则执行全部操作。如果不是,则仅使用您已经拥有的Bitmap设置ImageView或其他内容。

为了避免旋转时破坏位图,请使用:

    Bitmap image = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);

 image = (Bitmap) getLastNonConfigurationInstance();

     if(bitmap == null){
         image = downloadImage();
      }
     setImage(bitmap);
}


@Override
public Object onRetainNonConfigurationInstance() {
    return bitmap;
}

这个可以,我100%确定。


1
是的,那是我的问题。没有一个解决方案有效。人们只是发布这些东西,从来没有测试过代码。有点荒谬。 - Jimmy D
@NeTeInStEiN:这是JJD的同样问题。 - techi.services
请注意,您在此处检索的数据仅应用于处理配置更改的优化。您应该始终能够处理返回空指针,并且即使此函数返回null,活动仍必须能够通过正常的onSaveInstanceState(Bundle)机制将自身恢复到先前的状态。 - techi.services
你需要复习Java。在try块之前定义变量,而不是仅在try上下文中。Bitmap name = null;try{name = ...}catch(Exception e){ ... }return name; - neteinstein
呼,我觉得这个可能真的能用了,谢谢。当我捕获到一个异常时,我应该返回什么?还有在finally里面怎么处理? - Jimmy D
显示剩余2条评论

0

0

对我而言有效的方法是将类变量之一声明为静态变量。 事实证明,静态类变量在应用程序加载时只初始化一次,但当应用程序重新加载时,这些变量不会再次初始化。

这些变量可以保存状态或对象,您不希望重新初始化。 我不能说这不是非常优雅的方法,但经过测试并且对我而言有效。


0
例如,将其添加到清单中:
<activity android:name=".Explorer" android:label="@string/app_name"
            android:configChanges="orientation" android:launchMode="standard">
        </activity>

然后只需覆盖默认函数:

    @Override
        public void onConfigurationChanged(Configuration _newConfig){
            super.onConfigurationChanged(_newConfig);
int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        if(width > height){
// layout for landscape
}else{
// layout for portrait
        }
            }

注意:如果您覆盖此函数,则必须自己重新布局。这是实现您想要的唯一方法。Android解决屏幕大小问题的方法是将整个Activity关闭,然后使用新的尺寸再次启动它。如果您选择不关闭Activity,则必须处理屏幕大小更改。没有其他选项。

编辑:在这个特定的应用程序中,我有一个在纵向显示的表格和一个在横向显示的图表。所以我这样做:

void showDataView()
    {
        setContentView(mainView);
        currentView = mainView; 
    }

    void showGraphView()
    {
        if(currentView == mainView){
            if(graphView == null){
                setContentView(R.layout.graphview);
                graphView = (GraphView)findViewById(R.id.graphview);
            }
            setContentView(graphView);
            currentView = graphView;
            graphView.setDataToPlot(DATA_TO_PLOT);
            graphView.clear();
        }
    }

@Override
    public void onConfigurationChanged(Configuration _newConfig){
        super.onConfigurationChanged(_newConfig);
        int height = getWindowManager().getDefaultDisplay().getHeight();
        int width = getWindowManager().getDefaultDisplay().getWidth();
        if(width > height){
            showGraphView();
        }else{
            showDataView();
        }
        if(graphView != null) graphView.setGraphWidth(width);
    }

每次方向改变时,我会将内容视图从一个切换到另一个。在您的情况下,您可能只需invalidate当前根视图,看看它是否能正确重绘。
这就是为什么您希望平台来处理它,这样您就不必处理这些垃圾。最好只使用onSaveInstanceState来保留您需要的特定数据,然后在onCreate中检查该数据,然后使用它。有关详细信息,请参见http://developer.android.com/reference/android/app/Activity.html#ConfigurationChanges

好的,那我把这段代码放在哪里?是放在我的Activity的onCreate方法之前吗? - Jimmy D
@Femi 这是唯一正确的答案。我发现最好强制屏幕方向并保持不变,特别是对于任何类型的艺术资源密集型应用程序。这就是为什么市场上大多数游戏都会强制定向并且不允许更改的原因。 - SRM
我需要在“横向布局”和“纵向布局”的区域中放置什么内容? - Jimmy D
在你的Activity中:它只是另一个Android回调函数,就像onCreate一样:你必须实现onConfigurationChanged,然后强制新布局生效。它所说的是,当屏幕方向发生变化时,不要销毁Activity,而是调用此函数,自己重新布局。你可能只需要获取根View并使其无效即可。 - Femi
我仍然不知道在if/else部分应该做什么。我可以有一个例子吗? - Jimmy D
配置包含手机的方向。 - techi.services

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