技術情報

新人成長記録13th

AsyncTaskについて

今回もAndroidにおける非同期処理について書いていきます
前回はThreadでの非同期処理を書きました
今回はAsyncTaskについてです

AsyncTask

Threadでは、基本的にUIスレッドを使うことはできませんでした(Handlerを使えばUIスレッドへ投げられますけどね)
AsyncTaskではUIスレッドと関係のある非同期処理を行うことができます
例えば、長い処理の間の待ちとしてプログレスダイアログを表示することができます
現在の処理が全体の何パーセントか、何件中の何件処理完了とかですね
このようなダイアログを表示することでユーザにも現在の進行が分かるようになります

progress_spinner  progress_percent

プログラムの内容は以下のようになります。

public class AsyncFrag extends AsyncTask<Integer, Integer, Boolean> {

	Context context;
	ProgressDialog dialog;


	public AsyncFrag(Context context){
		this.context = context;
	}

	@Override
	protected void onPreExecute() {
		dialog = new ProgressDialog(context);
		dialog.setTitle("Please wait");
		dialog.setMessage("Loading data...");
		dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
		dialog.setCancelable(false);
		dialog.setMax(100);
		dialog.show();
	}

	@Override
	protected Boolean doInBackground(Integer... params){

		for(int i=0;i<100;i++){
			if(isCancelled()){
				return false;
			}
			try {
				Thread.sleep(300/(i%3 + 1));
				publishProgress(1);
			}catch (Exception e){}
		}
		publishProgress(1);
		return true;
	}

	protected void onProgressUpdate(Integer... params){
		dialog.incrementProgressBy(1);
	}

	@Override
	protected void onPostExecute(Boolean result) {
		if(dialog != null && dialog.isShowing()) {
			dialog.dismiss();
		}
	}

	@Override
	protected void onCancelled(){
		Log.d("debug","onCancelled");
		if(dialog != null && dialog.isShowing()) {
			dialog.dismiss();
		}
	}
}

AsyncTaskを使うときには必要な引数は3つあります
1つ目は、doInBackgroundメソッドの引数となっており、メインの処理で呼ぶ際に受け渡す値となります
2つ目は、opProgressUpdateメソッドの引数となっており、表示しているダイアログの更新などに使えます
3つ目は、doInBackgroundメソッドの返り値で、onPostExecuteメソッドの引数となっています

2つ目の引数に関しては、onProgressUpdateメソッドの必要がない場合には、Voidを指定してもいいですし、なにか適当に指定するのもいいです

それでは、このクラスの中での処理の流れを説明していきます
最初に、onPreExecuteが処理されます
ここでは、UIを変更することができるので、ここでダイアログを表示します

次にdoInBackgroundが処理されます
ここは、Uiスレッドとは異なるスレッドでの処理なのでUIの編集はできませんので注意が必要です
publishProgressでonProgressUpdateに処理を渡すことができますので、処理の中でのループで呼ぶようにしてあげると、ダイアログの更新を頻繁にでき、処理完了までの割合などが伝えることができます

ここが正常に終わるとonPostExecuteが処理されます
ここでもUIの処理ができるので、表示してあるダイアログを消したり、テキストの編集をしたりできます

また、非同期処理中にcancelがされているとdoInBackgroundの中でisCancelで判定し終了させるか、処理がすべて終わると
onCancelledが処理されます
この中でもダイアログを閉じる処理を入れるようにすることが必要です

呼び出し方

メイン処理からAsyncTaskを呼び出す時には、以下のようにします

asyncFrag = new AsyncFrag(this);
                asyncFrag.execute(view.getId());

これだけで非同期処理の実行が可能です

終わりに

Androidで非同期処理を行うには、UIの操作ができないですが、そもそもUIと処理を密接な関係にしている処理内容がダメなんじゃないかと少し思いました
ダイアログだけだして裏でUIが絡む処理をしているとプログレスダイアログでは、くるくる回る動作をせず少しダサい気がします
出来る限り、時間のかかる処理とUIの操作は分けるように作っていきたいです



出荷シェア87.5%に!

同年第3四半期(2016年7~9月)にAndroidの出荷シェアが過去最高を記録しました

android_os

続きを読む



新人成長記録12th

非同期で重たい(時間のかかる)処理をしたいことは非常に多くあります
例えば、通信中にプログレスダイアログを表示することや、重い計算や画像の処理などです

非同期処理で処理を行うには、ThreadやAsyncTaskを用います
今回はThreadについて学習していきます

また、Androidの特徴として、描画はUIスレッドで行わなければいけないため、非同期処理をしているスレッドでは、基本的に画面の描画を行うことができません

Thread

簡単な非同期処理であればTreadを利用するのがいいかと思います

単純な記述例では以下のようになります

Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                //処理
            }
        });
        
        thread.start();

もちろん、以下のようにimplementでメソッドを実装することも可能です

public class MainActivity extends Activity implements Runnable{
    public void onCreate(Bundle bundle){
        super.onCreate(bundle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.mainactivity);
        this.bundle = new Bundle();
        this.bundle.putBoolean("END",false);

        handler = new Handler();

        b1 = (Button) findViewById(R.id.frag1);
        b1.setOnClickListener(this);
        b2 = (Button) findViewById(R.id.frag2);
        b2.setOnClickListener(this);

        gv = new GraphicsView(this);

        Thread thread = new Thread(this);

        thread.start();

    }

    public void run(){
        //処理
    }
}

しかし、どの処理でも非同期スレッドの中では、UIスレッドの描画は行うことはできません
非同期処理の中で描画をしたいのならば、以下のようにHandlerでUIスレッドに描画するように指示を出すことです

Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText("Hello");
                    }
                });
            }
        });

終わりに

非同期にしたいけど、処理の中で描画などUIスレッドでしかできないことをしていて、うまいこと処理を分けられず四苦八苦したことがあります
描画と重い処理とは基本的に、分けた方がいいのではと思います
密接な関係にあるとどうしてもユーザを待たせてしまいレスポンスの悪いアプリとなりますので

次回にAsyncTaskについて書きたいと思います

火曜日担当:poppy



新人成長記録11th

前回の記事でも書いた通り、今回はFragmentのイベントをActivityで受け取る内容となります

例えばFragment上のボタンを押した時に、Activityで処理を書きたい時などに使えます

Fragmentの実装

Fragmentにはinterfaceとボタンを押した時の処理を記述します

まず初めに、interfaceを以下のように実装します

	public interface Mylistener{
		void onClickToast();
	}

interfaceは宣言のみで実装はしない!でした
Mylistenerの部分は好きな名前で大丈夫です
void onClickToast()の部分がActivity側に実装するメソッドとなります

また、Fragmentのライフサイクルの初めに以下のようにリスナを設定します

	public void onAttach(Context context){
		super.onAttach(context);
		if(context instanceof Mylistener){
			mylistener = (Mylistener) context;
		}
	}

if文内の”context instanceof Mylistener”では、受け取ったcontextにMylistenerが実装されているかをチェックします
trueならばリスナをセットします
これでinterfaceのメソッドを使用する準備は万端です

今回はボタンを押された時にメソッドを実行したいので以下のように実装します

	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle){
		View root = inflater.inflate(R.layout.fragment,container,false);

		Button button = (Button) root.findViewById(R.id.button);
		button.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				if(mylistener != null){
					mylistener.onClickToast();
				}
			}
		});

		return root;
	}

Activityの実装

Activity側では、以下のように先ほどのinterfaceをimplementsで実装していきます

public class MainActivity extends Activity implements Fragment1.Mylistener{
    public void onCreate(Bundle bundle){
        super.onCreate(bundle);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.mainactivity);
    }
}

このままでは何も起きないですし、ビルド時に怒られてしまいます
interfaceで宣言されているメソッドをすべて実装しないといけませんね
実装結果が以下です

    public void onClickToast(){
        Toast.makeText(this,"Fragmentのボタンが押されました",Toast.LENGTH_SHORT).show();
    }

これですべての実装が完了しました
Fragment内にあるボタンを押すことでActivity上のonClickToastが呼ばれ、Toastを表示することができます

終わりに

interfaceで外部に実装することは多くあり、必要な知識であるということは、業務に触れることによって実感しています
早いうちに学ぶ機会があり、記事にすることで理解を深めることができたと思います
少しずつですが、Android開発のことを理解してくると開発が楽しくなってきます

火曜日担当:poppy



新人成長記録10th

FragmentのイベントをActivityで受け取るのにinterfaceとimplementsについて詳しく学習する機会がありました
そこで、学習した内容をまとめたいと思います

今回では、interfaceとimplementsとはどのようなものかを記述します
それぞれの関係性を簡単に説明すると、interfaceでメソッドの定義を行い、implementsにてclassに実装します

次回に、FragmnetのイベントをActivityで受け取る内容にしていきます

続きを読む




アプリ関連ニュース

お問い合わせはこちら

お問い合わせ・ご相談はお電話、またはお問い合わせフォームよりお受け付けいたしております。

tel. 06-6454-8833(平日 10:00~17:00)

お問い合わせフォーム