1.首先看一下效果

1.1做成了一个GIF

  Diycode开源项目 ImageActivity分析

 1.2.我用格式工厂有点问题,大小无法调到手机这样的大小,目前还没有解决方案。

 1.3.网上有免费的MP4->GIF,参考一下这个网站吧。 

 1.4.讲解一下这个图片吧,首先是从话题中点击了其中一张图片,进入图片Activity,

   然后可以自由放大,自由翻转。


2.分析一下继承的BaseImageActivity

2.1因为ImageActivity继承了BaseImageActivtiy,首先看看源代码。

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-03-15 20:02:59
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.base.app;

import android.content.Intent;

import java.util.ArrayList;

/**
 * 对数据进行预处理
 */
public abstract class BaseImageActivity extends BaseActivity {
    public static final String ALL_IMAGE_URLS = "all_images";
    public static final String CURRENT_IMAGE_URL = "current_image";

    protected static final String MODE_NORMAL = "normal";
    protected static final String MODE_ERROR = "error";
    protected String mCurrentMode = MODE_NORMAL;

    protected ArrayList<String> images = new ArrayList<>();     // 所有图片
    protected String current_image_url = null;                  // 当前图片
    protected int current_image_position = 0;                  // 当前图片位置

    @Override
    protected void initDatas() {
        super.initDatas();

        // 初始化图片 url 和 图片集合,保证两个数据都存在
        Intent intent = getIntent();

        // 没有传递当前图片,设置模式为错误
        String imageUrl = intent.getStringExtra(CURRENT_IMAGE_URL);
        if (imageUrl == null || imageUrl.isEmpty()) {
            toastShort("没有传递图片链接");
            mCurrentMode = MODE_ERROR;
            return;
        }
        mCurrentMode = MODE_NORMAL;

        ArrayList<String> temp = intent.getStringArrayListExtra(ALL_IMAGE_URLS);
        if (temp == null || temp.size() <= 0) {
            // 记录当前图片,计算位置
            images.clear();
            images.add(imageUrl);
        } else if (temp.size() > 0) {
            // 如果图片集合大于0
            images = new ArrayList<>(temp);
        }

        if (!images.contains(imageUrl)) {
            images.add(imageUrl);
        }

        current_image_url = imageUrl;
        current_image_position = images.indexOf(current_image_url);
    }
}
View Code

2.2这里需要回顾一下BaseActivity。

  BaseActivity==>主要提供了项目本身API提供的Diycode类,ViewHolder类,Toast类,两个抽象方法。ActionBar。结束

当前活动。

    打开活动。

2.3.私有成员变量。

  ·存放图片链接的一个ArrayList<String>

   ·存放当前图片的链接current_image_url

  ·存放当前图片位置,整型current_image_positon

2.4.注意点,Override一个在基类中已经实现过的函数。

  重载,也是可以Override的。以前理解的Override就是抽象方法,接口方法。这里又涨知识了。

  如果写了一个父类中有的方法,就相当于重载了父类中的方法,就不会执行父类中的那个方法,而是执行自己的方法了。

名字是一样的。

2.5.在BaseActivity中写了一个空的initDatas方法。而且规定了这个方法执行的顺序。

  然后在子类BaseImageActivity中重载这个方法。

  这个类主要处理图片数据的。

2.6分析这个重载方法。

  Diycode开源项目 ImageActivity分析

  Diycode开源项目 ImageActivity分析

  2.6.1首先从intent中获得当前图片,如果没有,设置模式为错误。否则,设置模式为正常。

  2.6.2然后从intent中获得所有图片集合,如果没有,就把当前图片加进images去,如果有,就将集合加到一个images中。

  2.6.3然后它还判断了一下images中是否包含了当前url,应该是双保险吧,感觉没必要。

  2.6.4最后,就把当前图片和当前位置更新了一下。


3.分析一下图片缓存DiskImageCache

3.1首先看看在ImageActivity中定义的一个变量。DiskImageCache mCache;源代码如下:

/*
 * Copyright 2017 GcsSloop
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Last modified 2017-03-12 00:56:52
 *
 * GitHub:  https://github.com/GcsSloop
 * Website: http://www.gcssloop.com
 * Weibo:   http://weibo.com/GcsSloop
 */

package com.gcssloop.diycode.base.webview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.os.StatFs;
import android.support.annotation.NonNull;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Comparator;

public class DiskImageCache {
    private static final String CACHE_SUFFIX = ".cache";

    private static final int MB = 1024 * 1024;
    private static final int CACHE_SIZE = 50;   // 缓存占用空间大小
    private static final int FREE_SD_SPACE_NEEDED_TO_CACHE = 10;    // 为 SD 卡保留多少空间

    private File cacheDir;

    public DiskImageCache(Context context) {
        cacheDir = getDiskCacheDir(context, "web-image");
        // 整理缓存
        organizeCache(cacheDir);
    }

    /**
     * 从缓存中获取图片
     **/
    public Bitmap getBitmap(final String key) {
        final String path = getCachePath(key);
        File file = new File(path);
        if (file.exists()) {
            Bitmap bmp = BitmapFactory.decodeFile(path);
            if (bmp == null) {
                file.delete();
            } else {
                updateFileTime(path);
                return bmp;
            }
        }
        return null;
    }

    /**
     * 将图片存入文件缓存
     **/
    public void saveBitmap(String key, Bitmap bm) {
        if (bm == null) {
            return;
        }
        //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            return;     //SD空间不足
        }
        File file = new File(getCachePath(key));
        try {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            bm.compress(Bitmap.CompressFormat.PNG, 100, outStream);
            outStream.flush();
            outStream.close();
        } catch (FileNotFoundException e) {
            Log.w("ImageFileCache", "FileNotFoundException");
        } catch (IOException e) {
            Log.w("ImageFileCache", "IOException");
        }
    }

    /**
     * 保存 bytes 数据
     *
     * @param key   url
     * @param bytes bytes 数据
     */
    public void saveBytes(String key, byte[] bytes) {
        if (bytes == null) {
            return;
        }
        //判断sdcard上的空间
        if (FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            return;     //SD空间不足
        }
        File file = new File(getCachePath(key));
        try {
            file.createNewFile();
            OutputStream outStream = new FileOutputStream(file);
            outStream.write(bytes);
            outStream.flush();
            outStream.close();
        } catch (FileNotFoundException e) {
            Log.w("ImageFileCache", "FileNotFoundException");
        } catch (IOException e) {
            Log.w("ImageFileCache", "IOException");
        }
    }

    /**
     * 获取一个本地缓存的输入流
     *
     * @param key url
     * @return FileInputStream
     */
    public FileInputStream getStream(String key) {
        File file = new File(getCachePath(key));
        if (!file.exists())
            return null;
        try {
            FileInputStream inputStream = new FileInputStream(file);
            return inputStream;
        } catch (FileNotFoundException e) {
            Log.e("getStream", "FileNotFoundException");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取本地缓存路径
     *
     * @param key url
     * @return 路径
     */
    public String getDiskPath(String key) {
        File file = new File(getCachePath(key));
        if (!file.exists())
            return null;
        return file.getAbsolutePath();
    }

    /**
     * 是否有缓存
     *
     * @param key url
     * @return 是否有缓存
     */
    public boolean hasCache(String key) {
        File file = new File(getCachePath(key));
        return file.exists();
    }

    /**
     * 计算存储目录下的文件大小,
     * 当文件总大小大于规定的CACHE_SIZE或者sdcard剩余空间小于FREE_SD_SPACE_NEEDED_TO_CACHE的规定
     * 那么删除40%最近没有被使用的文件
     */
    private boolean organizeCache(@NonNull File cacheDir) {
        File[] files = cacheDir.listFiles();
        if (files == null) {
            return true;
        }
        if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            return false;
        }

        int dirSize = 0;
        for (int i = 0; i < files.length; i++) {
            if (files[i].getName().contains(CACHE_SUFFIX)) {
                dirSize += files[i].length();
            }
        }

        if (dirSize > CACHE_SIZE * MB || FREE_SD_SPACE_NEEDED_TO_CACHE > freeSpaceOnSd()) {
            int removeFactor = (int) ((0.4 * files.length) + 1);
            Arrays.sort(files, new FileLastModifSort());
            for (int i = 0; i < removeFactor; i++) {
                if (files[i].getName().contains(CACHE_SUFFIX)) {
                    files[i].delete();
                }
            }
        }

        if (freeSpaceOnSd() <= CACHE_SIZE) {
            return false;
        }

        return true;
    }

    /**
     * 修改文件的最后修改时间
     **/
    public void updateFileTime(String path) {
        File file = new File(path);
        long newModifiedTime = System.currentTimeMillis();
        file.setLastModified(newModifiedTime);
    }

    /**
     * 计算sdcard上的剩余空间
     **/
    private int freeSpaceOnSd() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double sdFreeMB = ((double) stat.getAvailableBlocks() * (double) stat.getBlockSize()) / MB;
        return (int) sdFreeMB;
    }

    /**
     * 根据文件的最后修改时间进行排序
     */
    private class FileLastModifSort implements Comparator<File> {
        public int compare(File arg0, File arg1) {
            if (arg0.lastModified() > arg1.lastModified()) {
                return 1;
            } else if (arg0.lastModified() == arg1.lastModified()) {
                return 0;
            } else {
                return -1;
            }
        }
    }


    /**
     * 获取缓存文件的绝对路径
     */
    private String getCachePath(String key) {
        return cacheDir.getAbsolutePath() + File.separator + convertKey(key);
    }

    /**
     * 获取磁盘缓存文件夹 优先获取外置磁盘
     *
     * @param context    上下文
     * @param uniqueName 自定义名字
     */
    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();
        }
        File cacheDir = new File(cachePath + File.separator + uniqueName);
        if (!cacheDir.exists())
            cacheDir.mkdir();
        return cacheDir;
    }

    /**
     * 哈希编码
     */
    public String convertKey(String key) {
        String cacheKey;
        try {
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            mDigest.update(key.getBytes());
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey + CACHE_SUFFIX;
    }

    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();
    }

}
View Code

3.2定义的常量及变量预览。

    Diycode开源项目 ImageActivity分析

3.3.构造函数就一个。实现方法在后面。

  Diycode开源项目 ImageActivity分析

3.4.如何从缓存中获取图片(通过一个String返回一个Bitmap),这个项目暂时没有用到。

  Diycode开源项目 ImageActivity分析

3.5.如何将图片存入文件缓存?(将一个bitmap,存放一个缓存路径为一个key下)

  Diycode开源项目 ImageActivity分析

3.6.如何保存bytes数据?(也是存放到一个key中)

  Diycode开源项目 ImageActivity分析

3.7.如何获取一个本地缓存的输入流?(通过一个key获得FileInputStream)

  Diycode开源项目 ImageActivity分析

3.8.如何获取本地缓存路径?(通过一个key得到一个String)

  Diycode开源项目 ImageActivity分析

3.9.如何判断是否有缓存?(通过一个key返回boolean)

  Diycode开源项目 ImageActivity分析

3.10.然后是关键的整理存储空间了。这个删除文件很关键,不然数据会越来越大的。

  Diycode开源项目 ImageActivity分析

  Diycode开源项目 ImageActivity分析

3.11.如何修改文件的最后修改时间?(参数为文件path)

  Diycode开源项目 ImageActivity分析

3.12.如何计算sdcard上的剩余空间?

  Diycode开源项目 ImageActivity分析

3.13.如何根据文件的最后修改时间进行排序?(继承了一个Comparator<File>的内部类)

  Diycode开源项目 ImageActivity分析

  FileLastModifSort其实就是一个类,类中有一个比较的函数,有两个File的参数,比较哪个更加最后而已。

3.14.如何获取缓存文件的绝对路径?(通过key得到一个String)

  Diycode开源项目 ImageActivity分析

3.15.如何获取磁盘缓存文件夹,优先获取外置磁盘?(参数为context和一个string返回一个File)

  Diycode开源项目 ImageActivity分析

3.16.什么是哈希编码?(参数为key返回一个String)

  Diycode开源项目 ImageActivity分析

  通过MD5加密后加了一个后缀为.cache,返回这个字符串。

3.17.bytes数组转化为哈希String?(参数为byte[]返回一个String)

  Diycode开源项目 ImageActivity分析

  这个在3.16.哈希编码中用到了,就是系统函数很多会转化为bytes,这个函数就是将byte[]类型的数据整合成String,

然后再处理逻辑。

  这个DiskImageCache比较长,主要处理的就是一些缓存问题了,图片缓存,和本地的存储器挂钩了,所以就有很多函数

要调用。

相关文章:

  • 2021-05-18
  • 2021-08-21
  • 2022-02-09
  • 2021-11-21
  • 2022-01-27
  • 2021-08-08
  • 2021-07-02
  • 2021-05-13
猜你喜欢
  • 2021-06-17
  • 2021-12-03
  • 2021-08-10
  • 2022-02-10
  • 2021-05-24
  • 2021-05-23
  • 2022-02-20
相关资源
相似解决方案