在线程android中使用处理程序

时间:2015-08-10 16:11:13

标签: android multithreading

我正在尝试在线程中运行一个处理程序,但我得到了错误"无法在未调用Looper.prepare()"的线程内创建处理程序。我花了几个小时寻找一个解决方案,但无法找到一个,所以我决定发布这个。我试过打电话" Looper.prepare(); "它修复了force close问题,但是停止了处理程序中的代码工作。

    public void ten(View view) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            private Vibrator mVibrator;
            private Runnable runnable;
            private Handler handler;

            public void run() {
                mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                mVibrator.vibrate(1000 * 10);// 10 sec sprint

                // HANDLER
                handler = new Handler();
                runnable = new Runnable() {
                    public void run() {
                        // calculate result1
                        TextView theFact = (TextView) findViewById(R.id.txtCurrentSpeed);
                        String shareFact = theFact.getText().toString();
                        TextView theFact1 = (TextView) findViewById(R.id.result1);
                        theFact1.setText(String.valueOf(shareFact));
                        // calculate result1
                    }
                };
                handler.postDelayed(runnable, 3000);
                // HANDLER END //
            }
        }, 5000, 60 * 1000 * 3);// 3 minute break (+5s first run delay)
    }
}



08-10 21:37:59.187: E/AndroidRuntime(26129): FATAL EXCEPTION: Timer-0
08-10 21:37:59.187: E/AndroidRuntime(26129): Process: com.example.speedometer, PID: 26129
08-10 21:37:59.187: E/AndroidRuntime(26129): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
08-10 21:37:59.187: E/AndroidRuntime(26129):    at android.os.Handler.<init>(Handler.java:200)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at android.os.Handler.<init>(Handler.java:114)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at com.example.speedometer.MainActivity$2.run(MainActivity.java:141)
08-10 21:37:59.187: E/AndroidRuntime(26129):    at java.util.Timer$TimerImpl.run(Timer.java:284)

我用Thread替换了Handler,线程内部的代码工作正常,但强制关闭会产生以下异常:

08-10 21:57:35.477: E/AndroidRuntime(31261): FATAL EXCEPTION: Thread-4399
08-10 21:57:35.477: E/AndroidRuntime(31261): Process: com.example.speedometer, PID: 31261
08-10 21:57:35.477: E/AndroidRuntime(31261): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7147)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:998)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:361)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.view.View.requestLayout(View.java:18491)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.checkForRelayout(TextView.java:8060)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4836)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4660)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at android.widget.TextView.setText(TextView.java:4635)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at com.example.speedometer.MainActivity$2$1.run(MainActivity.java:154)
08-10 21:57:35.477: E/AndroidRuntime(31261):    at java.lang.Thread.run(Thread.java:818)

3 个答案:

答案 0 :(得分:1)

android的Main / UI线程默认有一个looper。 因此,如果您在Activity / Fragment / View中创建一个Handler实例,那么在UI线程上运行该方法,它将使用默认的Looper并且永远不会抛出异常。

因此,最好在Main / UI线程上创建Handler来更新UI。

说过最简单的解决方案是将Default Looper作为参数传递,如此

 handler = new Handler(Looper.getMainLooper());

当您尝试更新用户界面时,这将解决您的问题。

答案 1 :(得分:0)

我已经看到你想要在发布到处理程序的runnable中更改UI。您应该注意两点:

  • 所有UI操作都应该在UI /主线程中完成而不是后台线程。

  • 处理程序会依赖于创建它们的主题。

因此,您应该在Main / UI线程中创建处理程序对象,然后在任何地方调用它的方法postDelayed。即在调用time.schedule()作为final Handler handler之前实例化您的处理程序对象,然后在该计时器任务中使用它。

注意:为了定期调用例程,我们讨论了一种更简单,更轻松的方法here

编辑#1

public void ten(View view) {
        // CHANGE #1
        final Handler handler = new Handler();

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            private Vibrator mVibrator;

            public void run() {
                mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
                mVibrator.vibrate(1000 * 10);// 10 sec sprint

                // HANDLER
                // CHANGE #2 (Removed this line)
                Runnable runnable = new Runnable() {
                    public void run() {
                        // calculate result1
                        TextView theFact = (TextView) findViewById(R.id.txtCurrentSpeed);
                        String shareFact = theFact.getText().toString();
                        TextView theFact1 = (TextView) findViewById(R.id.result1);
                        theFact1.setText(String.valueOf(shareFact));
                        // calculate result1
                    }
                };
                handler.postDelayed(runnable, 3000);
                // HANDLER END //
            }
        }, 5000, 60 * 1000 * 3);// 3 minute break (+5s first run delay)
    }

答案 2 :(得分:0)

如果您每3秒尝试执行一次任务,为什么不使用AlarmManager,而不是使用TimerTask。然后你将避免一起使用一个处理程序。