324 views
この記事は最終更新から 639日 が経過しています。
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); });