AsyncTask で Broadcast を受信して処理することは可能か?
可能であった。
試しに Bluetooth の検出を AsyncTask で捕捉してみた。
検出中はダイアログを表示するようにして、検出した BluetoothDevice インスタンスを呼び出し側で処理するものである。
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
/**
* BtScanTask
*/
public abstract class BtScanTask extends AsyncTask<String,Void,Integer> implements OnCancelListener{
public final static String BT_SCAN = "BT_SCAN";
public final static String BT_OFF = "BT_OFF";
/* サブクラスで検出した BluetoothDevice を処理する */
protected abstract void addDevice(BluetoothDevice device);
/* 検出終了をサブクラスに通知することで呼び出し元で処置をする */
protected abstract void postNotify(inr result);
private Context context;
private ProgressDialog dialog;
private String message;
private BTReceiver btReceiver;
BlockingQueue<Integer> queue;
Map<String,String> map; // Bluetooth 検出重複を避けるため
private BluetoothAdapter adapter;
public BtScanTask(Context context,String message){
this.context = context;
this.message = message;
queue = new ArrayBlockingQueue<Integer>(4);
map = new HashMap<String,String>();
}
@Override
protected void onPreExecute(){
// ここで、BluetoothAdapter を取得しないと doInBackground で落ちることがある。
adapter = BluetoothAdapter.getDefaultAdapter();
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothDevice.ACTION_NAME_CHANGED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
btReceiver = new BTReceiver();
context.registerReceiver(btReceiver,filter);
showDialog();
}
@Override
protected Integer doInBackground(String...request){
if (request[0].equals(BT_SCAN)){
if (adapter.isEnabled()){
adapter.startDiscovery();
}else{
if (!adapter.isEnabled()){
return 1; // OFFなのに、OFFが要求された場合は即終了
}
adapter.enable();
}
}else if(request[0].equals(BT_OFF)){
adapter.disable();
}
Integer rtn;
try{
rtn = queue.take();
}catch(InterruptedException e){
rtn = -1;
}
return rtn;
}
@Override
protected void onPostExecute(Integer result){
context.unregisterReceiver(btReceiver);
dismissDialog();
// 検出終了を通知または、OFF や、キャンセルを通知
postNotify(result);
}
@Override
public void onCancel(DialogInterface i){
context.unregisterReceiver(btReceiver);
dismissDialog();
}
@Override
protected void onCancelled(){
context.unregisterReceiver(btReceiver);
dismissDialog();
}
private void showDialog(){
dialog = new ProgressDialog(context);
dialog.setProgress(ProgressDialog.STYLE_SPINNER);
dialog.setMessage(message);
dialog.setIndeterminate(false);
dialog.setCancelable(true); // false なら BACK でキャンセル不可
dialog.setOnCancelListener(new DialogInterface.OnCancelListener(){
@Override
public void onCancel(DialogInterface _dialog){
cancel(true);
}
});
dialog.show();
}
protected void dismissDialog(){
if (dialog != null){
dialog.dismiss();
dialog = null;
}
}
class BTReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context _context,Intent intent){
String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)){
Bundle extras = intent.getExtras();
int state = extras.getInt(BluetoothAdapter.EXTRA_STATE);
if (state==BluetoothAdapter.STATE_ON){
// DISCOVERY_START を実行
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter.startDiscovery();
}else if(state==BluetoothAdapter.STATE_OFF){
queue.add(1);
}
}else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)){
// 検出開始
}else if(action.equals(BluetoothDevice.ACTION_NAME_CHANGED)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String address = device.getAddress();
if (!map.containsKey(address)){
map.put(address,address);
addDevice(device);
}
}else if(action.equals(BluetoothDevice.ACTION_FOUND)){
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
String address = device.getAddress();
if (!map.containsKey(address)){
map.put(address,address);
addDevice(device);
}
}else if(action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)){
// 検出終了
queue.add(0);
}
}
}
}