<< Android-Note

AsyncTaskを使った非同期なダウンロード方法

画像や音楽などをインターネットから非同期に(バックグランドで)ダウンロードしたい場合はAsyncTaskを使います。

このクラスはバックグラウンドで処理ができる上にUIスレッドにも直接アクセスできます。

なので複数の画像などをダウンロードしているときにダイアログに進歩状況を表示するといったことも可能です。

AsyncTaskを使う手順は次のようになります。

  1. パーミッションの追加
  2. AsyncTaskクラスの作成
  3. アクティビティやサービス側でAsyncTaskを使ってダウンロード

パーミッションの追加

通信を行うときはAndroidManidest.xmlに次のようにInternetパーミッションを追加します。

AndroidManifest.xml
    </application>

    <uses-permission android:name="android.permission.INTERNET" />
        <!--上の1行を追加-->
</manifest>

AsyncTaskクラスの作成

次にAsyncTaskクラスを拡張したクラスを作ります。ここではFileLoaderという名前で次のようなクラスを作りました。

FileLoader.java
public 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に返しています。

この例ではログを出力しているだけですが、もし進歩状況を表示したいならonProgressUpdateonPostExecuteメソッドでダイアログなどを表示することができます。

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メソッドをオーバーライドして呼び出しています。

関連項目
プライバシーポリシー