为什么我的Handler不能使用UI线程

时间:2018-01-27 15:59:55

标签: android

我试图理解Handler如何与Looper配对,但我有一些问题。我需要在后台线程中执行一些长操作,然后在textView中发送一些结果 按下按钮后出现以下错误:

  

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

public class MainActivity extends AppCompatActivity {
Button mButton;
TextView mTextView;
ConsumeThread mConsumeThread;

class ConsumeThread extends Thread{
    public Handler mHandler;

    @Override
    public void run() {
        Looper.prepare();
        mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                int arg = msg.what;
                someLongOperation(arg);
            }
        };
        Looper.loop();
    }

    private void someLongOperation(int arg){
        // do some long operation
        arg += 1000;
        mTextView.setText("Operation's code is " +arg); // fatal exception
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mTextView = (TextView)findViewById(R.id.txt_view);
    mButton = (Button) findViewById(R.id.button);

    mConsumeThread = new ConsumeThread();
    mConsumeThread.start();

    mButton.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v) {
            if(mConsumeThread.mHandler != null){
                Message msg = mConsumeThread.mHandler.obtainMessage(10);
                mConsumeThread.mHandler.sendMessage(msg);
            }
        }
    });
}

4 个答案:

答案 0 :(得分:1)

获取主线程Handler您已获得Handler,如下所示。 因为: -

  

每个Handler实例都与一个线程和该线程的消息队列相关联。创建新的Handler时,它将绑定到创建它的线程的线程/消息队列

因此,您需要获得与Handler相关联的MainThread。为此,您可以使用以下之一: -

  1. 使用上下文

    Handler mainHandler = new Handler(getMainLooper()){
    @Override
    public void handleMessage(Message msg) {
    }
    };
    
  2. 或直接使用Looper即使没有Context

    Handler mainHandler = new Handler(Looper.getMainLooper()){
    @Override
    public void handleMessage(Message msg) {
    }
    };
    

    我认为你正在做一些长期运行的任务。如果你选择AsyncTask,那就更好了。

答案 1 :(得分:1)

private void someLongOperation(int arg){
    // do some long operation
    arg =+ 1000;
    mTextView.setText("Operation's code is " +arg); // fatal exception
}

//看到这里,你是工作线程,所以你不能有多余的UI工具包或者异常,所以如果你想在工作线程中做一些与ui相关的任务,请使用runOnUi,见这里

runOnUiThread(new Runnable() {
                @Override
                public void run() {

                   textview.setText("");


                }
            })

答案 2 :(得分:0)

您无法从其他线程更新UI。您必须将更新UI的代码移动到UIThread。

尝试使用:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
       //TextView Update Code
   }
});
  

提示:尝试减少放在其中的代码行数,因为没有使用其他线程的目的。

答案 3 :(得分:0)

只有创建视图层次结构的原始线程才能触及其视图

你必须在主线程上做ui相关的工作...... 所以你可以这样做......

    private void someLongOperation(int arg){
            // do some long operation
            arg =+ 1000;
            MainActivity.this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
            mTextView.setText("Operation's code is " +arg); // fatal exception  
             } 
          });

        }