2

私はスレッド化を理解しようとしていますが、アプリがバックに送信されてから復元されると、TextViewの更新が停止するというこの問題が発生します。

アプリが前面に戻った後もTextViewが更新され続けるようにするにはどうすればよいですか?

または...

アクティビティを再開した後、実行可能スレッドのハンドラーにTextViewを再接続するにはどうすればよいですか?

うまく機能するプログレスバーがあるので、少し混乱しています。簡単な間違いをしているのではないかと思いますので、アドバイスをいただければ幸いです。

public class ThreadTestActivity extends Activity {
    private Handler handler;
    private static ProgressBar progress;
    private TextView tv;
    private int counter = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ThreadTest);
        handler = new Handler();
        progress = (ProgressBar) findViewById(R.id.progressBar1);
        tv = (TextView) findViewById(R.id.myText);
        Button but = (Button) findViewById(R.id.Button01);

        but.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {

                thread_fun();
            });}
    }
    private void thread_fun() {

        new Thread(new Runnable() {
            public void run() {

                try {
                    while (counter < 100) {
                        counter += 20;
                        Thread.sleep(2000);
                        // Update the progress bar and TextView (in 5 chunks of 20, 0 to 100) 
                        // This works perfectly it the app stays in front
                        handler.post(new Runnable() {
                            public void run() {
                            // but after sending to the back (esc) and bringing the activity back to the front
                                progress.setProgress(counter); //This progres bar maintains its value and updates correctly
                                tv.setText(String.valueOf(counter)); //This TextView reverts to its default text and does not update  
                            }
                        });
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}
4

1 に答える 1

1

アクティビティがバックグラウンド化されてから再開されると、ライフサイクル全体を通過します。これは、新しいインスタンスが作成され、Activity.onCreate が再度呼び出されることを意味します。詳しくはこちらの図をご覧ください。注意すべき重要なことは、アクティビティはこのライフサイクルを通過し、向きが変更されたときにも破棄され、再作成されるということです。ですから、それはあなたが知っていて、一緒に、または周りで働かなければならないものです.

アクティビティがバックグラウンド化されて再開されたときに ProgressBar が更新される理由は、onCreate の呼び出しごとに設定された静的参照がアクティビティにあるためです。この静的参照は、Activity の最初のインスタンスと再開後に作成される 2 番目のインスタンスの間で共有されます。スレッドを開始すると、この参照が指す ProgressBar が更新されるだけなので、同じ ProgressBar が更新されているような印象を受けます。

実際、それは同じオブジェクトではなく、別のインスタンスです。スレッドが画面上のものではなく、TextView の古いインスタンスを更新しているため、TextView 内のテキストが更新されないのはそのためです。これらすべてをデバッガーで確認するか、オブジェクトのハッシュ コードを出力するだけで簡単に確認できます。これをwhileループの中に入れてみてください:

Log.d("thread_fun", "threadid="+Thread.currentThread().getId()+
    ",progressbar="+progress.hashCode()+
    ",textview="+tv.hashCode());

スレッドが新しい ProgressBar を更新しているため、ProgressBar のハッシュ コードが変更されていますが、更新されている TextView のハッシュ コードは変更されていないことに注意してください。

D/thread_fun(28989): thread=3483,progress=1097438768,textview=1097437160
D/thread_fun(28989): thread=3483,progress=1097438768,textview=1097437160
D/thread_fun(28989): thread=3483,progress=1097528568,textview=1097437160
D/thread_fun(28989): thread=3483,progress=1097528568,textview=1097437160

ここでの答えは、TextView も静的にすることではありません。これは、Activity ライフサイクルの変更間で状態を維持する方法ではありません。注意しないとメモリ リークが発生する可能性があり、率直に言って、上記からわかるように混乱を招く可能性があるためです。代わりに、他のライフサイクル メソッド onPause または onStop のいずれかをオーバーライドして、ProgressBar と TextView の状態を保存し、おそらくそれを更新しているスレッドを強制終了する必要があります。次に、onCreate でその状態を Bundle から取り出し、ProgressBar と TextView をユーザーが移動したときの状態に復元し、おそらくスレッドを再起動する必要があります。おそらくあなたが読みたいと思うメソッドはActivity.onSaveInstanceStateと呼ばれます. 他のオプションもありますが、これは StackOverflow で多くの質問でカバーされており、Android SDK ドキュメントで詳しく説明されています。

それが役立つことを願っています!これが明確でない場合はお知らせください。

于 2012-09-15T03:38:37.390 に答える