Android资产:我应该使用多少加载线程?
我正在从我的Android资产:我应该使用多少加载线程?,android,multithreading,assets,Android,Multithreading,Assets,我正在从我的资源/在后台加载位图。 我在网上找到了一些解决方案,但它们为每幅图像都启动了一个新的背景任务 因为我发现它更容易理解,所以我将它改为只有一个加载线程,带有生产者/消费者模式。我对UI线程的请求使用BlockingQueues,并publishProgress进行响应 我的解决方案工作得很好,但它让我怀疑如果我使用多个线程是否会更好。我的代码支持请求失效,但它总是在处理新请求之前完成当前的加载 另一方面:线程不竞争磁盘访问吗 我的代码: package org.example; im
资源/
在后台加载位图。
我在网上找到了一些解决方案,但它们为每幅图像都启动了一个新的背景任务
因为我发现它更容易理解,所以我将它改为只有一个加载线程,带有生产者/消费者模式。我对UI线程的请求使用BlockingQueue
s,并publishProgress
进行响应
我的解决方案工作得很好,但它让我怀疑如果我使用多个线程是否会更好。我的代码支持请求失效,但它总是在处理新请求之前完成当前的加载
另一方面:线程不竞争磁盘访问吗
我的代码:
package org.example;
import android.content.ContextWrapper;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Pair;
import android.widget.ImageView;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.PriorityBlockingQueue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ImageLoader extends AsyncTask<Void, Pair<ImageLoader.SetImageTask, Bitmap>, Void> {
//~ Static fields/initializers -------------------------------------------------------------------------------------
private static final Logger L = LoggerFactory.getLogger(ImageLoader.class);
//~ Instance fields ------------------------------------------------------------------------------------------------
private final Map<String, Bitmap> cache = Maps.newHashMap();
private final ContextWrapper contextWrapper;
private final PriorityBlockingQueue<LoadTask> loadTasks =
new PriorityBlockingQueue<ImageLoader.LoadTask>(1, Ordering.arbitrary());
/* is changed to invalidate tasks */
private String uuid = null;
//~ Constructors ---------------------------------------------------------------------------------------------------
public ImageLoader(final ContextWrapper contextWrapper) {
this.contextWrapper = contextWrapper;
this.uuid = UUID.randomUUID().toString();
}
//~ Methods --------------------------------------------------------------------------------------------------------
public void invalidateTasks() {
L.debug("invalidating tasks");
this.uuid = UUID.randomUUID().toString();
}
public void setImage(final ImageView view, final String asset) {
this.loadTasks.add(new SetImageTask(this.uuid, view, asset));
}
public void loadIntoCache(final ImmutableList<String> assets) {
for (final String asset : assets) {
this.loadTasks.add(new LoadIntoCacheTask(asset));
}
}
@SuppressWarnings("unchecked")
@Override
protected Void doInBackground(Void... param) {
try {
while (true) {
LoadTask task = this.loadTasks.take();
if (task instanceof SetImageTask) {
SetImageTask setImageTask = (SetImageTask) task;
if (setImageTask.uuid.equals(this.uuid)) {
Bitmap bitmap = this.loadAsset(setImageTask.asset);
if (bitmap != null) {
this.publishProgress(Pair.create(setImageTask, bitmap));
}
} else {
L.debug("request for asset '{}' outdated", setImageTask.asset);
}
} else {
LoadIntoCacheTask cacheTask = (LoadIntoCacheTask) task;
Bitmap bitmap = this.loadAsset(cacheTask.asset);
L.debug("storing in cache: '{}'", cacheTask.asset);
cache.put(cacheTask.asset, bitmap);
}
}
} catch (final InterruptedException e) {
L.debug("interrupted -> exiting");
}
return null;
}
@Override
protected void onProgressUpdate(Pair<SetImageTask, Bitmap>... results) {
Pair<SetImageTask, Bitmap> result = results[0];
if (result.first.uuid.equals(this.uuid)) {
result.first.view.setImageBitmap(result.second);
} else {
L.debug("request for asset '{}' outdated", result.first.asset);
}
}
private Bitmap loadAsset(final String asset) {
if (this.cache.containsKey(asset)) {
L.debug("serving from cache '{}'", asset);
return this.cache.get(asset);
} else {
L.debug("loading from assets: '{}'", asset);
InputStream in = null;
Bitmap bitmap = null;
try {
in = new BufferedInputStream(contextWrapper.getAssets().open(asset));
bitmap = BitmapFactory.decodeStream(in);
} catch (final IOException e) {
L.error(e.getMessage(), e);
} finally {
try {
in.close();
} catch (final IOException e) {}
}
return bitmap;
}
}
//~ Inner Interfaces -----------------------------------------------------------------------------------------------
protected static interface LoadTask {}
//~ Inner Classes --------------------------------------------------------------------------------------------------
protected static final class SetImageTask implements LoadTask {
private final String uuid;
private final ImageView view;
private final String asset;
public SetImageTask(final String uuid, final ImageView view, final String asset) {
this.uuid = uuid;
this.view = view;
this.asset = asset;
}
}
protected static final class LoadIntoCacheTask implements LoadTask {
private final String asset;
public LoadIntoCacheTask(final String asset) {
this.asset = asset;
}
}
}
package org.example;
导入android.content.ContextWrapper;
导入android.graphics.Bitmap;
导入android.graphics.BitmapFactory;
导入android.os.AsyncTask;
导入android.util.Pair;
导入android.widget.ImageView;
导入com.google.common.collect.ImmutableList;
导入com.google.common.collect.Maps;
导入com.google.common.collect.Ordering;
导入java.io.BufferedInputStream;
导入java.io.IOException;
导入java.io.InputStream;
导入java.util.Map;
导入java.util.UUID;
导入java.util.concurrent.PriorityBlockingQueue;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
公共最终类ImageLoader扩展异步任务{
//~静态字段/初始值设定项-------------------------------------------------------------------------------------
私有静态最终记录器L=LoggerFactory.getLogger(ImageLoader.class);
//~实例字段------------------------------------------------------------------------------------------------
私有最终映射缓存=Maps.newHashMap();
私有最终ContextWrapper ContextWrapper;
私有最终优先级阻止队列加载任务=
新的PriorityBlockingQueue(1,Ordering.arbitral());
/*更改为使任务无效*/
私有字符串uuid=null;
//~z~施工人员---------------------------------------------------------------------------------------------------
公共图像加载器(最终上下文包装器){
this.contextWrapper=contextWrapper;
this.uuid=uuid.randomUUID().toString();
}
//~方法--------------------------------------------------------------------------------------------------------
公共无效无效tasks(){
L.调试(“使任务失效”);
this.uuid=uuid.randomUUID().toString();
}
public void setImage(最终图像视图,最终字符串资源){
this.loadTasks.add(新的SetImageTask(this.uuid,view,asset));
}
public void loadIntoCache(最终不可变列表资产){
for(最终字符串资产:资产){
this.loadTasks.add(新的LoadIntoCacheTask(资产));
}
}
@抑制警告(“未选中”)
@凌驾
受保护的Void doInBackground(Void…参数){
试一试{
while(true){
LoadTask=this.loadTasks.take();
if(SetImageTask的任务实例){
SetImageTask SetImageTask=(SetImageTask)任务;
if(setImageTask.uuid.equals(this.uuid)){
位图位图=this.loadAsset(setImageTask.asset);
if(位图!=null){
this.publishProgress(Pair.create(setImageTask,位图));
}
}否则{
L.debug(“请求资产{}过时”,setImageTask.asset);
}
}否则{
LoadIntoCacheTask cacheTask=(LoadIntoCacheTask)任务;
位图位图=this.loadAsset(cacheTask.asset);
debug(“存储在缓存中:{}”,cacheTask.asset);
cache.put(cacheTask.asset,位图);
}
}
}捕获(最终中断异常e){
L.调试(“中断->退出”);
}
返回null;
}
@凌驾
受保护的void onProgressUpdate(成对…结果){
配对结果=结果[0];
if(result.first.uuid.equals(this.uuid)){
result.first.view.setImageBitmap(result.second);
}否则{
L.debug(“请求资产{}过时”,result.first.asset);
}
}
私有位图加载资源(最终字符串资源){
if(this.cache.containsKey(资产)){
L.debug(“从缓存“{}”服务,资产);
返回此.cache.get(资产);
}否则{
L.debug(“从资产加载:{}”,资产);
InputStream in=null;
位图=空;
试一试{
in=new BufferedInputStream(contextWrapper.getAssets().open(asset));
位图=BitmapFactory.decodeStream(in);
}捕获(最终IOE例外){
L.错误(如getMessage(),e);
}最后{
试一试{
in.close();
}捕获(最终IOE){}
}
返回位图;
}
}
//~内部接口-----------------------------------------------------------------------------------------------
受保护的静态接口LoadTask{}
//~z~内部阶级--------------------------------------------------------------------------------------------------
受保护的静态最终类SetImageTask实现LoadTask{
私有最终字符串uuid;
私有最终图像视图;
私人最终资产;
公共SetImageTask(最终字符串uuid、最终图像视图、最终字符串资源){
this.uuid=uuid;
this.view=视图;
这个资产=资产;
}
}
受保护的静态最终类LoadI