Bitmap
和 FileOutputStream
可将网络图片保存到本地文件。
Android 网络图片保存到本地文件
在 Android 开发中,有时需要将网络上的图片保存到本地文件中,这可以通过使用网络库(如 OkHttp 或 Retrofit)来获取图片数据,然后将其写入本地存储来实现,以下是实现这一功能的详细步骤和代码示例。
1. 添加依赖
确保在你的build.gradle
文件中添加了所需的网络库依赖,这里以 OkHttp 为例:
dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
}
2. 请求网络图片
使用 OkHttp 发起网络请求,获取图片的输入流。
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.io.InputStream;
public class ImageDownloader {
private static final String IMAGE_URL = "https://example.com/image.jpg";
public static InputStream downloadImage() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(IMAGE_URL)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
return response.body().byteStream();
}
}
}
3. 保存图片到本地文件
获取到图片的输入流后,将其写入本地文件,我们会将图片保存到应用的缓存目录或外部存储中。
import android.content.Context;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class ImageSaver {
private Context context;
public ImageSaver(Context context) {
this.context = context;
}
public File saveImage(InputStream inputStream) throws IOException {
File cacheDir = context.getCacheDir(); // 或者使用 Environment.getExternalStorageDirectory() 获取外部存储目录
File imageFile = new File(cacheDir, "downloaded_image.jpg");
try (FileOutputStream outputStream = new FileOutputStream(imageFile)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
return imageFile;
}
}
4. 整合代码并运行
将下载和保存图片的代码整合在一起,并在合适的位置调用,在一个 Activity 中:
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
new Thread(() -> {
try {
InputStream inputStream = ImageDownloader.downloadImage();
File imageFile = new ImageSaver(this).saveImage(inputStream);
runOnUiThread(() -> {
Glide.with(this).load(imageFile).into(imageView);
});
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
在上面的代码中,我们使用了 Glide 库来加载保存到本地的图片并显示在 ImageView 中,你需要在build.gradle
文件中添加 Glide 的依赖:
dependencies {
implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
}
5. 权限处理
如果在 Android 6.0 及以上版本中需要访问外部存储,需要在AndroidManifest.xml
中声明权限,并在运行时请求权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
在 Activity 中请求权限:
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
if (ContextCompat.checkSelfPermission(this, WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this, READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE, READ_EXTERNAL_STORAGE}, 1);
}
相关问题与解答
问题1:如果图片很大,下载和保存过程会不会导致内存溢出?
解答:是的,如果图片非常大,直接将整个图片加载到内存中可能会导致内存溢出,为了避免这种情况,可以使用分段读取和写入的方式,如上面的代码所示,每次读取一部分数据并写入文件,而不是一次性将整个图片加载到内存中,可以考虑使用更高效的图片压缩算法来减小图片的大小。
问题2:如何在不同的 Android 版本中兼容外部存储的访问?
解答:在 Android 6.0 及以上版本中,访问外部存储需要动态请求权限,除了在AndroidManifest.xml
中声明权限外,还需要在代码中检查权限并在必要时请求权限,对于 Android 6.0 以下版本,只需要在AndroidManifest.xml
中声明权限即可,从 Android 10 开始,外部存储的访问方式发生了变化,建议使用应用特定的目录(如getExternalFilesDir
)来存储文件,以避免因外部存储的变化而导致的文件丢失问题。