线程池 - 结合Glide下载图片
下面开启线程池下载图片到SD:
下载图片耗时,所以开启线程下载,利用接口获取下载成功/失败状态和操作。
此处采用线程池:控制应用中处理某项业务中防止高并发问题带来的线程不安全的发生的概率。
1、新建DownloadCallBack接口(DownloadCallBack.interface):下载成功/失败函数
public interface DownloadCallBack {
void onDownloadSuccess(File file);
void onDownloadFailed();
}
2、新建图片下载线程类,继承Thread或实现Runnable(DownLoadImageService.java ):
public class DownLoadImageService implements Runnable {
private String url;
private Context context;
private DownloadCallBack downloadCallBack;
static ExecutorService singleExcutor;
//1、使用时先讲参数通过构造函数传进来,并实现接口函数,返回这个Runnable对象,可看完再理解这句话
public DownLoadImageService(String url, Context context, DownloadCallBack downloadCallBack) {
this.url = url;
this.context = context;
this.downloadCallBack = downloadCallBack;
}
//2、调用DownLoadImageService.runOnQueue(Runnable对象) 开始下载
public static void runOnQueue(Runnable runnable) {
//线程池:采用单线程化的线程池,线程FIFO执行
singleExcutor = null;
if (singleExcutor == null) {
//正常线程池线程数量
int corePoolSize = 1;
//最大线程池线程数量
int maxPoolSize = 1;
//等待时间
long keepAliveTime = 200;
//等待队列
ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(1);
singleExcutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, workQueue);
}
singleExcutor.submit(runnable);
}
}
@Override
public void run() {
File file = null;
try {
file = Glide.with(context)
.asFile()
.load(url)
.submit()
.get();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (file != null) {
downloadCallBack.onDownloadSuccess(file);
} else {
downloadCallBack.onDownloadFailed();
}
//关闭线程池
singleExcutor.shutdown();
}
}
3、在自己的类里调用
- 提前写了一个拷贝文件的工具类(FileUtil.java)
public class FileUtil {
/**
* 复制文件
*
* @param sourceFile 源文件
* @param targetFile 输出文件
*/
public static void copyFile(File sourceFile, File targetFile) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(targetFile);
byte[] buffer = new byte[1024];
while (fis.read(buffer) > 0) {
fos.write(buffer);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 复制文件
*
* @param bytes 源文件字节
* @param targetFile 输出文件
*/
public static void copyByBytes(byte[] bytes, File targetFile) {
FileOutputStream output;
try {
output = new FileOutputStream(targetFile);
output.write(bytes);
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 先动态申请写SD的权限(GlideTest.java)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
private boolean checksdpermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
return true;
}
return false;
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//R.id.btn_submit是我自定义的下载button
loadWithSubmit(findViewById(R.id.btn_submit));
} else {
Toast.makeText(this, "授权才能保存图片", Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
- 创建本地文件开始下载(GlideTest.java)
public void loadWithSubmit(final View view) {
if (checksdpermission()) {
DownLoadImageService service = new DownLoadImageService(gifUrl, this, new DownloadCallBack() {
@Override
public void onDownloadSuccess(File file) {
//创建本地图片文件保存
File DCIMdir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsoluteFile();
if (!DCIMdir.exists()) {
DCIMdir.mkdir();
}
String fileName = System.currentTimeMillis() + ".gif";
File targetFile = new File(DCIMdir, fileName);
// FileUtil.copyFile()是自己写的工具类,将下载的图片文件写到本地图片文件
FileUtil.copyFile(file, targetFile);
Snackbar.make(view, "图片已保存。\n" + targetFile.getPath(), Snackbar.LENGTH_SHORT).show();
//通知图库更新
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
Uri.fromFile(new File(targetFile.getParent()))));
}
@Override
public void onDownloadFailed() {
Toast.makeText(GlideTest.this, "图片保存失败。\n",
Toast.LENGTH_SHORT).show();
}
});
//启动下载
DownLoadImageService.runOnQueue(service);
}
}
小总结:
获取权限
-> 创建DownLoadImageService对象service,并实现参数中的DownloadCallBack接口中的函数
-> 调用DownLoadImageService.runOnQueue(service)
-> runOnQueue创建线程池singleExcutor,并singleExcutor.submit(runnable)
-> 自动run()
-> run()中Glide下载成功或失败会执行刚实现的接口函数,实现拷贝文件到SD等操作