1

在屏幕旋转期间,我设法使用了带有不确定进度条的 Asynctask。Asynctask 只启动一次,进度条在旋转时恢复,就像我想要的那样。

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

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

布局\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>

布局土地\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");
        }
    }
4

4 回答 4

1

我所做的如下:

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

2-使您的 AsyncTask 成为static inner class.

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

4-在这里,重要的是在屏幕旋转期间保持有效的活动参考。因此,重写onDestroy方法并从 AsyncTask 中取消绑定 Activity。因此,任务不会保留旧的(死的)活动。

5-onRetainNonConfigurationInstance,如果任务仍在运行,用当前活动更新其活动引用,因此它成功地绑定到新活动。

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

完整的工作解决方案:

布局\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>

布局土地\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");
    }
}
于 2012-09-12T17:27:23.840 回答
0

试试这个:

private void updateUI() {
    final TextView tv = (TextView) findViewById(R.id.hello);
    tv.setText(data == null ? "null" : data);
}

如果失败,是否可能是时间问题?也就是说,会不会是方​​向变化时完成的任务?为了安全起见,如果任务完成,您可以onCreate通过添加调用来修改您的方法:updateUI()

 @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();
                } else
                    updateUI();
            }
        }
    }
于 2012-09-12T14:47:46.013 回答
0

您的问题本质上是您尝试更改的 TextView 不再是屏幕上可见的 TextView 。轮换导致 Android 放弃旧的 Activity 并构建一个新的 - 完成 xml 文件中的所有视图。因此,您的 TextView 'tv' 仍然是旧活动的一部分,更改将无济于事。

现在获得您想要的行为的最简单方法是再次查找 textview,即在您的 updateUI 方法中再次使用“findViewById”,您应该没问题!

于 2012-09-12T14:49:29.003 回答
0

在这种情况下,您可能不希望在方向更改时重新创建活动。您可以通过将其添加到清单中的活动来处理活动中的方向更改:

android:configChanges="keyboardHidden|orientation"

然后覆盖 onConfigurationChanged:

@Override
public void onConfigurationChanged(Configuration newConfig) {
  super.onConfigurationChanged(newConfig);
  setContentView(R.layout.activity_main);
  tv = (TextView) findViewById(R.id.hello);
}
于 2012-09-12T14:50:42.967 回答