AsyncTaskを使った非同期なダウンロード方法
画像や音楽などをインターネットから非同期に(バックグランドで)ダウンロードしたい場合はAsyncTaskを使います。
このクラスはバックグラウンドで処理ができる上にUIスレッドにも直接アクセスできます。
なので複数の画像などをダウンロードしているときにダイアログに進歩状況を表示するといったことも可能です。
AsyncTaskを使う手順は次のようになります。
- パーミッションの追加
- AsyncTaskクラスの作成
- アクティビティやサービス側でAsyncTaskを使ってダウンロード
パーミッションの追加
通信を行うときはAndroidManidest.xmlに次のようにInternetパーミッションを追加します。
AndroidManifest.xml
</application>
<uses-permission android:name="android.permission.INTERNET" />
<!--上の1行を追加-->
</manifest>
AsyncTaskクラスの作成
次にAsyncTaskクラスを拡張したクラスを作ります。ここではFileLoaderという名前で次のようなクラスを作りました。
FileLoader.javapublic class FileLoader extends AsyncTask<String, Integer, ByteArrayBuffer[]> { @Override protected ByteArrayBuffer[] doInBackground(String... urls) { int urlNum = urls.length; ByteArrayBuffer[] byteArrays = new ByteArrayBuffer[urlNum]; for(int ui = 0; ui < urlNum; ++ui){ byte[] data = loadData(urls[ui]); //URLからデータをダウンロード ByteArrayBuffer byteArray = new ByteArrayBuffer(10000); byteArray.append(data, 0, data.length); byteArrays[ui] = byteArray; int percent = (int)((ui / (float)urlNum) * 100); publishProgress(percent); } return byteArrays; //データを返す。(onPostExecuteが呼ばれる) } @Override protected void onProgressUpdate(Integer... progresses) { Log.i("FileLoader : ", "ダウンロード進歩 : " + progresses[0] + "%"); } @Override protected void onPostExecute(ByteArrayBuffer[] results) { Log.i("FileLoader : ", "ダウンロード完了"); } /**画像データを読み込んでbyte配列で返す。*/ public byte[] loadData(String url) { byte[] fileData = null; DefaultHttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(url); HttpResponse response; try { response = client.execute(get); if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){ HttpEntity entity = response.getEntity(); fileData = EntityUtils.toByteArray(entity); } } catch (ClientProtocolException err) { err.printStackTrace(); } catch (IOException err) { err.printStackTrace(); } return fileData; } }
AsyncTaskのコンストラクタは3つのジェネリック型を取り、1つめがdoInBackgroundメソッドに渡される型、2つめが進歩状況の管理に使われる型、3つ目がonPostExecuteメソッドなどに渡される実際にダウンロードしたデータの型です。
ここでは1つめの型をString、2つめの型にInteger、3つめの型にByteArrayBufferの配列を指定しています。
また、データをダウンロードするのにloadDataメソッドを作り、そこでデータをバイト配列で取得してからByteArrayBufferに変換してdoInBackgroundに返しています。
この例ではログを出力しているだけですが、もし進歩状況を表示したいならonProgressUpdateやonPostExecuteメソッドでダイアログなどを表示することができます。
AsyncTaskの呼び出し
最後にアクティビティやサービスクラスでAsyncTaskを使ってファイルをダウンロードします。
例えばアクティビティ内で画像を特定のURLからダウンロードしたいなら次のようなコードが書けます。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Button downloadStartButton = (Button) findViewById(R.id.download_start_btn); final ImageView downloadImgView = (ImageView) findViewById(R.id.download_image_view); downloadStartButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { FileLoader fileLoader = new FileLoader(){ @Override protected void onPostExecute(ByteArrayBuffer[] byteArrays) { Toast.makeText(MainActivity.this, "ダウンロード完了!!", Toast.LENGTH_LONG).show(); int imageNum = byteArrays.length; for(int i = 0; i < imageNum; ++i){ byte[] data = byteArrays[i].toByteArray(); Bitmap image = BitmapFactory.decodeByteArray( data, 0, data.length); //byte配列を画像に変換 if(image != null){ downloadImgView.setImageBitmap(image); } } } }; String url = "http://xxx.xxx.com/sub/images/image1.png"; fileLoader.execute(url); //URLから画像データの取得 } }); } }
この例は下の画像のようにボタンを押したらダウンロードが始まってダウンロードし終わったら画像ビューに受け取ったデータを画像に変換して表示するような処理をします。
ダウンロード前 | ダウンロード後 |
---|---|
この例にあるようにAsyncTaskを実行するにはexecuteメソッドにデータのあるURLを渡すだけで実行されます。
その後にデータを受け取るためにFileLoaderインスタンス内でonPostExecuteメソッドをオーバーライドして呼び出しています。