Android AsyncTask ProgressDialog轮换配置不同

标签 android android-asynctask progressdialog screen-rotation

我已经设法在屏幕旋转期间使用带有不确定进度条的 Asynctask。 Asynctask 只启动一次,进度条按照我的意愿在旋转时恢复。

我有不同的纵向布局和布局方向。布局包括一个按钮和一个 TextView 。 layout-land 中 textview 的大小和文本颜色不同。方向是横向。

问题是当我在 asynctask 运行时旋转屏幕时,它无法在 onPostExecute 方法中更新 textview。当我旋转时,它会使用 layout-land 文件重新创建 Activity 。但为什么我不能更新我的 Textview?

layout\activity_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:text="Start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startClicked"
        />
    <TextView
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />

</LinearLayout>

layout-land\activity_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="horizontal">

    <Button 
        android:text="Start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startClicked"
        />
    <TextView
        android:textSize="36dp"
        android:textColor="#ff0000"
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />

</LinearLayout>

MainActivity.java:

package com.example.asynctaskconfig;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

    public class MainActivity extends Activity {
        static String data;
        static ProgressDialog pd;
        MyAsyncTask task;
        TextView tv;

        @Override
        public void onCreate(Bundle icicle) {
            super.onCreate(icicle);
            setContentView(R.layout.activity_main);

            tv = (TextView) findViewById(R.id.hello);

            if (getLastNonConfigurationInstance() != null) {
                task = (MyAsyncTask) getLastNonConfigurationInstance();
                if (task != null) {
                    if (!(task.getStatus().equals(AsyncTask.Status.FINISHED))) {
                        showProgressDialog();
                    }
                }
            }
        }

        @Override
        public Object onRetainNonConfigurationInstance() {
            if (pd != null)
                pd.dismiss();
            if (task != null)
                return (task);
            return super.onRetainNonConfigurationInstance();
        }


        private void showProgressDialog() {
            if (pd == null || !pd.isShowing()) {
                pd = new ProgressDialog(MainActivity.this);
                pd.setIndeterminate(true);
                pd.setTitle("DOING..");
                pd.show();
            }
        }

        private void dismissProgressDialog() {
            if (pd != null && pd.isShowing())
                pd.dismiss();
        }

        public class MyAsyncTask extends AsyncTask<String, Void, Boolean> {
            @Override
            protected void onPreExecute() {
                showProgressDialog();
            }

            @Override
            protected Boolean doInBackground(String... args) {
                try {
                    Thread.sleep(5000);
                    data = "result from ws";
                } catch (Exception e) {
                    return true;
                }
                return true;
            }

            protected void onPostExecute(Boolean result) {
                if (result) {
                    dismissProgressDialog();
                    updateUI();
                }
            }
        }

        private void updateUI() {
            tv.setText(data == null ? "null" : data);
        }

        public void startClicked(View target) {
            task = new MyAsyncTask();
            task.execute("start");
        }
    }

最佳答案

我的做法如下:

1-android:freezesText="true" 添加到我所有的 TextView。这使 TextView 能够在配置更改时保存它们的状态。

2- 使您的 AsyncTask 成为静态内部类。

3- 修改AsyncTask 以保留对它所在的Activity 的引用。因此AsyncTask 可以通过此引用访问Activity 的UI 小部件。

4- 在这里,在屏幕旋转期间保持有效的 Activity 引用很重要。因此,重写 onDestroy 方法并将 Activity 与 AsyncTask 解除绑定(bind)。因此,任务不会保留旧的(已死亡的) Activity 。

5-onRetainNonConfigurationInstance 中,如果任务仍在运行,则使用当前 Activity 更新其 Activity 引用,以便它成功绑定(bind)到新 Activity 。

6- 最后,在onPostExecuteMethod中,通过 Activity 引用访问 Activity 的UI元素。

完整的工作解决方案:

layout\activity_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:text="Start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startClicked"
        />
    <TextView
        android:freezesText="true"
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
</LinearLayout>

layout-land\activity_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="horizontal">

    <Button 
        android:text="Start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="startClicked"
        />
    <TextView
        android:freezesText="true"
        android:textSize="36dp"
        android:textColor="#ff0000"
        android:id="@+id/hello"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
</LinearLayout>

MainActivity.java:

package com.example.asynctaskconfig;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends Activity {
    static ProgressDialog pd;
    MyAsyncTask task;
    TextView tv;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_main);

        tv = (TextView) findViewById(R.id.hello);

        if (getLastNonConfigurationInstance() != null) {
            task = (MyAsyncTask) getLastNonConfigurationInstance();
            if (task != null) {
                task.activity = this;
                if (!(task.getStatus().equals(AsyncTask.Status.FINISHED))) {
                    showProgressDialog();
                }
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (task != null) {
            task.activity = null;
        }
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        if (pd != null)
            pd.dismiss();
        if (task != null)
            return (task);
        return super.onRetainNonConfigurationInstance();
    }

    private void showProgressDialog() {
        if (pd == null || !pd.isShowing()) {
            pd = new ProgressDialog(MainActivity.this);
            pd.setIndeterminate(true);
            pd.setTitle("DOING..");
            pd.show();
        }
    }

    private void dismissProgressDialog() {
        if (pd != null && pd.isShowing())
            pd.dismiss();
    }

    static class MyAsyncTask extends AsyncTask<String, Void, String> {
        MainActivity activity;

        public MyAsyncTask(MainActivity activity) {
            this.activity = activity;
        }

        @Override
        protected void onPreExecute() {
            activity.showProgressDialog();
        }
        @Override
        protected String doInBackground(String... args) {
            try {
                Thread.sleep(8000);
                return "data from ws";
            } catch (Exception e) {
                return "exception";
            }
        }

        protected void onPostExecute(String result) {
            activity.dismissProgressDialog();
            activity.tv.setText(result == null ? "null" : result);
        }
    }

    public void startClicked(View target) {
        task = new MyAsyncTask(this);
        task.execute("start");
    }
}

关于Android AsyncTask ProgressDialog轮换配置不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12390657/

相关文章:

java - 从 Android 中的 Asynctask 返回 boolean 值

android - 异步任务错误 : Only the original thread that created a view hierarchy can touch its views

android - 如何设计像在android中修复的进度条这样的 View ?

java - aChartEngine - 如何屏蔽条形图?

android - 在 ViewModel 类中使用新线程

Android:更改进度对话框文本

android - 调用显示 ProgressDialog 的新 Activity 后隐藏键盘

java - 产品风格和来源层次结构

java - 不显示按钮的背景

Android Volley SSL 错误