三级缓存,先在内存Lrucache中查找缓存,没有就去外存DiskLrucache中查找,再没有就下载,Lru不会自动删除,所以要设置最大缓存内存,后台运行Lrucache不会消失,关闭程序Disklrucache不会消失.代码有点乱,但还是可以用的
public class MainActivity extends AppCompatActivity { private GridView gv_photo; PhotoWall photoWall; ImageView imageView; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.image); photoWall = new PhotoWall(); } @Override protected void onPause() { super.onPause(); photoWall.flushCache(); } @Override protected void onDestroy() { super.onDestroy(); photoWall.cancelTask(); } @Override protected void onStart() { super.onStart(); photoWall.getView(); } public class PhotoWall { // 声明LruCache缓存对象 private LruCache<String, Bitmap> lruCache; // 声明DiskLruCache硬盘缓存对象 private DiskLruCache diskLruCache; // 任务队列 private Set<LoadImageAsync> tasks; // 声明GridView对象 private GridView gridView; ImageView imageView; public PhotoWall() { this.gridView = gridView; tasks = new HashSet<LoadImageAsync>(); /** * 初始化内存缓存LruCache */ // 获取应用程序最大可占内存值 int maxMemory = (int) Runtime.getRuntime().maxMemory(); // 设置最大内存的八分之一作为缓存大小 int lruMemory = maxMemory / 8; lruCache = new LruCache<String, Bitmap>(lruMemory) { @Override protected int sizeOf(String key, Bitmap bitmap) { // 返回Bitmap对象所占大小,单位:kb return bitmap.getByteCount(); } }; /** * 初始化硬盘缓存DiskLruCahce */ // 获取硬盘缓存路径,参数二为所在缓存路径的文件夹名称 File directory = getDiskCacheDir(getApplicationContext(), "aaa"); if (!directory.exists()) { // 若文件夹不存在,建立文件夹 directory.mkdirs(); } int appVersion = getAppVersion(getApplicationContext()); try { // 参数1:缓存文件路径,参数2:系统版本号,参数3:一个缓存路径对于几个文件,参数4:缓存空间大小:字节 diskLruCache = DiskLruCache.open(directory, appVersion, 1, 1024 * 1024 * 10); } catch (IOException e) { e.printStackTrace(); } } /** * @param context * @param uniqueName * @return * 当SD卡存在或者SD卡不可被移除的时候,就调用getExternalCacheDir()方法来获取缓存路径,否则就调用getCacheDir * ()方法来获取缓存路径。 前者获取到的就是 /sdcard/Android/data/<application * package>/cache 这个路径 而后者获取到的是 datadata/application package>/cache * 这个路径。 */ public File getDiskCacheDir(Context context, String uniqueName) { String cachePath; if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) || !Environment.isExternalStorageRemovable()) { cachePath = context.getExternalCacheDir().getPath(); } else { cachePath = context.getCacheDir().getPath(); } return new File(cachePath + File.separator + uniqueName); } /** * @param context * @return 获取系统版本号 */ public int getAppVersion(Context context) { try { PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); return info.versionCode; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } return 1; } public View getView() { // 获取图片资源URL地址 String path ="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2548029202,3494755824&fm=27&gp=0.jpg"; // 获取控件实例 imageView = findViewById(R.id.image); // 设置一个唯一标识符,避免异步加载图片时错位 // imageView.setTag(path); // 设置默认图片 imageView.setImageResource(R.drawable.icon12); // 根据图片URL到缓存中去找图片资源并设置 setImageFromLruCache(path, imageView); return imageView; } /** * 根据图片URL地址获取缓存中图片,若不存在去磁盘缓存中查找=》网络下载 * * @param path * @param imageView */ private void setImageFromLruCache(String path, ImageView imageView) { Bitmap bitmap = lruCache.get(path); if (bitmap != null) { // 缓存存在,取出设置图片 Log.i("PhotoWallAdapter", "在内存缓存中找到"); imageView.setImageBitmap(bitmap); } else { // 缓存不存在,先找硬盘缓存,还不存在,就去网络下载(开启异步任务) LoadImageAsync loadImageAsync = new LoadImageAsync(); loadImageAsync.execute(path); // 添加任务到任务队列 tasks.add(loadImageAsync); } } /** * 取消队列中准备下载和正在下载的任务 */ public void cancelTask() { for (LoadImageAsync task : tasks) { task.cancel(false); } } /** * 同步内存操作到journal文件 */ public void flushCache() { if (diskLruCache != null) { try { diskLruCache.flush(); } catch (IOException e) { e.printStackTrace(); } } } class LoadImageAsync extends AsyncTask<String, Void, Bitmap> { // 图片资源URL String path = null; @Override protected Bitmap doInBackground(String... params) { // 图片下载地址 this.path = params[0]; DiskLruCache.Snapshot snapshot = null; OutputStream outputStream = null; Bitmap bitmap = null; // String pathMd5 = MD5Utils.md5(path); String key = hashKeyForDisk(path); // 根据图片url(md5)查找图片资源是否存在于硬盘缓存 try { snapshot = diskLruCache.get(key); if (snapshot == null) { // 在磁盘缓存中没有找到图片资源 // 获取一个DiskLruCache写入对象 DiskLruCache.Editor editor = diskLruCache.edit(key); if (editor != null) { outputStream = editor.newOutputStream(0); // 开启异步网络任务获取图片,并存入磁盘缓存 if (downloadUrlToStream(path, outputStream)) { // 下载成功 Log.i("PhotoWallAdapter", "下载文件成功"); editor.commit(); } else { editor.abort(); } } } // 图片写入磁盘缓存后,再一次的查找磁盘缓存 snapshot = diskLruCache.get(key); if (snapshot != null) { // 若查找到,获取图片,并把图片资源写入内存缓存 bitmap = BitmapFactory.decodeStream(snapshot.getInputStream(0)); Log.i("PhotoWallAdapter", "在磁盘缓存中找到"); } if (bitmap != null) { // 将Bitmap对象添加到内存缓存当中 lruCache.put(path, bitmap); } return bitmap; } catch (IOException e) { e.printStackTrace(); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); // 根据Tag获取控件对象并设置图片 // ImageView imageView = (ImageView) gridView.findViewWithTag(path); if (imageView != null && bitmap != null) { // 加载图片 imageView.setImageBitmap(bitmap); } tasks.remove(this); } /** * 根据图片URL地址下载图片,成功返回true,失败false * * @param urlString * @param outputStream * @return */ private boolean downloadUrlToStream(String urlString, OutputStream outputStream) { HttpURLConnection urlConnection = null; BufferedOutputStream out = null; BufferedInputStream in = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024); out = new BufferedOutputStream(outputStream, 8 * 1024); int b; while ((b = in.read()) != -1) { out.write(b); } return true; } catch (final IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (final IOException e) { e.printStackTrace(); } } return false; } } public String hashKeyForDisk(String key) { String cacheKey; try { final MessageDigest mDigest = MessageDigest.getInstance("MD5");//把uri编译为MD5,防止网址有非法字符 mDigest.update(key.getBytes()); cacheKey = bytesToHexString(mDigest.digest()); } catch (NoSuchAlgorithmException e) { cacheKey = String.valueOf(key.hashCode()); } return cacheKey; } private String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); } } }
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:id="@+id/line1" android:orientation="vertical" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="200dp" /> </LinearLayout>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:hardwareAccelerated="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application>