594 views
この記事は最終更新から 982日 が経過しています。
1. やりたいこと
Androidプログラムを書いていて、以下の制約を意識したコードを書かなければならいことを知った。
制約 : UI描画処理は、アプリのメインスレッド上でのみ実行できる。
右往左往したので、少し整理しておく。
2. やってみる
後でいろいろと整理する。
Thread1 : Handlerを作成。1秒ごとに Main threadの Looperに postする。
Thread2 : Handlerを作成。1回だけ Main threadの Looperに postする。run()内部で1秒間 sleepしながら処理を繰り返し。
Thread3 : Sub threadを作成。run()内部で1秒間 sleepしながら処理を繰り返し。
・Thread2は、Handlerを使って Main threadの Looperに Postしているため、処理中は Main threadを占有する。
→ Thread1の処理は動けない。
・Thread3は、Main threadとは別に Sub threadを起動している。
→ Thread2と並行して動ける。
→ ただし、Main threadではないため、Android UIの制御ができない。
→ Thread3から Main threadの Looperに UI制御の Runnableを Postしている。
・Thread1と Thread3は別スレッドなので、Semaphoreで待ち合わせができる。
・Handler.post は Handlerクラスインスタンスを生成したスレッドに対して Runnableインスタンスを送る。
・Handlerは 1スレッドに 1個でよい。
→ Main threadに処理を postしたい場合、Main thread用に一つ Handlerを生成する、。
→ すべての Runnableはそこを指定して postする。
package com.example.testthread;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
import java.util.concurrent.Semaphore;
public class MainActivity extends AppCompatActivity {
private Semaphore smph = new Semaphore(1);
private final Handler hMainThread = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.hMainThread.post(this.runThread1);
this.hMainThread.post(this.runThread2);
this.RunSubThread3();
}
///////////////////////////////////////////////////////////////////////////
// Thread1
private final Runnable runThread1 = new Runnable() {
private int i = 0;
@Override
public void run() {
System.out.println("Thread1.START (" + i + ")>>>================================");
try {
smph.acquire();
// Do something...
smph.release();
}catch(InterruptedException e){
e.printStackTrace();
}
hMainThread.postDelayed(this, 1000);
System.out.println("Thread1.END <<<==================================");
this.i++;
}
};
///////////////////////////////////////////////////////////////////////////
// Thread2
private final Runnable runThread2 = new Runnable() {
@Override
public void run() {
/*
Main threadの Looperに Postされた処理
→ Main threadに queueingされた処理
→ Main threadの空き待ち後に実行される。*/
for(int i = 0 ; i < 10 ; i++) {
System.out.println("Thread2.START >>>*******************************");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread2.END <<<*********************************");
}
}
};
///////////////////////////////////////////////////////////////////////////
// Thread3
private final Runnable runThread3B = new Runnable() {
// Sub threadから Main threadに Postされて実行される処理
@Override
public void run() {
TextView tv = findViewById(R.id.tv_1);
tv.setText("Thread3 Done!");
}
};
private final Runnable runThread3 = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if(i == 3){
try {
smph.acquire();
}catch(InterruptedException e){
e.printStackTrace();
}
}
if(i == 8){
smph.release();
}
System.out.println("Thread3.START (" + i + ")>>>------------------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread3.END <<<--------------------------------");
}
// ここで UIにアクセスすると例外発生! → Main threadに handleを postする。
//TextView tv = findViewById(R.id.tv_1);
//tv.setText("Thread3 Done!");
hMainThread.post(runThread3B);
}
};
private void RunSubThread3() {
Thread thread3 = new Thread(runThread3);
thread3.start();
}
}