【问题标题】:Didn't update UI when pause and resume thread暂停和恢复线程时未更新 UI
【发布时间】:2012-07-19 11:33:36
【问题描述】:

我现在正在做一个 android 项目。 我的线程有问题。我想在按下主页按钮时暂停线程,并在返回应用程序时恢复线程。

这是我的代码:

Handler handler = new Handler() 
{
    @Override
    public void handleMessage(Message msg) 
    {
        int tempWaktu = (Integer) msg.obj;

        if(!status){
            if(tempWaktu < 10 ) textSec.setText("0"+tempWaktu);
            else textSec.setText(""+tempWaktu);
        }

        if(tempWaktu==0){
            stopYourActivity();
        }
    }
}; //handler

@Override
public void onStart() 
{
    super.onStart();

    timer = new Thread(new Runnable() {
        public void run() {
        try 
        {
            while(jalan){
                if(running){
                    Thread.sleep(1000);
                    waktu--;
                    Message msg = handler.obtainMessage(1, waktu);
                    handler.sendMessage(msg);
                    if(waktu==0){
                        running = false;
                    }
                }
            }
        } 
        catch (Throwable t){

        }
    }//run
    });//background
    timer.start();
}//onStart


@Override
public void onPause(){
    synchronized (timer) {
        try {
            timer.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    pause = true;
}

@Override
public void onResume(){
    super.onResume();
    if(pause){
        synchronized (timer) {
            timer.notify(); textSec.postInvalidate();
            pause = false;
        } 
    }
}

当我按下主页按钮时,线程不会停止,当我返回应用程序时,用户界面会冻结。我不明白为什么。

我需要的是当我按下主页按钮时线程暂停,当我返回线程运行并且 UI 没有冻结时。

感谢您为帮助我而编写的任何代码。非常感谢。


更新

我已将timer.wait() 放入run() 中,如下所示:

@Override
public void onStart() 
{
    super.onStart();

    if(!pause){
        timer = new Thread(new Runnable() {
            public void run() {
            try 
            {
                while(jalan){
                    if(running){
                        Thread.sleep(1000);
                        waktu--;
                        Message msg = handler.obtainMessage(1, waktu);
                        handler.sendMessage(msg);
                        Log.v("Timer Thread", "Thread Berjalan "+waktu);
                        if(waktu==0){
                            Log.v("Thread Timer", "Waktu Berhenti");
                            running = false;
                        }
                        if(pause){
                            synchronized (timer) {
                                timer.wait();
                            }
                        }
                    }
                }
            } 
            catch (Throwable t){    
            }
        }//run
        });//background
        timer.start();
    }

}//onStart

timer.notify() 就像上面一样在onResume() 中,当我按下主页时,它会强制关闭。日志是这样写的:

07-19 10:27:41.173: E/AndroidRuntime(2280): FATAL EXCEPTION: main
07-19 10:27:41.173: E/AndroidRuntime(2280): android.app.SuperNotCalledException: Activity {com.konsep.baby.scratch/com.konsep.baby.scratch.BabyScratchChallenge} did not call through to super.onPause()
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.Activity.performPause(Activity.java:3854)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1191)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2341)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread.performPauseActivity(ActivityThread.java:2311)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:2291)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread.access$1700(ActivityThread.java:117)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:938)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.os.Looper.loop(Looper.java:123)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at android.app.ActivityThread.main(ActivityThread.java:3683)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at java.lang.reflect.Method.invokeNative(Native Method)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at java.lang.reflect.Method.invoke(Method.java:507)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-19 10:27:41.173: E/AndroidRuntime(2280):     at dalvik.system.NativeStart.main(Native Method)

我的代码有什么问题?

【问题讨论】:

    标签: android multithreading


    【解决方案1】:

    第一个问题是Activity 的生命周期实际上是如何工作的。当您进入主屏幕时,您当前的Activity 会一直进入停止状态(即调用onStop())。因此,当您返回应用程序时,您将收到onStart(),然后是onResume()。现在,让我们根据这些信息检查代码中发生的情况:

    1. 首次启动时,会在onStart() 中创建一个新线程并启动。由于布尔标志,onResume() 什么都不做。
    2. 按下HOME键,onPause()被调用,在这个线程上调用wait()
    3. 返回应用程序,onStart() 被调用,现在计时器指向一个新线程,让旧线程悬空。
    4. onResume() 被调用,notify() 被发送到新的 Thread 实例。

    所以这里的问题是你wait()的线程和你notify()的线程不是同一个对象。

    第二个问题是wait() 的实际作用。来自 Java 文档(已添加重点):

    使调用线程等到另一个线程调用此对象的 notify() 或 notifyAll() 方法。该方法只能由拥有该对象监视器的线程调用;请参阅 notify() 了解线程如何成为监视器的所有者。

    Thread 上调用wait() 不会阻塞创建Thread 的线程,它会阻塞调用方法 的线程,在本例中是主线程。因此,您编写的应用程序在暂停期间成功阻塞了主线程并且无法解锁它,因此冻结。

    如果你想使用wait()notify() 来暂停你的后台线程,你需要确保wait() 在后台线程内被调用(即在它的run() 块内)

    【讨论】:

    • 我已将timer.wait() 放入run() 并涉及强制关闭。请看看我的更新。抱歉,我是线程新手。
    • 对不起,错误是我的错。你的回答是对的。非常感谢
    【解决方案2】:

    谷歌的培训页面已经说明了。Here

    当您的应用暂停时,它会“停止可能消耗 CPU 的动画或其他正在进行的操作。”

    【讨论】:

    • 我还是不明白,和我的问题有什么关系?
    猜你喜欢
    • 1970-01-01
    • 2016-03-24
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2015-02-21
    • 2012-07-13
    相关资源
    最近更新 更多