我不能为我的生活弄清楚如何管理对话框而不使用configChanges来指定您想要手动处理方向更改。 所以,假设你有这个AndroidManifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testandroid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
拿这个MainActivity.java:
package com.example.testandroid;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
Dialog mDialog = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_main);
}
public void doShowDialog(View b) {
Log.d(TAG, "doShowDialog");
showDialog(1);
}
private void tryDismiss() {
Log.d(TAG, "tryDismiss");
try {
dismissDialog(1);
removeDialog(1);
mDialog.dismiss();
} catch(IllegalArgumentException ex) {
Log.e(TAG, ex.getMessage());
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
@Override
protected void onPause() {
tryDismiss();
super.onPause();
Log.d(TAG, "onPause");
}
@Override
protected Dialog onCreateDialog(int dialog) {
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
mDialog = b.create();
return mDialog;
}
}
和这个布局(main.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Dialog"
android:onClick="doShowDialog"
/>
</LinearLayout>
如果从onDestroy或onPause调用似乎没关系,对话框会在方向切换后显示备份。但为什么?我告诉它要走了。如果调用removeDialog / dismissDialog,它在方向更改之前调用时不执行任何操作。我无法弄清楚为什么会这样。摆脱这种我知道的唯一方法是使用
自己处理方向变化android:configChanges="keyboardHidden|orientation"
我知道新的工作方式是使用我尚未升级的FragmentDialog内容,并且我还没准备好重写我的整个应用程序。看起来很奇怪,这不起作用。
这只是我在我的应用中遇到的一个现实世界问题的示例,用户可以请求从远程服务器提取一些数据(更新微调器的数据),如果他们切换方向,则加载对话框将永远不会离开,除了使用android:configChanges选项处理方向更改之外似乎没有解决这个问题。我能做什么,但我必须做到这一点似乎很荒谬。
- 更新 - 删除按钮以关闭对话框,因为没有必要,因为对话框位于顶部,所以无论如何都无法单击它。
要重现只需启动应用程序,请单击打开对话框的按钮,然后旋转手机。
答案 0 :(得分:2)
您的对话框已保存在onSaveInstanceState
中,因此您可能会在启动之前尝试将其解除:
@Override
protected void onSaveInstanceState(Bundle state)
{
tryDismiss();
super.onSaveInstanceState(state);
}
另外我真的不明白为什么你使用Activity的onCreateDialog来管理对话框。它的设计原因是自动处理方向变化。如果你想手动处理它,为什么不只是使用对话框的功能?不是直接使用showDialog(id)
和onCreateDialog(id)
,而是在旋转屏幕后不再重新显示。
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
Dialog mDialog = b.create();
mDialog.show(); // <-----
答案 1 :(得分:1)
塞巴斯蒂安得到了它,但我想更多地解释一下情况以及我对话的发现,因为它可能很混乱:
比这更重要的是我学会了你是否正在做一些异步任务,比如一个HTTP调用,你有一个内部类,它包含一个回调函数,它将在任务完成时运行,你需要知道如果旋转屏幕,内部类方法将包含对外部Activity类的原始实例的引用。这对我来说并不是很明显,而且我实际上并没有使用AsyncTask,因为其他许多人都遇到了问题(我使用的是异步http库)。
举一个类似于我的真实代码的小例子:
public class MyActivity extends Activity {
private static MyActivity sThis;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
@Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
@Override
public void onWorkComplete() {
dismissDialog(LOADING_DIALOG); //doesn't work if orientation change happened.
}
});
}
}
以上代码通过CategoryManager连接到外部服务器,下载类别列表,一旦完成,就调用onCategoriesObtained然后onFetchComplete(为简洁起见,还会删除一些错误处理回调函数)。如果fetchCategories调用和onFetchComplete之间发生方向更改,则onFetchComplete中对dismissDialog的调用将永远不会起作用。原因是此内部类具有对在调整方向之前创建的Activity类的原始实例的隐式引用。因此,当您调用dismissDialog时,您在原始实例上调用它而不是新实例,这将导致dismissDialog失败并显示以下消息:&#34;没有通过Activity#showDialog&#34;显示没有ID为1的对话框。我确实找到了解决这个问题的方法,但它有点破解:
在Activity类中,包含对 this 引用的静态引用,并在onCreate中设置它,并在onDestroy中将其null,并使用内部类中的引用,如下所示:
public class MyActivity extends Activity {
private static MyActivity sThis;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
@Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
@Override
public void onWorkComplete() {
sThis.dismissDialog(LOADING_DIALOG);
}
});
}
}
请注意,我不确定这是一个很好的做法,但它对我有用。我知道在引用外部类(泄露上下文)的活动中可能存在内部类的问题,因此可能有更好的方法来解决这个问题。
答案 2 :(得分:0)
AFAIK,此窗口泄露可以通过两种方式处理。
HttpResponse
或
@Override
public void onDestroy(){
super.onDestroy();
if ( Dialog!=null && Dialog.isShowing() ){
Dialog.dismiss();
}
}
这里Dailog是你的进度/警报dailog
答案 3 :(得分:-1)
如果没有已保存的应用创建应用,则可以使用super.onCreate(null);