[Android] 非同期処理でネットワークからファイルをダウンロードして外部SDカードに保存する

2011/11/15

非同期処理でネットワークからファイルをダウンロードして、指定のFileに保存するクラスを作りましたです。

今回の使い方アプリは、

ダウンロードボタンを押すと、ネットワークからダウンロードがスタート

終わったら、SDカードに保存します。

■作り方
AndroidManifest.xml にユーザー許可を追加します。

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/loadStartButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Download" />

</LinearLayout>

AsyncFileLoader.java

AsyncTaskを使っています。
あと、InputStreamとOutputStreamを使って
少しずつ入力ファイルを読み込んで、
それを出力ファイルに書き込みます。


package com.kinkuma.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

import android.os.AsyncTask;
import android.util.Log;

public class AsyncFileLoader extends AsyncTask<Void, Void, Boolean> {
	private final String TAG = "AsyncFileLoader";
	private String _urlStr;
	private URL _url;
	private URLConnection _urlConnection;
	private final int TIMEOUT_READ = 5000;
	private final int TIMEOUT_CONNECT = 30000;
	private InputStream _inputStream;
	private BufferedInputStream _bufferedInputStream;
	private FileOutputStream _fileOutputStream;
	private File _outputFile;
	private byte[] buff = new byte[5 * 1024];
	
	private int _totalByte = 0;
	private int _currentByte = 0;
	
	public AsyncFileLoader(String urlStr, File outputFile){
		this._urlStr = urlStr;
		this._outputFile = outputFile;
	}
	
	@Override
	protected Boolean doInBackground(Void... params) {
		
		if(isCancelled()){
			return false;
		}
		
		try{
			int len;
			while((len = _bufferedInputStream.read(buff)) != -1){
				_fileOutputStream.write(buff, 0, len);
				_currentByte += len;
				//publishProgress();
				if(isCancelled()){
					break;
				}
			}
	
		}catch(IOException e){
			Log.d(TAG, "error on read file:" + e.toString());
			return false;
		}
		return true;
	}
	
	@Override
	protected void onPreExecute(){
		try{
			connect();
		}catch(IOException e){
			Log.d(TAG, "error on preExecute:" + e.toString());
			cancel(true);
		}
	}
	/*
	@Override
	protected void onProgressUpdate(Void... progress){
		
	}
	*/
	@Override
	protected void onPostExecute(Boolean result){
		if(result == true){
			try{
				close();
			}catch(IOException e){
				Log.d(TAG, "error on postExecute:" + e.toString());
			}
		}else{
			Log.d(TAG, "result: load error");
		}
	}
	
	private void connect() throws IOException
	{
		_url = new URL(_urlStr);
		_urlConnection = _url.openConnection();
		_urlConnection.setReadTimeout(TIMEOUT_READ);
		_urlConnection.setConnectTimeout(TIMEOUT_CONNECT);
		_inputStream = _urlConnection.getInputStream();
		_bufferedInputStream = new BufferedInputStream(_inputStream, 1024 * 5);
		_fileOutputStream = new FileOutputStream(_outputFile);
		
		//_totalByte = _bufferedInputStream.available(); //this is not work
		_totalByte = _urlConnection.getContentLength();
		_currentByte = 0;
	}
	
	private void close() throws IOException
	{
		_fileOutputStream.flush();
		_fileOutputStream.close();
		_bufferedInputStream.close();
	}
	
	public int getLoadedBytePercent()
	{
		if(_totalByte <= 0){
			return 0;
		}
		//Log.d(TAG, Integer.toString(_currentByte) + ":" + Integer.toString(_totalByte));
		return (int)Math.floor(100 * _currentByte/_totalByte);
	}
}

main activity

SDカードのパスを拾うために、Environment.getExternalStorageDirectory()を使いました。

package com.myprogress;

import java.io.File;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.kinkuma.util.AsyncFileLoader;

public class DownloadingAndProgressbarActivity extends Activity {
    private final String TAG = "DownloadSample";
	private Button _loadStartButton;
	private ProgressDialog _progressDialog;
	private Handler _progressHandler;
	private final String VIDEO_URL = "http://192.168.1.0/video/sample_movie.mp4";
	private AsyncFileLoader _fileLoader;
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        _loadStartButton = (Button)findViewById(R.id.loadStartButton);
        _loadStartButton.setOnClickListener(new View.OnClickListener() {
		
			@Override
			public void onClick(View v) {
				initFileLoader();
				showDialog(0);
				_progressDialog.setProgress(0);
				_progressHandler.sendEmptyMessage(0);
			}
		});
        
        _progressHandler = new Handler(){
        	public void handleMessage(Message msg){
        		super.handleMessage(msg);
        		if(_fileLoader.isCancelled()){
        			_progressDialog.dismiss();
        			Log.d(TAG, "load canceled");
        		}
        		else if(_fileLoader.getStatus() == AsyncTask.Status.FINISHED){
        			_progressDialog.dismiss();
        		}else{
        			_progressDialog.setProgress(_fileLoader.getLoadedBytePercent());
        			_progressHandler.sendEmptyMessageDelayed(0, 100);
        		}
        	}
        };
    }
    
    @Override
    protected void onPause(){
    	Log.d(TAG, "onPause");
    	super.onPause();
    	cancelLoad();
    }
    
    @Override
    protected void onStop(){
    	Log.d(TAG, "onStop");
    	super.onStop();
    	cancelLoad();
    }
    
    private void cancelLoad()
    {
    	if(_fileLoader != null){
    		_fileLoader.cancel(true);
    	}
    }
    
    private void initFileLoader()
    {
    	File sdCard = Environment.getExternalStorageDirectory();
    	File directory = new File(sdCard.getAbsolutePath() + "/SampleFolder");
    	if(directory.exists() == false){
    		directory.mkdir();
    	}
    	File outputFile = new File(directory, "myvideo.mp4");
    	_fileLoader = new AsyncFileLoader(VIDEO_URL, outputFile);
    	_fileLoader.execute();
    }
    
    @Override
    protected Dialog onCreateDialog(int id){
    	switch(id){
    		case 0:
    			_progressDialog = new ProgressDialog(this);
    			_progressDialog.setIcon(R.drawable.ic_launcher);
    			_progressDialog.setTitle("Downloading files..");
    			_progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    			_progressDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Hide", new DialogInterface.OnClickListener() {
					
				@Override
				public void onClick(DialogInterface dialog, int which) {
						Log.d(TAG, "hide");
					}
				});
    			_progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
					
					@Override
					public void onClick(DialogInterface dialog, int which) {
						Log.d(TAG, "cancel");
						cancelLoad();
					}
				});
    	}
		return _progressDialog;
    }
}

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る