229 views
この記事は最終更新から 642日 が経過しています。
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(); } }