我正在使用Picasso在我的Android应用中显示图像:
/**
* load image.This is within a activity so this context is activity
*/
public void loadImage (){
Picasso picasso = Picasso.with(this);
picasso.setDebugging(true);
picasso.load(quiz.getImageUrl()).into(quizImage);
}
我已启用调试,它始终显示红色和绿色。但从不显示黄色
现在如果我下次加载相同的图像并且互联网不可用,则不会加载图像。
问题:
答案 0 :(得分:220)
这就是我所做的。效果很好。
首先将OkHttp添加到app模块的gradle构建文件中:
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.okhttp3:okhttp:3.10.0'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
然后创建一个扩展Application
import android.app.Application;
import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;
public class Global extends Application {
@Override
public void onCreate() {
super.onCreate();
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE));
Picasso built = builder.build();
built.setIndicatorsEnabled(true);
built.setLoggingEnabled(true);
Picasso.setSingletonInstance(built);
}
}
将其添加到Manifest文件中,如下所示:
<application
android:name=".Global"
.. >
</application>
现在像往常一样使用毕加索。没有变化。
修改强>
如果您只想使用缓存图像。像这样调用库。我注意到,如果我们不添加networkPolicy,那么图片在完全离线的开始中就不会显示,即使它们已被缓存 。下面的代码解决了这个问题。
Picasso.with(this)
.load(url)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView);
编辑#2
上面代码的问题是,如果你清除缓存,Picasso将继续在缓存中离线查找并失败,下面的代码示例查看本地缓存,如果没有找到离线,它会联机并补充缓存
Picasso.with(getActivity())
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
//Try again online if cache failed
Picasso.with(getActivity())
.load(posts.get(position).getImageUrl())
.error(R.drawable.header)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
}
@Override
public void onError() {
Log.v("Picasso","Could not fetch image");
}
});
}
});
答案 1 :(得分:45)
1)第一个问题的回答: 根据{{3}}
使用with()返回的全局默认Picasso实例会自动使用适合大多数实现的默认值进行初始化。
- LRU内存缓存可用应用程序RAM的15%
- 2%存储空间的磁盘缓存高达50MB但不低于5MB。
但 Disk Cache
全局默认毕加索的操作仅适用于API 14 +
2)第二个问题的回答:Picasso
使用HTTP
客户请求Disk Cache
操作所以你可以使你的自己http request header
的财产Cache-Control
与max-age
并使用
1] Picasso Doc for With() method(注意:仅适用于API 13+)
2] HttpResponseCache(适用于所有API)
OkHttpClient
创建自己的静态毕加索课程的示例:
首先创建一个新类来获取自己的单例picasso
对象
import android.content.Context;
import com.squareup.picasso.Downloader;
import com.squareup.picasso.OkHttpDownloader;
import com.squareup.picasso.Picasso;
public class PicassoCache {
/**
* Static Picasso Instance
*/
private static Picasso picassoInstance = null;
/**
* PicassoCache Constructor
*
* @param context application Context
*/
private PicassoCache (Context context) {
Downloader downloader = new OkHttpDownloader(context, Integer.MAX_VALUE);
Picasso.Builder builder = new Picasso.Builder(context);
builder.downloader(downloader);
picassoInstance = builder.build();
}
/**
* Get Singleton Picasso Instance
*
* @param context application Context
* @return Picasso instance
*/
public static Picasso getPicassoInstance (Context context) {
if (picassoInstance == null) {
new PicassoCache(context);
return picassoInstance;
}
return picassoInstance;
}
}
使用您自己的单身picasso
对象而不是Picasso.With()
PicassoCache.getPicassoInstance(getContext()).load(imagePath).into(imageView)
3)回答第三个问题:磁盘缓存操作不需要任何磁盘权限
参考文献:OkHttpClient,Github issue about disk cache已回答了两个问题 - &gt; @jake-wharton和Question1
答案 2 :(得分:21)
对于缓存,我会使用OkHttp 拦截器来控制缓存策略。查看OkHttp库中包含的此示例。
RewriteResponseCacheControl.java
以下是我与毕加索一起使用的方法 -
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.networkInterceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder().header("Cache-Control", "max-age=" + (60 * 60 * 24 * 365)).build();
}
});
okHttpClient.setCache(new Cache(mainActivity.getCacheDir(), Integer.MAX_VALUE));
OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
Picasso picasso = new Picasso.Builder(mainActivity).downloader(okHttpDownloader).build();
picasso.load(imageURL).into(viewHolder.image);
答案 3 :(得分:6)
1)毕加索默认有缓存(见ahmed hamdy回答)
2)如果你真的必须从磁盘缓存然后网络中获取图像,我建议你自己编写下载器:
public class OkHttpDownloaderDiskCacheFirst extends OkHttpDownloader {
public OkHttpDownloaderDiskCacheFirst(OkHttpClient client) {
super(client);
}
@Override
public Response load(Uri uri, int networkPolicy) throws IOException {
Response responseDiskCache = null;
try {
responseDiskCache = super.load(uri, 1 << 2); //NetworkPolicy.OFFLINE
} catch (Exception ignored){} // ignore, handle null later
if (responseDiskCache == null || responseDiskCache.getContentLength()<=0){
return super.load(uri, networkPolicy); //user normal policy
} else {
return responseDiskCache;
}
}
}
在OnCreate方法的应用程序单例中,将它与picasso一起使用:
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setCache(new Cache(getCacheDir(), 100 * 1024 * 1024)); //100 MB cache, use Integer.MAX_VALUE if it is too low
OkHttpDownloader downloader = new OkHttpDownloaderDiskCacheFirst(okHttpClient);
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(downloader);
Picasso built = builder.build();
Picasso.setSingletonInstance(built);
3)defalut应用程序缓存文件夹
无需权限答案 4 :(得分:2)
我不知道该解决方案有多好,但绝对是容易 一个,我刚刚在我的应用中使用过,并且运行正常
您这样加载图像
select id,
(sum(datediff(second, start_time, end_time) -
datediff(second, min(start_time), max(end_time)
) as overlap
from t
group by id;
您可以像这样获得join
import asyncio
@asyncio.coroutine
def async_copyfile(src, dst):
yield shutil.copyfile(src, dst)
def generate_tasks():
goo_dst = '/home/usr2/Pictures/GOO'
amz_dst = '/home/usr2/Pictures/AMZ'
os.makedirs(goo_dst,exist_ok=1)
os.makedirs(amz_dst,exist_ok=1)
for root, dirs, files in os.walk('/'):
for name in files:
path = os.path.join(root, name)
if name.startswith('GOO_') and (name.endswith('.jpg') or name.endswith('.jpeg') or name.endswith('.png')):
yield (path, goo_dst)
elif name.startswith('AMZ_') and name.endswith('.jpg'):
yield (path, amz_dst)
loop = asyncio.get_event_loop()
tasks = [asyncio.ensure_future(async_copyfile(src, dst)) for src, dst in generate_tasks()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
现在将public void loadImage (){
Picasso picasso = Picasso.get();
picasso.setIndicatorsEnabled(true);
picasso.load(quiz.getImageUrl()).into(quizImage);
}
转换为bimap
文件并存储在缓存中,下面是获取bimap并将其缓存的完整代码
Bitmap bitmap = Picasso.get().load(quiz.getImageUrl()).get();
出于某种原因需要在单独的线程上调用Bitmap
的{{1}}方法,我也将该图像保存在同一线程上。
保存图像后,您可以获取所有类似的文件
JPG
现在您可以在下面找到所需的文件
Thread thread = new Thread() {
public void run() {
File file = new File(getCacheDir() + "/" +member.getMemberId() + ".jpg");
try {
Bitmap bitmap = Picasso.get().load(uri).get();
FileOutputStream fOut = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100,new FileOutputStream(file));
fOut.flush();
fOut.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
})
答案 5 :(得分:0)
我使用此代码并且有效,可能对您有用:
public static void makeImageRequest(final View parentView,final int id, final String imageUrl) {
final int defaultImageResId = R.mipmap.user;
final ImageView imageView = (ImageView) parentView.findViewById(id);
Picasso.with(context)
.load(imageUrl)
.networkPolicy(NetworkPolicy.OFFLINE)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.v("Picasso","fetch image success in first time.");
}
@Override
public void onError() {
//Try again online if cache failed
Log.v("Picasso","Could not fetch image in first time...");
Picasso.with(context).load(imageUrl).networkPolicy(NetworkPolicy.NO_CACHE)
.memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE).error(defaultImageResId)
.into(imageView, new Callback() {
@Override
public void onSuccess() {
Log.v("Picasso","fetch image success in try again.");
}
@Override
public void onError() {
Log.v("Picasso","Could not fetch image again...");
}
});
}
});
}
答案 6 :(得分:0)
在/**
Reset the default state of the buttons
*/
func resetButtonStates() {
for button in [YOUR_BUTTON_ARRAY_VARIABLE_HERE] {
button.isSelected = false
button.setTitleColor(UIColor.gray, for: .normal)
}
}
func buttonPressed(sender:AnyObject) {
guard let button = sender as? UIButton else { return }
// Check wether the button is selected already, to be used as mentioned below
let isAlreadySelected = sender.isSelected == true
// Reset the default state to all the buttons
resetButtonStates()
// Now update the button state of the selected button alone if its not selected already
if !isAlreadySelected {
button.isSelected = true
button.setTitleColor(UIColor.black, for: .normal)
} else {
// Do Nothing since as per your case if you selected the already selected button it should change to disable right, so the resetButtonStates() will do that.
}
}
中添加跟随代码,然后正常使用
Application.onCreate
如果您先缓存图像,请在 Picasso picasso = new Picasso.Builder(context)
.downloader(new OkHttp3Downloader(this,Integer.MAX_VALUE))
.build();
picasso.setIndicatorsEnabled(true);
picasso.setLoggingEnabled(true);
Picasso.setSingletonInstance(picasso);
ProductImageDownloader.doBackground
并像正常或使用磁盘缓存一样加载图像
final Callback callback = new Callback() {
@Override
public void onSuccess() {
downLatch.countDown();
updateProgress();
}
@Override
public void onError() {
errorCount++;
downLatch.countDown();
updateProgress();
}
};
Picasso.with(context).load(Constants.imagesUrl+productModel.getGalleryImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
Picasso.with(context).load(Constants.imagesUrl+productModel.getLeftImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
Picasso.with(context).load(Constants.imagesUrl+productModel.getRightImage())
.memoryPolicy(MemoryPolicy.NO_CACHE).fetch(callback);
try {
downLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(errorCount == 0){
products.remove(productModel);
productModel.isDownloaded = true;
productsDatasource.updateElseInsert(productModel);
}else {
//error occurred while downloading images for this product
//ignore error for now
// FIXME: 9/27/2017 handle error
products.remove(productModel);
}
errorCount = 0;
downLatch = new CountDownLatch(3);
if(!products.isEmpty() /*&& testCount++ < 30*/){
startDownloading(products.get(0));
}else {
//all products with images are downloaded
publishProgress(100);
}
注意:
红色颜色表示图片是从网络获取的。
绿色颜色表示图片是从缓存中提取的。
蓝色颜色表示图片是从磁盘内存获取的。
在发布应用程序之前,删除或设置 Picasso.with(this).load(Constants.imagesUrl+batterProduct.getGalleryImage())
.networkPolicy(NetworkPolicy.OFFLINE)
.placeholder(R.drawable.GalleryDefaultImage)
.error(R.drawable.GalleryDefaultImage)
.into(viewGallery);
false
,picasso.setLoggingEnabled(true);
(如果不需要)。 Thankx
答案 7 :(得分:0)
对于最新版本2.71828 这些是您的答案。
第一季度:它没有本地磁盘缓存吗?
A1 :毕加索中有默认的缓存,请求流就是这样
App -> Memory -> Disk -> Server
无论他们何时遇到他们的图像,他们都会使用该图像,然后停止请求流。 响应流程如何?不用担心,这是这里。
Server -> Disk -> Memory -> App
默认情况下,它们将首先存储到本地磁盘中以作为扩展保留缓存。然后是内存,用于缓存的实例使用。
通过启用此功能,您可以使用毕加索中的内置指示器查看图像的形成位置。
Picasso.get().setIndicatorEnabled(true);
它将在图片的左上角显示一个标志。
第二季度:如何启用磁盘缓存,因为我将多次使用同一图像?
A2 :您不必启用它。这是默认设置。
您需要做的是禁用,当您希望图像始终保持新鲜时。有两种禁用缓存的方式。
.memoryPolicy()
设置为 NO_CACHE 和/或 NO_STORE ,流程将如下所示。NO_CACHE 将跳过从内存中查找图像。
App -> Disk -> Server
NO_STORE 在第一次加载图像时会跳过将图像存储在内存中。
Server -> Disk -> App
.networkPolicy()
设置为 NO_CACHE 和/或 NO_STORE ,流程将如下所示。NO_CACHE 将跳过从磁盘查找图像。
App -> Memory -> Server
NO_STORE 将在第一次加载图像时跳过磁盘中的存储图像。
Server -> Memory -> App
对于完全不缓存图像,您都不能禁用。这是一个例子。
Picasso.get().load(imageUrl)
.memoryPolicy(MemoryPolicy.NO_CACHE,MemoryPolicy.NO_STORE)
.networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE)
.fit().into(banner);
完全没有缓存和没有存储的流程如下所示。
App -> Server //Request
Server -> App //Response
因此,您可能还需要这样做以最大程度地减少应用程序的存储使用量。
第3季度:我需要向Android清单文件添加一些磁盘权限吗?
A3 :否,但不要忘记为HTTP请求添加INTERNET权限。
答案 8 :(得分:-2)
我遇到了同样的问题并使用了Glide库。缓存是开箱即用的。 https://github.com/bumptech/glide