素人プログラマ奮闘記

javaの初心者がAndroidのことを独学で勉強しつつ、メモを残していきます。

スレッドの勉強(1)

今回はスレッドについて勉強しします。

スレッドとは、画面表示処理とは別にバックで処理したい場合などによく使用します。
ゲームなどを作るときはほぼ間違いなく使用するはずです。

一般的に画面表示処理(メイン処理)などをUIスレッドとよびます。
このUIスレッドで重たい処理などをしてしまうと画面がフリーズしてしまうので
ほかの重たい処理などをUIスレッドではなく、作業用のスレッドで行うと良いでしょう。

まずはRunnableインターフェイスの実装したクラス(SubThread)を作成します。

スレッドで行いたい処理を「java.lang.Runnable 」インターフェースの実装したクラスに記述して
new Thread(SubThread)で引数として渡し、thread.start();でスレッドが開始します。

SubThreadクラスを次のように作成します。

package com.example.threadtest;

import java.text.SimpleDateFormat;
import java.util.Date;

public class SubThread implements Runnable {

	private String myName;    //名前
	private long mySpan;      //周期
	private int myloopCount;  //ループ回数
	
	//コンストラクタ
	public SubThread(String name,long span,int loopCount) {
		myName = name;
		mySpan = span;
		myloopCount = loopCount;
	}
	
	@Override
	public void run() {
		// TODO 自動生成されたメソッド・スタブ
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		//何かの処理
		for(int i = 0; i < myloopCount; i++) {			
			try {
				
				String tmp = sdf.format(new Date());
				String text = String.format("[%s][%s][%s]:", tmp,myloopCount,myName,"処理中");
				System.out.println(text);
				Thread.sleep(mySpan);
				
			} catch (InterruptedException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}
		}		
	}
}
コンストラクタで名前とスレッドスパンとループ回数を指定します。
次に下記のメソッド内に別スレッドで行いたい処理を実装します。

public void run() {
// スレッドの処理を記述します。
}

今回の場合は、指定したループ回数分
指定されたスパンで待機しながら、任意の文字をprintlnしています。

次はUI側から作成したSubThreadを呼んでサブスレッドを実行する処理を作ります。
				
package com.example.threadtest;


import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {

	private Button startButton = null;		//スレッドスタートボタン

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		this.startButton = (Button)findViewById(R.id.start_button);
		
		this.startButton.setOnClickListener(this);
		
	}

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

	@Override
	public void onClick(View arg0) {
		// TODO 自動生成されたメソッド・スタブ
		SubThread sh = new SubThread("サブスレッド", 1000, 100);
		Thread th = new Thread(sh);		
		th.start();
	}
}
画面上にボタンを配置して、そのボタンが押された時にサブスレッドを実行するよにしています。
スレッドを発行している箇所はonClickです。
				
		SubThread sh = new SubThread("サブスレッド", 1000, 100);
		Thread th = new Thread(sh);		
		th.start();
とりあえずこれでUIスレッドをフリーズすることなくログを出力する機能ができました。
次回は、スレッドで実行した結果をUIに表示したりする処理を勉強したいと思います。

カテゴリーへ

スレッドの勉強(2)

今回は前回作ったスレッド処理で、スレッドループの中で数字をカウントして
その結果をUIに表示してみたいと思います。

まずはスレッド内のループごとに1ループ終了を通知してやる必要があるため
カスタムイベントから作成していきます。

初めに、EventListenerクラスを継承したInterfaceに定義します。

package com.example.threadtest;
import java.util.EventListener;

public interface SubThreadEventListener extends EventListener {
	void onOneLoopEndEvent(int count);
}
   

onOneLoopEndEvent(int count)の引数countはループ回数です。
イベント発生側で回数をセットすることとします。


次にMainActivityクラス宣言に、implementsでSubThreadEventListenerをとりこみます。
				public class MainActivity extends Activity implements 
											OnClickListener,SubThreadEventListener {


MainActivityクラスに、SubThreadEventListenerのイベントハンドラをOverrideします。
処理は、とりあえずログを出力するようにしておきます。
				@Override
				public void onOneLoopEndEvent(int count) {
					// TODO 自動生成されたメソッド・スタブ
				    System.out.println("MainActivity=" + count);
				}	


次はSubThreadクラス編集です、SubThreadEventListenerクラスのメンバー変数を追加します。。
public class SubThread implements Runnable {

	private SubThreadEventListener myEventListener = null; //イベントリスナー


SubThreadクラスにubThreadEventListenerの参照を受け取る関数と参照解除の関数を追加します。
	//イベントセット
	public void setEventListener(SubThreadEventListener listener) {
		this.myEventListener = listener;
	}
	//イベント解除
    public void removeListener(){
        this.myEventListener = null;
    }


SubThreadクラスのrun関数内でonOneLoopEndEventを呼びます。
				
	@Override
	public void run() {
		// TODO 自動生成されたメソッド・スタブ
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		//何かの処理
		for(int i = 0; i < myloopCount; i++) {			
			try {
				
				String tmp = sdf.format(new Date());
				String text = String.format("[%s][%s][%s]:", tmp,myloopCount,myName,"処理中");
				System.out.println(text);
				Thread.sleep(mySpan);
				
				//↓↓↓↓↓↓↓これ追加
				if(this.myEventListener != null){
					this.myEventListener.onOneLoopEndEvent(i);
				}
				//↑↑↑↑↑↑↑↑これ追加
				
			} catch (InterruptedException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}
		}		
	}



MainActivityクラスのonClick時のSubThreadインスタンス生成時にsetEventListenerで自クラスをわたしてやります。
				
	@Override
	public void onClick(View arg0) {
		// TODO 自動生成されたメソッド・スタブ
		SubThread sh = new SubThread("サブスレッド", 1000, 100);
		
		//↓↓↓↓↓↓↓これ追加
		sh.setEventListener(this);
	   //↑↑↑↑↑↑↑↑これ追加
	
		Thread th = new Thread(sh);		
		th.start();
	}


これで準備完了です!

実行してみてください。うまくMainActivityクラスのonOneLoopEndEvent関数が呼ばれているはずです。


これで、onOneLoopEndEvent関数内で、テキストなどに
わたってきたカウント数を表示すればいいわけですが、
すんなりとはいきませんでした・・・。orz
非同期処理と UIスレッドについて勉強しないとだめそうです。
その辺は次回に勉強します。


カテゴリーへ

inserted by FC2 system