(30) AndroidEmulatorからHTTP接続して画像をダウンロードする。

投稿者: | 2023年1月13日

294 views

この記事は最終更新から 493日 が経過しています。

1. やりたいこと

AndroidStudioでアプリを作り、そのアプリ上で、インターネットからダウンロードした画像を表示したい。

2. やってみた

前投稿ではいろいろと手順を端折ったために、後で見直したときに???になった。
今回は、丁寧に手順を記して行こうと思う。

(1) AndroidStudio上でプロジェクトを新規作成する。

1) [New Project] メニューを選択する。

2) [Empty Activity]を選択する。

3) プロジェクト名を決定して [Finish] する。

(2) アプリで HTTPS通信出来るように設定する。

(1) INTERNETアクセスを許可する。

AndroidManufest.xml に 4行目を追記する。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"

(2) HTTPS接続を強制する。(必要な場合)

新規に XMLファイルを作成する。名前は何でもよい。
ここでは communication_rules.xml として作成し、/res/xml フォルダに配置した。

手順:
1. xmlフォルダを選択する。
2. 右クリックして popup menuを表示する。
3. [New]-[File]メニューを選択する。
4. ファイル名 communication_rules.xml を入力する。

<network-security-config>
    <domain-config usesCleartextTraffic="false">
        <domain includeSubdomains="true">www.dogrow.net</domain>
    </domain-config>
</network-security-config>

次に、作ったファイルを AndroidManufest.xml でインポートする。7行目を追記する。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- android:usesCleartextTraffic="true" -->
    <application
        android:networkSecurityConfig="@xml/communication_rules"
        android:allowBackup="true"
 :

(3) Gradleに OkHTTPパッケージを追加

Gradleはスクリプトを書いてビルド実行を制御するツール。
今回は OkHttpをインポートして使う。

build.gradle.
7行目を追記する。

dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    implementation 'com.squareup.okhttp3:okhttp:4.10.0'
}

記述後は、Sync now メニューを選択し、パッケージのダウンロードを実行する。

(3) 画像ダウンロードするプログラムを書く。

以下の機能を持つ Javaプログラムを書いた。
1) ボタン押下のイベントハンドラ onClickに MainActivity.updateImg() を登録した。
2) updateImg()では、HTTPリクエストで画像ファイルの URLを指定して画像取得を要求する。
3) HTTPレスポンスの受信ハンドラ onResponse では、画像データを取得する。
 → メインスレッド側で画像を Viewに表示する。

Androidアプリでは、メインスレッド以外から UIに関する操作(今回の場合は画像表示)ができない。
UI制御を担当するメインスレッドでは、内部的に Looperオブジェクトを持っている。
Looperは MessageQueueを持ち、外部からの処理依頼を受け付ける。
MessageQueueは、Message, Runnableオブジェクト受け取り、それを処理する。

public class MainActivity extends AppCompatActivity {
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        handler = new Handler(Looper.getMainLooper());
    }

    public void updateImg(View view){
        String url = "https://www.dogrow.net/nbdx/ImgDL/fruit_ao_ringo.png";
        OkHttpClient httpClient = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();

        httpClient.newCall(request).enqueue(new Callback(){
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response resp) throws IOException {
                InputStream is = resp.body().byteStream();
                Bitmap bmp = BitmapFactory.decodeStream(is);
                handler.post(() -> {
                    ImageView iv = findViewById(R.id.imgDLView);
                    iv.setImageBitmap(bmp);
                });
            }
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e){
                Log.e("Step2", e.getMessage());
            }
        });
    }
}

参考 :
OkHttpの Callback Class仕様はこちらを参照のこと。
OkHttp Callback

愚直に Callbackクラスのサブクラスを作り、このインスタンスを渡してもよい。

public class MainActivity extends AppCompatActivity {
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        handler = new Handler(Looper.getMainLooper());
    }

    public void updateImg(View view){
        String url = "https://www.dogrow.net/nbdx/ImgDL/fruit_ao_ringo.png";
        OkHttpClient httpClient = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();

        class MyCallback implements Callback{
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response resp) throws IOException {
                InputStream is = resp.body().byteStream();
                Bitmap bmp = BitmapFactory.decodeStream(is);
                handler.post(() -> {
                    ImageView iv = findViewById(R.id.imgDLView);
                    iv.setImageBitmap(bmp);
                });
            }
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e){
                Log.e("Step2", e.getMessage());
            }
        }
        MyCallback myCallback = new MyCallback();
        httpClient.newCall(request).enqueue(myCallback);
    }
}

(4) UIスレッドへの処理依頼の方法いろいろ

(1) 愚直に書く。

class myRunner implements Runnable {
    @Override
    public void run() {
        ImageView iv = findViewById(R.id.imgDLView);
        iv.setImageBitmap(bmp);
    }
}
Runnable runner = new myRunner();
handler.post(runner);

(2) 無名クラスで書く。

Runnable runner = new Runnable() {
    @Override
    public void run() {
        ImageView iv = findViewById(R.id.imgDLView);
        iv.setImageBitmap(bmp);
    }
};
handler.post(runner);

(3) 上記(2)をさらに短縮して書く。

handler.post(new Runnable() {
    @Override
    public void run() {
        ImageView iv = findViewById(R.id.imgDLView);
        iv.setImageBitmap(bmp);
    }
});

(4) ラムダ式で書く。

handler.post(() -> {
    ImageView iv = findViewById(R.id.imgDLView);
    iv.setImageBitmap(bmp);
});

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)