1

画面の回転中に進行状況バーが不確定な非同期タスクを使用することができました。非同期タスクは1回だけ開始され、プログレスバーは希望どおりに回転すると復元されます。

縦向きとレイアウトの向きに異なるレイアウトがあります。レイアウトには、ボタンとテキストビューが含まれます。レイアウトランドのテキストビューのサイズとテキストの色が異なります。そして、オリエンテーションは風景です。

問題は、asynctaskの実行中に画面を回転すると、onPostExecuteメソッドでテキストビューを更新できないことです。回転すると、layout-landファイルでアクティビティが再作成されます。しかし、なぜ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");
        }
    }
4

4 に答える 4

1

私がしたことは次のとおりです。

1-android:freezesText="true"すべてのTextViewに追加します。これにより、TextViewは構成の変更時に状態を保存できます。

2 -AsyncTaskをaにしますstatic inner class.

3-変更して、存在するアクティビティへの参照を保持します。したがって、 AsyncTaskAsyncTaskは、この参照を介してアクティビティのUIウィジェットにアクセスできます。

4-ここでは、画面の回転中に有効なアクティビティ参照を保持することが重要です。したがって、onDestroyメソッドをオーバーライドし、AsyncTaskからアクティビティのバインドを解除します。したがって、タスクは古い(死んだ)アクティビティを保持しません。

5-で、タスクがまだ実行中の場合はonRetainNonConfigurationInstance、そのアクティビティ参照を現在のアクティビティで更新して、新しいアクティビティに正常に関連付けられるようにします。

6-最後に、でonPostExecuteMethod、アクティビティ参照を介してアクティビティの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");
    }
}
于 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が画面に表示されなくなったことです。ローテーションにより、Androidは古いアクティビティを破棄し、新しいアクティビティを構築しました。これには、xmlファイル内のすべてのビューが含まれます。したがって、TextViewの「tv」はまだ古いアクティビティの一部であり、変更しても何も起こりません。

必要な動作を取得するための最も簡単な方法は、テキストビューをもう一度探すことです。つまり、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 に答える