2019年8月11日日曜日

AsyncTaskによるDB非同期処理をListenerを使ってクラス化

Android ActivityでDBを頻繁に使うプログラムを開発する場合に、
前項のようなコードをActivity内に組込むのはやめたい。
クラス化にあたっての課題は、処理の結果を呼び出したクラスに渡すか?
非同期処理処理を踏まえてどうするか。。。
で、先人の知恵を借りてListenerを使って呼び出し側で非同期処理の終了を
解るようにして、一件落着
ますます、便利になった。
Peace!!

ソースの先頭には、使い方を書いた。
サーバーサイドのDBプログラムは別途必要です。
ソースコード、どーんと(笑)

/***********************************************************
 * AsyncTask<型1, 型2,型3>
 *   型1 … Activityからスレッド処理へ渡したい変数の型
 *          ※ Activityから呼び出すexecute()の引数の型
 *          ※ doInBackground()の引数の型
 *   型2 … 進捗度合を表示する時に利用したい型
 *          ※ onProgressUpdate()の引数の型
 *   型3 … バックグラウンド処理完了時に受け取る型
 *          ※ doInBackground()の戻り値の型
 *          ※ onPostExecute()の引数の型
 *   ※ それぞれ不要な場合は、Voidを設定すれば良い
 * --------------------------------------------------------------
 * 呼び出す側に以下を追加する
 ********************************************************************************
 * 汎用DBアクセスクラス SqlOpeAsyncTask を使う場合のListener設定
 * クラスを使う側で設定する。
 * onDestroyは、使うクラス側で重ならなければ使えるかも。未確認
 * @return
 * /
    private SqlOpeAsyncTask.Listener createListener(){
        return new SqlOpeAsyncTask.Listener(){
            @Override
            public void onSuccess(String ret){
                // 以下は個々のプログラム毎に記述
                etKata.setText(ret);
            }
        };
    }
    @Override
    protected void onDestroy() {
        SqlOpeAsyncTask.setListener(null);
        super.onDestroy();
    }

    // 呼び出し例
        String in1 =  getResources().getString(R.string.url_srv_gets1);
        String in2 =  "?100:select kata,tana,hinc,kazu from zaiko where hinc = '15916-1' and tana <> 'REFER' order by tana DESC; ";
        SqlOpeAsyncTask retAsyn = new SqlOpeAsyncTask();
        retAsyn.setListener(createListener());
        String inStr = in1 + in2;
        Log.d(TAG, "before Async execute");
        retAsyn.execute(inStr);
 ***********************************************************************/

package com.futureagri.app.thn.hd.java;

import android.nfc.Tag;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/******************************************************************
 * 非同期でデータベース処理をするクラス。
 ******************************************************************/
public  class SqlOpeAsyncTask  extends AsyncTask<String, Void, String> {
    private Listener listener;

    private static final String TAG = "SqlOpeAsyncTask";
    private String retString = "";
    private TextView textView;

    /********************************************************************
     * メインスレッドとは別のスレッドで実行されます。
     * 非同期で処理したい内容を記述します。
     * このメソッドだけは必ず実装する必要があります
     * @param data
     * @return
     */
    @Override
    //protected String doInBackground(Object[] data) {
    public String doInBackground(String... data) {
        // target URL
        String urlStr = (String)data[0];
        Log.d(TAG, "doInBackground: " + "input sql=" + urlStr);
        // Variable of set result texts
        //StringBuilder result = new StringBuilder();
        String result = "";
        //http接続を行うHttpURLConnectionオブジェクトを宣言。finallyで確実に解放するためにtry外で宣言。
        HttpURLConnection con = null;
        //http接続のレスポンスデータとして取得するInputStreamオブジェクトを宣言。同じくtry外で宣言。
        InputStream is = null;
        int i = 10;
        try {
            //URLオブジェクトを生成。
            URL url = new URL(urlStr);
            //URLオブジェクトからHttpURLConnectionオブジェクトを取得。
            con = (HttpURLConnection) url.openConnection();
            //http接続メソッドを設定。
            con.setRequestMethod("GET");
            //接続。
            con.connect();
            final int   status = con.getResponseCode();
            if (status == HttpURLConnection.HTTP_OK) {
                // Success HTTP GET method
                is = con.getInputStream();
                result = is2String(is);
                is.close();
            }else {
                Log.d(TAG, "doInBackground: HTTP response error");
            }
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
            //} catch (ProtocolException ex) {
            //ex.printStackTrace();
            Log.d(TAG, "doInBackground: HTTP MalformedURLException");
        } catch (IOException ex) {
            ex.printStackTrace();
            Log.d(TAG, "doInBackground: HTTP IOException");
        } finally {
            // HttpURLConnectionオブジェクトがnullでないなら解放。
            if (con != null) {
                con.disconnect();
            }
            // InputStreamオブジェクトがnullでないなら解放。
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    Log.d(TAG,"doInBackground: HTTP close is IOException");
                }
            }
        }
        // 非同期で取得したデータをセットする
        if ( i == 0) {
            Log.d(TAG, "doInBackground: HTTP return : error end");
            return "-99999";
        }else {
            //return result.toString();
            retString = result;
            return result;
        }
    }
    /*****************************************************************************
     * doInBackgroundメソッドの実行後にメインスレッドで実行されます。
     * doInBackgroundメソッドの戻り値をこのメソッドの引数として受け取り、
     * その結果を画面に反映させることができます
     * @param result
     */
    @Override
    public void onPostExecute(String result) {
        //toastMake(result, 0, -200);
        Log.d(TAG, "onPostExecute: result :" + result);
        String[] ret = result.split("\\|");  // Mac \ -> (option + ¥)
        int iMode = Integer.parseInt(ret[0]);   // 呼び出した処理番号
        int cnt  = Integer.parseInt(ret[1]);    // 検索数
        int retu = Integer.parseInt(ret[2]);    // 列数
        Log.d(TAG, "onPostExecute: mode:cnt:retu=" + iMode + ":" + cnt + ":" + retu);
        //-------------------------------------------------------------
        //  mode=100 kata,tana,hinc,kazu
        //-------------------------------------------------------------
        if (iMode == 100) {
            retString = iMode + "|" + cnt + "|" + retu + "|";
            for (int i = 0; i < cnt * retu; i++) {
                retString = retString + ret[3 + i] + "|";
            }
        }
        if (listener != null) {
            listener.onSuccess(retString);
        }
    }
    /*****************************************************************************
     * InputStreamオブジェクトを文字列に変換するメソッド。変換文字コードはUTF-8。
     *
     * @param is 変換対象のInputStreamオブジェクト。
     * @return 変換された文字列。
     * @throws IOException 変換に失敗した時に発生。
     */
    private String is2String(InputStream is) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        StringBuffer sb = new StringBuffer();
        char[] b = new char[2048];
        int line;
        while(0 <= (line = reader.read(b))) {
            sb.append(b, 0, line);
        }
        return sb.toString();
    }
    /************************************************************
     * Listener 処理を定義する
     * 
     * @param listener
     */
    void setListener(Listener listener) {
        this.listener = listener;
    }
    interface Listener {
        void onSuccess(String  count);
    }
}

0 件のコメント:

コメントを投稿