20 May 2014

(Android) HTTPで受信

AndroidでHTTP通信で受信(ダウンロード)するサンプル

Android 4以降対応のための非同期処理

Android 4以降は、ネットワーク処理はAsyncTaskクラスで非同期処理をすることになっている。 MainActivity内のonCreateで直接ネットワーク処理を行うとExceptionが発生する。

推奨される書き方(非同期処理)
import android.os.AsyncTask;
 
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
 
public class MainActivity extends ActionBarActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        Task task = new Task();
        task.execute("http://www.example.com/index.html");
 
    }
 
    private class Task extends AsyncTask<String, Void, String> {
        protected String doInBackground(String... urls) {
 
            // ネットワーク処理をここに記述する
 
            return("ネットワークからダウンロードした文字列");
        }
 
        @Override
        protected void onPostExecute(String str_recv)
        {
            TextView text = (TextView) MainActivity.this.findViewById(ID_TEXTVIEW);
            text.setText(str_recv);
            return;
        }
    }
}

AsynkTaskクラス派生の定義部分で<String, Void, String>となっている部分は、<Params, Progress, Result>という各引数の型を指定する部分

Params → protected Result doInBackground(Params args)
Progress → protected void onProgressUpdate(Progress args)
Result → protected void onPostExecute(Result arg)

という、それぞれの引数の型を指定するもので、最も重要なものは、非同期タスク doInBackground の戻り値が、PostExecuteの引数になることである。ここの変数の型は合わせないといけない。

通常は、ネットワークからの受信文字列を引き渡すため、「Result」は「String」になるのだが、Android DevelopersのサンプルではLong intとなっている。

Android 2.xでは、推奨される非同期処理を用いずに次の方法でも「一応」実行は可能。ただし、HTTPリクエスト処理が終了するまでGUIが固まるが…

推奨されない書き方(無理やり制限を回避)
import android.os.StrictMode;
 
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
 
public class MainActivity extends ActionBarActivity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().permitAll().build());
 
    // ネットワーク処理を直接こに記述する
 
    }
}

HttpGetを使う場合の例

import android.os.AsyncTask;
 
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
import android.widget.LinearLayout;
import android.widget.TextView;
 
import org.apache.http.*;
import org.apache.http.impl.client.*;
import org.apache.http.client.methods.*;
import org.apache.http.util.*;
 
public class MainActivity extends ActionBarActivity {
 
    final int ID_TEXTVIEW = 0x1001;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
 
        setContentView(R.layout.activity_main);
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        setContentView(layout);
        // HTTP受信したデータ(文字列)を表示する部分
        TextView text = new TextView(this);
        text.setId(ID_TEXTVIEW);
        text.setText("しばらくお待ちください");
        text.setTextSize((int)(text.getTextSize()*1.3));
        layout.addView(text);
 
        Task task = new Task();
        task.execute("http://www.example.com/index.html");
 
    }
 
    private class Task extends AsyncTask<String, Void, String> {
        protected String doInBackground(String... urls) {
 
            String str_recv = "";    // HTTP受信した文字列を格納する
            try{
                HttpGet hg = new HttpGet(urls[0]);
                DefaultHttpClient dhclient = new DefaultHttpClient();
                HttpResponse res = dhclient.execute(hg);
                if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                    str_recv = EntityUtils.toString(res.getEntity());
                }
                else{
                    str_recv = "HTTP応答が200ではないため受信失敗";
                }
            } catch (Exception e) {
                str_recv = "HTTP接続に失敗";
            }
            return(str_recv);
        }
 
        @Override
        protected void onPostExecute(String str_recv)
        {
            TextView text = (TextView) MainActivity.this.findViewById(ID_TEXTVIEW);
            text.setText(str_recv);
            return;
        }
    }
}

java.net.URL を使う場合

AsyncTask クラス拡張部分の doInBackground のところだけを抜き出して書く。(他の部分は、HttpGetと同じ)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
 
〜 〜 〜 
 
        protected String doInBackground(String... urls) {
 
            String str_recv = "";    // HTTP受信した文字列を格納する
            BufferedReader bf = null;
            try{
                URL url = new URL(urls[0]);
                URLConnection url_conn = url.openConnection();
                // タイムアウト(ミリ秒)の設定
                url_conn.setReadTimeout(6000);
                Object content = url_conn.getContent();
                if (content instanceof InputStream) {
                    bf = new BufferedReader(new InputStreamReader( (InputStream)content) );
                    // 1行毎に読み込んだ文字列を連結する
                    String line;
                    while ((line = bf.readLine()) != null) {
                        str_recv += (line + "\n");
                    }
                }
                else{
                    str_recv = content.toString();
                }
            } catch (Exception e) {
                str_recv = "HTTP接続に失敗 : " + e.getLocalizedMessage();
            }
            finally {
                if(bf != null){
                    try{
                        bf.close();
                    } catch (Exception e) {  }
                }
            }
 
            return(str_recv);
        }