乐者为王

Do one thing, and do it well.

使用showDialog()创建的ProgressDialog再次打开时进度条不变化

先来看段代码:

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <Button
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Copy Contacts"
        android:onClick="copyContacts" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;

public class DialogActivity extends Activity {
    private static final int COPY_CONTACTS = 0;

    private ProgressDialog mProgressDialog;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void copyContacts(View target) {
        showDialog(COPY_CONTACTS);
    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case COPY_CONTACTS:
            mProgressDialog = new ProgressDialog(this);
            mProgressDialog.setTitle("Copy contacts");
            mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            mProgressDialog.setMax(100);
            new AsyncCopyContactsTask().execute();
            break;
        }
        return mProgressDialog;
    }

    private class AsyncCopyContactsTask extends AsyncTask<Void, Void, Integer> {
        @Override
        protected Integer doInBackground(Void... params) {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                }
                publishProgress();
            }
            return 0;
        }

        protected void onProgressUpdate(Void... progress) {
            mProgressDialog.incrementProgressBy(1);
        }

        protected void onPostExecute(Integer result) {
            mProgressDialog.dismiss();
        }
    }
}

第一次点击按钮会显示一个进度条,上面的数字处于变动当中,到达最大值后进度条会消失不见;再次点击按钮后,就会发现进度条上的数值和消失前相同,并且不再变化,而且进度条也不会消失。这是为什么呢?

Activity中有三个和对话框显示有关的方法:showDialog(),dismissDialog()和removeDialog()。其中showDialog()用于显示一个对话框;dismissDialog()使对话框消失,但仍然处于内存中,只是不显示而已,如果再次调用showDialog()方法,则缓存在内存中的对话框会重新显示,而不需要重新创建。removeDialog()使对话框消失,并从内存中将对话框清除,如果再次调用showDialog()来显示它,则在显示之前需要重新创建对话框。

在一个对话框的声明周期内,onCreateDialog()仅被调用一次,但onPrepareDialog()方法会每次被调用。比如,第一次调用 showDialog()方法显示某个对话框时,会先触发onCreateDialog()的执行,然后再触发onPrepareDialog()方法;如果将某个对话框 removeDialog()后再showDialog(),也会先触发onCreateDialog(),接着触发onPrepareDialog()方法;如果某个对话框是被dismiss()掉的,再调用 showDialog()方法来显示它时就不会触发onCreateDialog()方法的执行,只会触发onPrepareDialog()方法。

这是因为第一次调用showDialog()时,Android从你的Activity中调用onCreateDialog()方法,得到返回的Dialog对象。把当前Activity设置为该对话框的所有者,从而把对话框挂靠到Activity上,让Activity自动管理该对话框的状态。这样,下次调用showDialog()时就不用重新创建Dialog对象,而是复用旧的。

所以,解决再次打开ProgressDialog时进度条不变化的最好方法就是将mProgressDialog.dismiss()改成removeDialog(COPY_CONTACTS)。

注意:如果你决定在onCreateDialog()方法之外创建一个对话框,它将不会被附着到活动上。不过,你可以通过setOwnerActivity()把它附着到一个Activity上。

Comments