AsyncTask で Broadcast 受信

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);
         }
      }
   }

}