将活动重新回到最前面之后,TextView停止更新 [英] TextView stops updating after bringing activity back to the front

查看:154
本文介绍了将活动重新回到最前面之后,TextView停止更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试找出线程问题,并遇到以下问题:如果将应用发送到后台,然后又将其还原,则TextView会停止更新.

I'm trying to figure out threading and have this issue where a TextView stops being updated if the app is sent to the back, and then restored.

在将应用重新带回前端后,如何确保TextView继续更新?

How can I ensure that the TextView continues to be updated after the app is brought back to the front?

或者...

重新启动活动后,如何将TextView重新连接到可运行线程中的处理程序?

How do I reconnect the TextView to the handler in my run-nable thread after restarting the activity?

有一个进度条,它工作得很好,所以我有些困惑.我很乐意提供一些建议,因为我认为我可能会犯一个简单的错误.

There is a Progress Bar which works just fine, so I'm somewhat confused. I'd appreciate some advice as I think I may be making a simple mistake.

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();
    }
}

推荐答案

Activity在后台启动并恢复时,会经历整个生命周期.这意味着将创建一个新实例,并再次调用Activity.onCreate.有关详细信息,请参见图此处.需要注意的重要一点是,活动会经历此生命周期,并且在更改方向后也会被破坏并重新创建.因此,这是您必须了解并与之合作的事情.

When an Activity is backgrounded and then resumed, it goes through the whole lifecycle. This means a new instance is created, and Activity.onCreate is called again. See the diagram here for details. An important thing to note is that Activities go through this lifecycle and are destroyed and re-created also when the orientation is changed. So it's something you kind of have to be aware of and work with or around.

在后台激活并恢复活动时更新ProgressBar的原因是,您在Activity中有一个静态引用,该引用是在每次调用onCreate时设置的.此静态引用在活动"的第一个实例和恢复后创建的第二个实例之间共享.一旦启动线程,它将仅更新该引用指向的任何ProgressBar,因此您会感觉到正在更新相同的ProgressBar.

The reason that your ProgressBar is updated when your Activity is backgrounded and resumed is that you've got a static reference in your Activity that is set upon each call to onCreate. This static reference is shared between the first instance of your Activity and the second instance that is created after you resume. Once you start your thread, it will just update whatever ProgressBar this reference points to, so you get the impression that the same ProgressBar is being updated.

实际上,它不是同一对象,而是不同的实例.这就是为什么您的TextView中的文本未更新的原因,因为线程正在更新TextView的一个较旧的实例,而不是屏幕上的那个.您可以在调试器中确认所有这些内容,或更简单地仅通过打印对象的哈希码来确认所有这些内容.尝试将其放入while循环中:

In fact, it's not the same object, it's a different instance. That's why the text in your TextView is not updated, because the thread is updating an older instance of TextView, not the one on the screen. You can confirm all this in the debugger, or more simply just by printing out the hash codes of the objects. Try putting this inside your while loop:

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

请注意,由于线程正在更新新的ProgressBar,所以ProgressBar的哈希码已更改,但是正在更新的TextView的哈希码却没有.

Notice that the ProgressBar's hash code changes, because the thread is updating a new ProgressBar, but the hash code of the TextView that is being updated does not.

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还是静态的.这不是在生命周期更改之间保持状态的方式,因为它可能导致内存泄漏,如果您不小心的话,坦白说,它也会使您感到困惑,如您从上方看到的那样.相反,您应该重写其他生命周期方法之一,即onPause或onStop,以保存ProgressBar和TextView的状态,并可能杀死正在更新它的线程.然后,在onCreate中,您需要将该状态从Bundle中拉出,并将ProgressBar和TextView恢复为用户离开时的状态,并且还可能重新启动线程.您可能想阅读的方法称为

Now, the answer is not to make the TextView also static. This isn't how you should maintain state between the Activity lifecycle changes, because it can lead to memory leaks if you're not careful, and frankly it's also confusing, as you can see from above. Instead, you should override one of the other lifecycle methods, onPause or onStop, to save the state of the ProgressBar and TextView, and probably kill the thread that is updating it. Then, in onCreate, you'll need to pull that state out of the Bundle and restore the ProgressBar and TextView to the state they were when the user navigated away, and also probably restart the thread. The method you probably want to read up on is called Activity.onSaveInstanceState. There are other options too, but this is something that's covered on StackOverflow in a lot of questions and is described well in the Android SDK docs.

我希望能对您有所帮助!让我知道是否不清楚!

I hope that helps! Let me know if this isn't clear!

这篇关于将活动重新回到最前面之后,TextView停止更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆