スレッド
AndrroidのUIスレッド(メインスレッド)はSingleton Threadのため、Thread Safeではない
UIスレッドのみはUIコントロールにアクセスできる
UIスレッドを塞がないように下記の方法で解決できる
・HandlerとLooper
MessageQueue、Message
・Activity.runOnUIThread(Runnable)
・View.post(Runnable)或いはView.postDelayed(Runnable, long)
・AsyncTask
引数
1、Params
2、Progress
3、Result
Callback
1、onPreExecute
2、doInBackground
3、onProgressUpdate
4、onPostExecute
非同期処理 HandlerとAsyncTask
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
public class AndroidTestActivity extends Activity implements OnClickListener {
private static final String TAG
= AndroidTestActivity.class.getSimpleName();
private static final String PATH1
= "http://careercrud.appspot.com/images/log_in.png";
private static final String PATH2
= "http://careercrud.appspot.com/images/log_out.png";
private static final int SUCCESS = 1;
private FrameLayout frameLayout = null;
private Bitmap bitmap = null;
private ProgressDialog dialog = null;
// ★方法1 Handlerメンバ変数が繰り返し、実行できる
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case SUCCESS:
ImageView view
= (ImageView)frameLayout.findViewById(R.id.image);// 書き方1
view.setImageBitmap(bitmap);
dialog.dismiss();
break;
}
}
};
// ★方法2 AsyncTaskメンバ変数が一回のみ、繰り返し、実行できないため、ローカル変数にしよう
// private AsyncTask<String, Integer, Bitmap> asyncTask = new AsyncTask ×
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btn1 = (Button)findViewById(R.id.btn1);
Button btn2 = (Button)findViewById(R.id.btn2);
btn1.setOnClickListener(this);
btn2.setOnClickListener(this);
ProgressBar progress = (ProgressBar)findViewById(R.id.progress);
progress.setVisibility(View.GONE);
frameLayout = (FrameLayout)findViewById(R.id.frameLayout);
}
public void onClick(View v) {
dialog = ProgressDialog.show(this, "", "Wait...", true, true);
switch(v.getId()){
case R.id.btn1:
// 別スレッドを起動
handler.post(new Runnable(){
public void run() {
// ファイルをダウンロード
bitmap = getBitmapByHttp(PATH1);
//newよりMessagePoolから取得した方が効率よい
//Message msg = new Message();
Message msg = handler.obtainMessage(); Better
msg.what = SUCCESS;
//msg.arg1 = SUCCESS;
//msg.arg2 = SUCCESS;
handler.sendMessage(msg);
}
});
break;
case R.id.btn2:
AsyncTask<String, Integer, Bitmap> asyncTask = new AsyncTask<String, Integer, Bitmap>() {
@Override
protected Bitmap doInBackground(String... params) {
return getBitmapByHttp(params[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
ImageView imgView
= (ImageView)frameLayout.getChildAt(0); // 書き方2
imgView.setImageBitmap(result);
dialog.dismiss();
}
};
asyncTask.execute(PATH2);
break;
}
}
private Bitmap getBitmapByHttp(String path) {
HttpURLConnection conn = null;
Bitmap bitmap = null;
try {
URL url = new URL(path);
conn = (HttpURLConnection)url.openConnection();
bitmap = BitmapFactory.decodeStream(conn.getInputStream());
}
catch (MalformedURLException e) {
Log.d(TAG, "Exception", e);
}catch (IOException e) {
Log.d(TAG, "Exception", e);
} finally {
if(conn != null){
conn.disconnect();
}
}
return bitmap;
}
}
★Handler
実はスレッドをstart()させないまま、単にrun()を呼ぶだけで、Message Queueに基づく
特徴:
・コード量が多いが、コストが低い
・通信量が少ない時に利用
利用方法1 boolean sendMessage(Message msg)
手順:
1.UIスレッドの中にHandler(handleMessageメソッドを実装)をnewする
2.子スレッドの中にnew済みのHandler(sendMessageメソッドでメッセージを送る)を呼び出す
サンプルは左側のコードを参照
利用方法2 boolean post(Runnable r)
手順:
1.UIスレッドの中にHandlerをnewする
2.Runnable(runメソッドを実装)をnewする
3.子スレッドの中にnew済みのRunnable(postメソッドで呼ぶ)を呼び出す
サンプルはソーシャルを参照
★AsyncTask
実はスレッドプール
特徴:
コード量が少ないが、コストが高い
通信量が多い時に利用
注意点:
1.Taskは必ずUIスレッドの中にnewする
2.executeは必ずUIスレッドの中に呼ぶ
3.Taskは一回のみ実行される
new AsyncTask<Params, Progress, Result>().execute(Params... params)
onPreExecute()
doInBackground(Params…)
onProgressUpdate(Progress…)
onPostExecute(Result)
o