技術情報
新人成長記録13th
AsyncTaskについて
今回もAndroidにおける非同期処理について書いていきます
前回はThreadでの非同期処理を書きました
今回はAsyncTaskについてです
AsyncTask
Threadでは、基本的にUIスレッドを使うことはできませんでした(Handlerを使えばUIスレッドへ投げられますけどね)
AsyncTaskではUIスレッドと関係のある非同期処理を行うことができます
例えば、長い処理の間の待ちとしてプログレスダイアログを表示することができます
現在の処理が全体の何パーセントか、何件中の何件処理完了とかですね
このようなダイアログを表示することでユーザにも現在の進行が分かるようになります
プログラムの内容は以下のようになります。
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の操作は分けるように作っていきたいです
admin at 2016年11月08日 10:00:28
- 2016年11月07日
- Android
出荷シェア87.5%に!
SH at 2016年11月07日 10:00:57
新人成長記録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
admin at 2016年11月01日 03:04:03
新人成長記録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
admin at 2016年10月25日 10:03:10
新人成長記録10th
FragmentのイベントをActivityで受け取るのにinterfaceとimplementsについて詳しく学習する機会がありました
そこで、学習した内容をまとめたいと思います
今回では、interfaceとimplementsとはどのようなものかを記述します
それぞれの関係性を簡単に説明すると、interfaceでメソッドの定義を行い、implementsにてclassに実装します
次回に、FragmnetのイベントをActivityで受け取る内容にしていきます
admin at 2016年10月18日 10:00:55