2015年10月19日月曜日

background処理を書いてみる

調べてみると、以下のように作るのが一般的?のようだ
 1. IntentServiceを継承したクラスを記載
  runnableのrunをOverrideし、重い処理を書く
  IntentServiceのコンストラクタでHandlerをnewする
  IntentServiceのonHandleIntentでhandlerをpostする(これによってUIスレッド側で処理を実施)
  一定時間後に繰り返したい場合はpostDelayedで遅延実行
    (ThreadSleepを使っても同じようだ)
 2. MainActivityで上記Intentを作成、開始    startService で開始

データのやりとりとしては
MainActivity -> IntentService
  開始時(startServiceする前)にsetActionで文字列を渡す
IntentService -> MainActivity
 MainActivityでBroadcastReceiverを登録しておく
 Intentを作成し、putExtraで文字列を登録し、sendBroadcastで送信

 ---
public class MainActivity extends Activity {

    Button buttonStart;
    static public TextView textCount;
    Intent intent;
    boolean isRunning = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buttonStart = (Button)findViewById(R.id.button_start);
        textCount = (TextView)findViewById(R.id.text_count);

        // ボタン押下時のハンドラ
        buttonStart.setOnClickListener(new ButtonClickListener_startButton());  // 実体は↓のクラス

        // Broadcastを受けとるReceiverを設定
        DataReceiver dataReceiver = new DataReceiver();
        // LocalBroadcastの設定
        IntentFilter intentFilter = new IntentFilter("BkTimerEvent");
        LocalBroadcastManager.getInstance(this).registerReceiver(dataReceiver, intentFilter);
    }

    // ボタン押下ハンドラとして登録される
    private class ButtonClickListener_startButton implements View.OnClickListener {
        @Override
        public void onClick(View v){
            Log.d("BackgroundTimer", "onClick");       // ログ出力
            intent = new Intent(getApplication(), BackgroundIntentTimer.class);      // intentを生成
            intent.setAction("start");      // 文字列を受け渡す。受け側はonHandleIntentの引数から、getActionで文字列を取得する事ができる(putExtraでも同様の事が出来そう)
            startService(intent);           // 開始。onHandleIntentが呼び出され
        }
    }

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

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    // Broadcastを受けとる
    public class DataReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent){
            Log.d("BackgroundTimer", "MainActivity Received");

            // Broadcastされたメッセージを取り出す
            String message = intent.getStringExtra("Message");
            if(message!=null) {
                textCount.setText(message);
            }
        }
    }
}

---
 package com.example.training.backgroundtimer;

import android.app.IntentService;
import android.content.Intent;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

/**
 * Timer
 */
public class BackgroundIntentTimer  extends IntentService{

    private Handler handler;

    public BackgroundIntentTimer(){
        super("com.example.training.backgroundtimer.BackgroundIntentTimer");
        handler = new Handler();
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d("BackgroundTimer", "onHandleIntent");
        String action = intent.getAction();     // Activity側でsetActionした内容を出力

        // callbackをremoveしないと重複処理される為
        handler.removeCallbacks(thread);
        if(action.equals("start")){
            count = 0;
            handler.post(thread);   // UIスレッドに対して処理をポストする(描画処理の為)
        }
        Log.d("BackgroundTimer", action);
    }

    // スレッド
    private Runnable thread = new Runnable() {
        @Override
        public void run() {
            // ここに重い処理を呼び出す
            Log.d("BackgroundTimer", "run!!");
            timerProcess();
        }
    };

    private void timerProcess(){
        // 表示更新用にメッセージ(Intent)送信
        Log.d("BackgrountTimer", "timer Process");        Intent messageIntent = new Intent("BkTimerEvent");
        messageIntent.putExtra("Message", Integer.toString(count));
        LocalBroadcastManager.getInstance(this).sendBroadcast((messageIntent));

        // 1秒ごとにカウントアップする処理
         /*
            try {
                LocalBroadcastManager.getInstance(this).sendBroadcast((messageIntent));                handler.removeCallbacks(thread);
                Thread.sleep(1000);
            } catch (InterruptedException ie){
                Log.d("BackgroundTimer", "timer error");
            }
            */
            handler.removeCallbacks(thread);            handler.postDelayed(thread,1000);   // 遅延実行する場合
            // handler.post(thread);   //Thread.sleepする場合
        }
    }
}