Почему процесс handleMessage выполняется за основным потоком, когда дочерний поток прерывается? - PullRequest
0 голосов
/ 17 мая 2019

Недавно я создал пользовательский view с нитью сына. Чтобы манипулировать компонентами в MainActivity, я написал метод обратного вызова и использовал handler для обработки message, но когда я прервал поток сына, процесс handleMessage запустился после основного потока.

Я пытался использовать Thread.sleep, но мне не удалось. Понравилось:

try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

Первоначальный проект был слишком велик, поэтому я переписал похожую демонстрацию. MainActivity:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Handler handler;
    Message message;
    private Button bt_start,bt_finish;
    Thread thread1;
    private MyView myView;
    private TextView tv;
    //锁对象
    private final Object lock = new Object();

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

    public void initView() {
        bt_start = (Button)findViewById(R.id.bt_start);
        bt_finish = (Button)findViewById(R.id.bt_finish);
        myView = (MyView)findViewById(R.id.myView);
        tv = (TextView)findViewById(R.id.textView);

        bt_start.setOnClickListener(this);
        bt_finish.setOnClickListener(this);

        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case 1:
                        String s = (String)msg.obj;
                        tv.setText(s);
                        System.out.println("handling Meassage1 ");
                        break;
                    case 2:
                        System.out.println("handling Meassage2 ");
                        break;
                }
            }
        };
    }

    public void initAction() {
        myView.setCallbackListener(new MyView.CallbackListener() {
            @Override
            public void updateData(String testData) {
                message = new Message();
                message.what = 1;
                message.obj = testData;
                handler.sendMessage(message);
            }

            @Override
            public void clear() {
                tv.setText("");
            }
        });
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.bt_finish:
                if (thread1 != null)
                    thread1.interrupt();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("finish");
                myView.reset();
                break;
            case R.id.bt_start:
                thread1 = new Thread(myView.new InnerThread(lock));
                thread1.start();
                break;
        }
    }

}

Код MyView здесь:

public class MyView extends View {
    public Paint mPaint;
    private String testData;
    private CallbackListener callbackListener;

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        testData = "test";
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.YELLOW);
        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
    }
    //InnerThread
    public class InnerThread implements Runnable {
        private Object lock;

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

        public void test1(){
            System.out.println("before test1 wait");
            try {
                synchronized (lock) {
                    lock.wait();
                }
            } catch (InterruptedException ie){
                System.out.println("test1 is interrupted");
                Thread.currentThread().interrupt();
            }
            System.out.println("after test1 wait");
        }

        public void test2(){
            System.out.println("before test2 wait");
            try {
                synchronized (lock) {
                    lock.wait();
                }
            } catch (InterruptedException ie){
                System.out.println("test2 is interrupted");
                Thread.currentThread().interrupt();
            }
            System.out.println("after test2 wait");
        }
        public void mainFun() {
            test1();
            callbackListener.updateData(testData);
            test2();
        }

        public InnerThread(Object lock) {
            super();
            this.lock = lock;
        }
    }
    public interface CallbackListener {
        void updateData(String testData);
        void clear();
    }

    public void setCallbackListener(CallbackListener ls) {
        this.callbackListener = ls;
    }

    public void reset() {
        callbackListener.clear();
    }
}

Наконец, activity_main.xml здесь:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.bug.MyView
        android:id="@+id/myView"
        android:layout_width="match_parent"
        android:layout_height="300px" />

    <Button
        android:id="@+id/bt_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start" />

    <Button
        android:id="@+id/bt_finish"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="finish" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TextView" />
</LinearLayout>

Я ожидаю результат handleMessage(Message msg) до результата System.out.println("finish");, но фактический результат здесь:

2019-05-17 17:11:06.301 31565-31591/com.example.bug I/System.out: before test1 wait
2019-05-17 17:11:08.671 31565-31591/com.example.bug I/System.out: test1 is interrupted
2019-05-17 17:11:08.671 31565-31591/com.example.bug I/System.out: after test1 wait
2019-05-17 17:11:08.671 31565-31591/com.example.bug I/System.out: before test2 wait
2019-05-17 17:11:08.671 31565-31591/com.example.bug I/System.out: test2 is interrupted
2019-05-17 17:11:08.671 31565-31591/com.example.bug I/System.out: after test2 wait
2019-05-17 17:11:09.173 31565-31565/com.example.bug I/System.out: finish
2019-05-17 17:11:09.178 31565-31565/com.example.bug I/System.out: handling Meassage1 

Я не могу найти ошибку, поэтому я предполагаю, что я что-то делаю неправильно. В чем проблема?

...