1

我创建了一个简单的应用程序。

当用户触摸“开始..”按钮时,按钮标签上会显示“加载动画”。

我在我的 PC 上创建了应用程序(例如桌面应用程序),效果很好。

Android的应用程序代码:

package com.example.threaddot;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends Activity {

    SeekBar pointSpeed, numPoint;
    Button startButton, detailsButton;
    Thread count;
    boolean started = false;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // my vars
        startButton = (Button) findViewById(R.id.button_start);
        detailsButton = (Button) findViewById(R.id.button_details);
        numPoint = (SeekBar) findViewById(R.id.seekBar_numpoints);
        pointSpeed = (SeekBar) findViewById(R.id.PointSpeedSeekBar);

        count = new Thread(new Runnable() {

            @Override
            public void run() {
                setDots();
            }
        });

        startButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                count.start();
            }
        });

        detailsButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                showAlert("Info",
                        String.format("Current: %s, %d points, and shown per %d m/s.", !started ? "working" : "suspend", 
                                numPoint.getProgress(), pointSpeed.getProgress()));             
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

    public void setDots() {
        int counter = 0, numPoints = numPoint.getProgress();
        while(true) {
            if(counter++ < 10) {
                startButton.setText(startButton.getText() + ".  ");
            }

            else {
                counter = 0;
            }

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }           
    }

    void showAlert(String title, String msg) {
        AlertDialog alertDialog;
        alertDialog = new AlertDialog.Builder(this).create();
        alertDialog.setTitle(title);
        alertDialog.setMessage(msg);
        alertDialog.show();
    }
}

当我按下“开始..”按钮时,它被粉碎了。

换句话说,

startButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            count.start();
        }
    });

使应用程序崩溃。为什么?

日志猫:

01-18 20:07:43.453: W/dalvikvm(29186): threadid=10: thread exiting with uncaught exception (group=0x40018578)
01-18 20:07:43.500: E/AndroidRuntime(29186): FATAL EXCEPTION: Thread-11
01-18 20:07:43.500: E/AndroidRuntime(29186): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.view.ViewRoot.checkThread(ViewRoot.java:3055)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.view.ViewRoot.invalidateChild(ViewRoot.java:649)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:675)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.view.View.invalidate(View.java:5279)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.widget.TextView.checkForRelayout(TextView.java:5782)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.widget.TextView.setText(TextView.java:2824)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.widget.TextView.setText(TextView.java:2685)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at android.widget.TextView.setText(TextView.java:2654)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at com.example.threaddot.MainActivity.setDots(MainActivity.java:66)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at com.example.threaddot.MainActivity$1.run(MainActivity.java:32)
01-18 20:07:43.500: E/AndroidRuntime(29186):    at java.lang.Thread.run(Thread.java:1019)
01-18 20:10:49.632: W/ActivityThread(29426): Application com.example.threaddot is waiting for the debugger on port 8100...
01-18 20:10:49.648: I/System.out(29426): Sending WAIT chunk
01-18 20:10:49.859: I/System.out(29426): Debugger has connected
01-18 20:10:49.859: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:50.054: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:50.257: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:50.460: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:50.664: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:50.867: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:51.062: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:51.265: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:51.468: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:51.671: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:51.875: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:52.085: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:52.281: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:52.500: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:52.695: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:52.898: I/System.out(29426): waiting for debugger to settle...
01-18 20:10:53.101: I/System.out(29426): debugger has settled (1476)
01-18 20:12:48.117: W/dalvikvm(29426): threadid=10: thread exiting with uncaught exception (group=0x40018578)
01-18 20:12:48.195: E/AndroidRuntime(29426): FATAL EXCEPTION: Thread-10
01-18 20:12:48.195: E/AndroidRuntime(29426): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.view.ViewRoot.checkThread(ViewRoot.java:3055)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.view.ViewRoot.invalidateChild(ViewRoot.java:649)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:675)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.view.View.invalidate(View.java:5279)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.widget.TextView.checkForRelayout(TextView.java:5782)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.widget.TextView.setText(TextView.java:2824)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.widget.TextView.setText(TextView.java:2685)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at android.widget.TextView.setText(TextView.java:2654)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at com.example.threaddot.MainActivity.setDots(MainActivity.java:66)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at com.example.threaddot.MainActivity$1.run(MainActivity.java:32)
01-18 20:12:48.195: E/AndroidRuntime(29426):    at java.lang.Thread.run(Thread.java:1019)
01-18 20:14:52.031: D/AndroidRuntime(29761): Shutting down VM
01-18 20:14:52.031: W/dalvikvm(29761): threadid=1: thread exiting with uncaught exception (group=0x40018578)
01-18 20:14:52.062: E/AndroidRuntime(29761): FATAL EXCEPTION: main
01-18 20:14:52.062: E/AndroidRuntime(29761): java.lang.IllegalThreadStateException: Thread already started.
01-18 20:14:52.062: E/AndroidRuntime(29761):    at java.lang.Thread.start(Thread.java:1227)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at com.example.threaddot.MainActivity$2.onClick(MainActivity.java:40)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.view.View.performClick(View.java:2485)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.view.View$PerformClick.run(View.java:9080)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.os.Handler.handleCallback(Handler.java:587)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.os.Handler.dispatchMessage(Handler.java:92)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.os.Looper.loop(Looper.java:130)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at android.app.ActivityThread.main(ActivityThread.java:3687)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at java.lang.reflect.Method.invokeNative(Native Method)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at java.lang.reflect.Method.invoke(Method.java:507)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
01-18 20:14:52.062: E/AndroidRuntime(29761):    at dalvik.system.NativeStart.main(Native Method)
01-18 20:15:35.492: W/ActivityThread(29953): Application com.example.threaddot is waiting for the debugger on port 8100...
01-18 20:15:35.734: I/System.out(29953): Sending WAIT chunk
01-18 20:15:35.937: I/System.out(29953): Debugger has connected
01-18 20:15:35.937: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:36.140: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:36.343: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:36.546: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:36.742: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:36.945: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:37.148: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:37.359: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:37.554: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:37.757: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:37.960: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:38.164: I/System.out(29953): waiting for debugger to settle...
01-18 20:15:38.367: I/System.out(29953): debugger has settled (1495)
01-18 20:16:13.609: W/dalvikvm(29953): threadid=9: thread exiting with uncaught exception (group=0x40018578)
01-18 20:16:13.679: E/AndroidRuntime(29953): FATAL EXCEPTION: Thread-10
01-18 20:16:13.679: E/AndroidRuntime(29953): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.view.ViewRoot.checkThread(ViewRoot.java:3055)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.view.ViewRoot.invalidateChild(ViewRoot.java:649)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:675)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.view.View.invalidate(View.java:5279)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.widget.TextView.checkForRelayout(TextView.java:5782)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.widget.TextView.setText(TextView.java:2824)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.widget.TextView.setText(TextView.java:2685)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at android.widget.TextView.setText(TextView.java:2654)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at com.example.threaddot.MainActivity.setDots(MainActivity.java:66)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at com.example.threaddot.MainActivity$1.run(MainActivity.java:32)
01-18 20:16:13.679: E/AndroidRuntime(29953):    at java.lang.Thread.run(Thread.java:1019)
01-18 20:21:29.492: D/AndroidRuntime(30489): Shutting down VM
01-18 20:21:29.492: W/dalvikvm(30489): threadid=1: thread exiting with uncaught exception (group=0x40018578)
01-18 20:21:29.632: E/AndroidRuntime(30489): FATAL EXCEPTION: main
01-18 20:21:29.632: E/AndroidRuntime(30489): java.lang.IllegalThreadStateException: Thread already started.
01-18 20:21:29.632: E/AndroidRuntime(30489):    at java.lang.Thread.start(Thread.java:1227)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at com.example.threaddot.MainActivity$2.onClick(MainActivity.java:40)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.view.View.performClick(View.java:2485)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.view.View$PerformClick.run(View.java:9080)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.os.Handler.handleCallback(Handler.java:587)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.os.Handler.dispatchMessage(Handler.java:92)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.os.Looper.loop(Looper.java:130)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at android.app.ActivityThread.main(ActivityThread.java:3687)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at java.lang.reflect.Method.invokeNative(Native Method)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at java.lang.reflect.Method.invoke(Method.java:507)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
01-18 20:21:29.632: E/AndroidRuntime(30489):    at dalvik.system.NativeStart.main(Native Method)
4

2 回答 2

2

如日志:

CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触其视图。

意味着您将需要runOnUiThread()以更新以从 Thread 访问 Ui 元素:

   MainActivity.this.runOnUiThread(new Runnable() {

        @Override
        public void run() {
            // update textview here

        }
    });

将您的 setDots() 方法更改为:

public void setDots() {
        int counter = 0, numPoints =0;
                MainActivity.this.runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                    numPoints = numPoint.getProgress();
                 }
               });
          while(true) {
            if(counter++ < 10) {
                MainActivity.this.runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                     startButton.setText(startButton.getText() + ".  ");
                 }
               });
            }

            else {
                counter = 0;
            }

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }           
    }
于 2013-01-18T18:25:00.967 回答
0

除了“主”线程之外​​,您不能修改任何线程上处理 UI 的任何内容。您应该考虑使用能够定期报告信息并在完成后更新的 AsyncTask。“快速而肮脏”的方式是创建一个处理程序(它必须在 UI 线程上创建,因此初始化为您的活动或 oncreate、onXXX 等的实例变量)并在您需要时将其发布到 UI 线程更新。

这必须在 UI 线程上创建。

Handler handler = new Handler();

这个处理程序可以传递给你的后台线程并像这样发布更新:

handler.post(new Runnable()
{
    public void run() {
    //UI UPDATES HERE.
    }
});

你真的应该通读 android 文档,它很详尽,并且非常详细地涵盖了所有这些。

于 2013-01-18T18:34:10.230 回答