AndroidでImageViewに直接Web画像を表示する
オリジナルのブログ記事です。
土井テクニカルチーム
リンクアドレスです。
https://blog.doiduoyi.com/authors/1584446358138
はじまり。偉大な土井技術チームの学習経験を記録する
ネイティブのImageViewでは、Web上の画像を直接表示するメソッドはありません。Webの画像を表示する必要がよくある場合、その都度操作が必要で面倒なので、今日はImageViewで簡単にWebの画像を表示する方法をお教えします。
ImageViewメソッドのカスタマイズ
ImageViewを継承したクラスを作成し、setImageURL(path)メソッドを追加してください。
import android.content;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os;
import android.util;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class MyImageView extends ImageView {
public static final int GET_DATA_SUCCESS = 1;
public static final int NETWORK_ERROR = 2;
public static final int SERVER_ERROR = 3;
// sub-threads can not operate the UI, set the image through Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case GET_DATA_SUCCESS:
Bitmap bitmap = (Bitmap) msg.obj;
setImageBitmap(bitmap);
break;
case NETWORK_ERROR:
Toast.makeText(getContext(),"Network connection failed",Toast.LENGTH_SHORT).show();
break;
case SERVER_ERROR:
Toast.makeText(getContext(),"Server error occurred",Toast.LENGTH_SHORT).show();
break;
}
}
};
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// Set the network image
public void setImageURL(final String path) {
//open a thread for networking
new Thread() {
@Override
public void run() {
try {
//transform the passed path to a URL
URL url = new URL(path);
//Get the connection
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//use the GET method to access the network
connection.setRequestMethod("GET");
//timeout is 10 seconds
connection.setConnectTimeout(10000);
//Get the return code
int code = connection.getResponseCode();
if (code == 200) {
InputStream inputStream = connection.getInputStream();
// Use the factory to produce a Bitmap from the network's input stream
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
//Use Message to send the image to Handler
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = GET_DATA_SUCCESS;
handler.sendMessage(msg);
inputStream.close();
}else {
//Error occurred on service start
handler.sendEmptyMessage(SERVER_ERROR);
}
} catch (IOException e) {
e.printStackTrace();
// Network connection error
handler.sendEmptyMessage(NETWORK_ERROR);
}
}
}.start();
}
}
レイアウト上でImageViewを使用することはできません。MyImageViewを使用するには、先ほど書き換えたMyImageViewの1つへのフルパスを記述してください。
<Button
android:text="Load web image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/button" />
<com.example.dell.myapplication.MyImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
MainActivity上で、setImageURL()を呼び出し、Web画像へのパスを直接書き込むだけで、Web画像が表示されます。
final MyImageView myImageView = (MyImageView) findViewById(R.id.image_view);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// write the path of the image directly to the network to display the image of the network
myImageView.setImageURL("https://pic.cnblogs.com/avatar/1142647/20170416093225.png");
}
});
最後に、ネットワークへのアクセスを追加することを忘れないでください。
<uses-permission android:name="android.permission.INTERNET"/>
レンダリング
圧縮率
Webから写真を取得してImageViewに直接表示するのは比較的簡単ですが、Web画像が大きくスマホの画面サイズを超えてしまった場合、元の画像を読み込んだままだとメモリの無駄遣いやメモリオーバーの可能性があるので、Web画像を圧縮する必要があることを考えたことがありますか?
まず表示するImageViewの幅と高さを取得する
/**
* Get the actual width of the ImageView
* @return Returns the actual width of the ImageView
*/
public int realImageViewWith() {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
ViewGroup.LayoutParams layoutParams = getLayoutParams();
// If the ImageView sets the width, you can get the real width
int width = getWidth();
if (width <= 0) {
//If the ImageView does not set a width, get the width of the parent container
width = layoutParams.width;
}
if (width <= 0) {
//Get the maximum width of the ImageView
width = getMaxWidth();
}
if (width <= 0) {
//Get the width of the screen
width = displayMetrics.widthPixels;
}
Log.e("Actual width of ImageView", String.valueOf(width));
return width;
}
/**
* Get the actual height of the ImageView
* @return Return the actual height of the ImageView
*/
public int realImageViewHeight() {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
ViewGroup.LayoutParams layoutParams = getLayoutParams();
//If the ImageView has a height set, you can get the real width
int height = getHeight();
if (height <= 0) {
//If the ImageView doesn't have a height set, get the height of the parent container
height = layoutParams.height;
}
if (height <= 0) {
//Get the maximum height of the ImageView
height = getMaxHeight();
}
if (height <= 0) {
//Get the maximum value of the ImageView height
height = displayMetrics.heightPixels;
}
Log.e("Actual height of ImageView", String.valueOf(height));
return height;
}
次に、ウェブ画像のサイズから圧縮する比率を計算します。
/**
* Get the ratio to be compressed
*
* @param options needs to be passed in already BitmapFactory.decodeStream(is, null, options);
* @return return the ratio of compression, minimum is 1
*/
public int getInSampleSize(BitmapFactory.Options options) {
int inSampleSize = 1;
int realWith = realImageViewWith();
int realHeight = realImageViewHeight();
int outWidth = options.outWidth;
Log.e("The actual width of the network image", String.valueOf(outWidth));
int outHeight = options.outHeight;
Log.e("The actual height of the network image", String.valueOf(outHeight));
//Get the one with the largest ratio
if (outWidth > realWith || outHeight > realHeight) {
int withRadio = Math.round(outWidth / realWith);
int heightRadio = Math.round(outHeight / realHeight);
inSampleSize = withRadio > heightRadio ? withRadio : heightRadio;
}
Log.e("compression ratio", String.valueOf(inSampleSize));
return inSampleSize;
}
圧縮率を求めたら、圧縮の準備です
/**
* Return a compressed image based on the input stream
* @param input input stream of the image
* @return compressed image
*/
public Bitmap getCompressBitmap(InputStream input) {
// Because the InputStream has to be used twice, but using it once is invalid, so you need to copy two
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// Copy the new input stream
InputStream is = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
// just get the size of the network image, not really get the image
BitmapFactory.Options options options = new BitmapFactory;
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
//Get the image and compress it
options.inSampleSize = getInSampleSize(options);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is2, null, options);
}
最後に、setImageURL()メソッド内で、Bitmap bitmap = BitmapFactory.decodeStream(inputStream); を次のように変更します。
Bitmap bitmap = getCompressBitmap(inputStream);
キャッシュ
時には運用効率を向上させ、トラフィックを保存するには、多くの場合、キャッシュ、データキャッシュを使用しない場合でも、ネットワークを使用することができます、次のキャッシュを学ぶために開始、私はこのようなキャッシュは、正式なキャッシュ技術ではありません。
setImageURL()メソッドを次のように変更し、2つのグローバル変数imagePath、isUseCacheを追加します。
//Whether caching is enabled
public boolean isUseCache = false;
private String imagePath;
// Set the network image
public void setImageURL(String path) {
imagePath = path;
if (isUseCache){
useCacheImage();
}else {
useNetWorkImage();
}
}
以前の setImageURL() の機能のほとんどを useNetWorkImage() メソッドに入れ、画像をキャッシュするかどうかという決定を追加しました。
// Use the network image display
public void useNetWorkImage(){
//open a thread for networking
new Thread() {
@Override
public void run() {
try {
//transform the passed path to a URL
URL url = new URL(imagePath);
//Get the connection
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//use the GET method to access the network
connection.setRequestMethod("GET");
//timeout is 10 seconds
connection.setConnectTimeout(10000);
//Get the return code
int code = connection.getResponseCode();
if (code == 200) {
Bitmap bitmap;
//Get the network input stream
InputStream inputStream = connection.getInputStream();
// Determine if the cached image is being used
if (isUseCache){
//because the InputStream has to be used twice, but using it once is invalid, so you need to copy two
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len;
while ((len = inputStream.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// Copy the new input stream
InputStream is = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
// call the compression method to display the image
bitmap = getCompressBitmap(is);
//call the cache image method
cacheImage(is2);
}else {
//call the compress method
bitmap = getCompressBitmap(inputStream);
}
//Use Message to send the image to Handler
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = GET_DATA_SUCCESS;
handler.sendMessage(msg);
inputStream.close();
} else {
//service start error occurred
handler.sendEmptyMessage(SERVER_ERROR);
}
} catch (IOException e) {
e.printStackTrace();
// Network connection error
handler.sendEmptyMessage(NETWORK_ERROR);
}
}
}.start();
}
渡されたURLを元に一意のファイルを生成し、そのパスを元に画像を生成し、キャッシュされた画像があるかどうかを調べるメソッドを作成します。
/**
* Generate a filename based on the URL
* @return filename
*/
public String getURLPath() {
StringBuilder urlStr2 = new StringBuilder();
String[] strings = imagePath.split("\\\/");
for (String string : strings) {
urlStr2.append(string);
}
Log.e("MyImageView","Filename: "+urlStr2.toString());
return urlStr2.toString();
}
生成されたパスに基づいて画像をキャッシュする
/**
* Cache images for the network
* @param inputStream The input stream for the network
*/
public void cacheImage(InputStream inputStream) {
try {
File file = new File(getContext().getCacheDir(), getURLPath());
FileOutputStream fos = new FileOutputStream(file);
int len;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) ! = -1) {
fos.write(buffer, 0, len);
}
fos.close();
Log.e("MyImageView","Cache successful");
} catch (IOException e) {
e.printStackTrace();
Log.e("MyImageView","Cache failed");
}
}
最後に、キャッシュされた画像を使用することができます。
// Use cached images
public void useCacheImage() {
// Create a file with the same path
File file = new File(getContext().getCacheDir(), getURLPath());
// determine if the file exists
if (file ! = null && file.length() > 0) {
//use local image
try {
InputStream inputStream = new FileInputStream(file);
// call the compression method to display the image
Bitmap bitmap = getCompressBitmap(inputStream);
//Use Message to send the image to Handler
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = GET_DATA_SUCCESS;
handler.sendMessage(msg);
Log.e("MyImageView","Using cached image");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}else {
// Use a network image
useNetWorkImage();
Log.e("MyImageView","usingNetImage");
}
}
キャッシュを使用するためには、isUseCache を true に設定する必要があります。
// Write the path to the web image directly to display the web image
String url = "https://pic.cnblogs.com/avatar/1142647/20170416093225.png";
//set to true to enable caching, default is false
myImageView.isUseCache = true;
myImageView.setImageURL(url);
MyImageView.javaのコード全体
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os;
import android.util;
DisplayMetrics;
DisplayMetrics; import android.util;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class MyImageView extends ImageView {
private String imagePath;
// whether to enable caching
public boolean isUseCache = false;
public static final int GET_DATA_SUCCESS = 1;
public static final int NETWORK_ERROR = 2;
public static final int SERVER_ERROR = 3;
// sub-threads can not operate the UI, set the image through Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case GET_DATA_SUCCESS:
Bitmap bitmap = (Bitmap) msg.obj;
setImageBitmap(bitmap);
break;
case NETWORK_ERROR:
Toast.makeText(getContext(), "Network connection failed", Toast.LENGTH_SHORT).show();
break;
case SERVER_ERROR:
Toast.makeText(getContext(), "An error occurred on the server", Toast.LENGTH_SHORT).show();
break;
}
}
};
public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// Set the network image
public void setImageURL(String path) {
imagePath = path;
if (isUseCache){
useCacheImage();
}else {
useNetWorkImage();
}
}
// use the network image display
public void useNetWorkImage(){
//open a thread for networking
new Thread() {
@Override
// Network connection error
handler.sendEmptyMessage(NETWORK_ERROR);
}
}
}.start();
}
// Use cached image
public void useCacheImage() {
//create a file with the same path
File file = new File(getContext().getCacheDir(), getURLPath());
// determine if the file exists
if (file ! = null && file.length() > 0) {
//use local image
try {
InputStream inputStream = new FileInputStream(file);
// call the compression method to display the image
Bitmap bitmap = getCompressBitmap(inputStream);
//Use Message to send the image to Handler
Message msg = Message.obtain();
msg.obj = bitmap;
msg.what = GET_DATA_SUCCESS;
handler.sendMessage(msg);
Log.e("MyImageView","Using cached image");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}else {
// Use a network image
useNetWorkImage();
Log.e("MyImageView","usingNetImage");
}
}
/**
* Cache images from the network
* @param inputStream The input stream for the network
*/
public void cacheImage(InputStream inputStream) {
try {
File file = new File(getContext().getCacheDir(), getURLPath());
FileOutputStream fos = new FileOutputStream(file);
int len;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) ! = -1) {
fos.write(buffer, 0, len);
}
fos.close();
Log.e("MyImageView","Cache successful");
} catch (IOException e) {
e.printStackTrace();
Log.e("MyImageView","Cache failed");
}
}
/**
* Generate a file name based on the URL
* @return filename
*/
public String getURLPath() {
StringBuilder urlStr2 = new StringBuilder();
String[] strings = imagePath.split("\\\/");
for (String string : strings) {
urlStr2.append(string);
}
Log.e("MyImageView","File name: "+urlStr2.toString());
return urlStr2.toString();
}
/**
* Returns a compressed image based on the input stream
*
* @param input The input stream of the image
* @return compressed image
*/
public Bitmap getCompressBitmap(InputStream input) {
// Because the InputStream has to be used twice, but using it once is invalid, so you need to copy two
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
} catch (IOException e) {
e.printStackTrace();
}
// Copy the new input stream
InputStream is = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
// just get the size of the network image, not really get the image
BitmapFactory.Options options options = new BitmapFactory;
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
//Get the image and compress it
options.inSampleSize = getInSampleSize(options);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeStream(is2, null, options);
}
/**
* Get the ratio to be compressed
*
* @param options needs to be passed in already BitmapFactory.decodeStream(is, null, options);
* @return return the ratio of compression, minimum 1
*/
public int getInSampleSize(BitmapFactory.Options options) {
int inSampleSize = 1;
int realWith = realImageViewWith();
int
キャッシュを利用した効果イメージ
画像読み込みフレームワーク「Glide」の利用
この非常に高度なオープンソースの時代に、私たちがそのような複雑な作業をする必要がないように作られている様々なオープンソースのフレームワークがあるのは確かです。ここでは、画像読み込みフレームワークGlideの簡単な使い方を紹介します。
Glideを使用する前にGlideの依存関係を追加するには
compile 'com.github.bumptech.glide:glide:4.0.0'
先ほどと同じ条件で、クリックイベントのアクションを次の2行のコードに置き換えます。
String url = "https://pic.cnblogs.com/avatar/1142647/20170416093225.png";
Glide.with(MainActivity.this).load(url).into(myImageView);
このオープンソースのライブラリがあれば、まだあの膨大なコードの山を書きたいとは思わないでしょうし、さらに強力なのは、すでにキャッシュ機能を備えていて、あなたのためにすべてをやってくれることです。
Web画像の読み込みのイメージ図
キャッシュを使用した場合の効果イメージ
このように強力なオープンソースライブラリなので、その使い方を簡単に理解しましょう。まず、6つの引数を取ることができる with() メソッドのソースコードから、さまざまな状況で動作することを確認します。
public static RequestManager with(Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(FragmentActivity activity) { return getRetriever(activity).get(activity); }
return getRetriever(activity).get(activity);
}
public static RequestManager with(android.app.Fragment fragment) { return getRetriever(activity).get(activity); }
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(View view) {
return getRetriever(view.getContext()).get(view);
}
例えば、String 型を渡すと、ネットワークから画像を読み込んでくれますが、File(ローカル画像を読み込む)、int(アプリケーションファイルのソースを読み込む)、byte[] (バイトストリーム)、Uri
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
とりあえずアプリの画像を読み込んでみよう
Glide.with(MainActivity.this).load(R.mipmap.ic_launcher).into(myImageView);
レンダリング
最後に、into()メソッドで、表示したいImageViewを読み込んで完了です。
繰り返しの処理 グライド-->with()-->load()-->into()
プロジェクトのソースコードです。 https://resource.doiduoyi.com/#2o4csq2
関連
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
AndroidStudioは、新しいプロジェクト:エミュレータを作成した後、エラーを報告します。ERROR: x86 emulation currently requires hardware acceleration!
-
Android フロントカメラのビデオ録画に失敗しました (MediaRecorder: start failed: -19)
-
アプリケーションがメインスレッドで過剰に作業している可能性があります。
-
Android - adb 権限拒否の解決策
-
Android android-support-multidexを使用すると、Dexがメソッドの制限を超える問題を解決し、アプリケーションがバーストしなくなります。
-
android.view.inflateexception バイナリ xml ファイル行例外の解決方法
-
Android SDKです。sdkmanagerコマンドラインツールの使用(パッケージの表示、インストール、アップデート、アンインストール)
-
android セキュリティ: フラグ FLAG_RECEIVER_REGISTERED_ONLY の意味
-
Android - シンプルな目覚まし時計アプリ
-
Androidソースコード構造解析