• 图片、缓存Android仿人人客户端(v5.7.1)——对从服务器端(网络)获取的图片进行本地双缓存处理(编码实现)by小雨


    废话就不多说了,开始。。。

              转载请表明出处:http://blog.csdn.net/android_ls/article/details/8797740

               明声:常有人说,能把杂复的情事,用最简略艰深式方向大家描述清晰,此乃“牛人”或称“师大别级”。我自知离那个别级还差很远。因此,我宣布的仿人人Android客户端系列博文,是与有定一Andoird基础知识的友人来分享的。

               这篇是基于上一篇Android仿人人客户端(v5.7.1)——对从服务器端(络网)得获的图片行进地本双缓存理处(流程图或活动图)来行进讲授,没看过的可以先浏览下上一篇博文,其实我个人得觉图片双缓存理处这块,一张流程图已足以明说一切。至于码编现实,不同的人有不同的现实式方,面下我就和大家聊一聊我的现实式方:

        一、图片双缓存理处,类图如下:

        

        二、络网图片地本双缓存的码编现实(以得获户用图像为例):

               1、出发要需表现户用图像的请求

    String headUrl = user.getHeadurl();
                            LogUtil.i(TAG, "headUrl = " + user.getHeadurl());
                           
                            // 户用图像的巨细48x48,单位为dip,转换为px
                            int widthPx = DensityUtil.dip2px(mContext, 48);
                            
                            // 要一张角圆高量质的图片
                            ImageInfo imgInfo = new ImageInfo(mLeftPanelLayout.ivUserIcon, headUrl, widthPx, widthPx, true, false);
                            mImageLoader.displayImage(imgInfo);

                注:mLeftPanelLayout.ivUserIcon为ImageView;ImageInfo对象封装了图片请求参数。

                2、根据URL从存内缓存中得获Bitmap对象,找到了Bitmap对象,用ImageView对象表现图像,到这里止终。

    Bitmap bitmap = memoryCache.get(url);
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap);
            }

               注:memoryCache是MemoryCache(存内缓存类)的对象引用。

                3 、没有从缓存中找到了Bitmap对象,则根据URL从文件缓存中得获File对象,将File对象解码(剖析)成Bitmap对象,用ImageView对象表现户用图像,到这里止终。

    final File file = fileCache.getFile(url);
                if(file.exists()){
                    String pathName = file.getAbsolutePath();
                    System.out.println("pathName = " + pathName);
                    System.out.println("file.length() = " + file.length());
                    
                    bitmap = BitmapFactory.decodeFile(pathName);
                    imageView.setImageBitmap(bitmap);
                }

               注:fileCache为文件缓存类的引用             

                4、没有从文件缓存中找到File对象,则开启络网请求务业线程。

    // 开启线程加载图片
                    try {
                        AsyncBaseRequest asyncRequest = new AsyncHttpGet(url, null, null, new ResultCallback() {
    
                            @Override
                            public void onSuccess(Object obj) {
                                
                            }
    
                            @Override
                            public void onFail(int errorCode) {
                                System.out.println("Loading image error. errorCode = " + errorCode);
                            }
                        });
    
                        mDefaultThreadPool.execute(asyncRequest);
                        mAsyncRequests.add(asyncRequest);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                 5、络网请求返回的图片数据流可能会很大,直接解码成生Bitmap对象,可能会形成OOM。因此,要根据指定的缩压比例,得获适合的Bitmap

    Bitmap bitmap = BitmapUtil.decodeStream((InputStream) obj, imgInfo.getWidth(), imgInfo.getHeight());

                6、上一步理处后过,可能解码成生的Bitmap对象还会很大,可能还会形成OOM,因此,Bitmap对象再次行进量质缩压。

    if (imgInfo.isCompress()) {
                                        // 对Bitmap行进量质缩压
                                        bitmap = BitmapUtil.compressBitmap(bitmap);
                                    }

              7、行进地本文件缓存

    try {
                                    fileCache.writeToFile(inStream, file);
                                } catch (IOException e) {
                                    // TODO Auto-generated catch block
                                    e.printStackTrace();
                                }

              8、行进地本存内缓存

    // 将数据流将其转换成Bitmap
                                bitmap = BitmapFactory.decodeStream(inStream);
    
                                // 存入存内缓存中
                                memoryCache.put(url, bitmap);

              9、用ImageView对象表现户用图像,到这里止终。

    // 用ImageView对象表现图片
                                final Bitmap btm = bitmap;
                                mHandler.post(new Runnable() {
    
                                    @Override
                                    public void run() {
                                        imageView.setImageBitmap(btm);
                                    }
                                });

           加载图片的整完方法,码代如下:

    /**
         * 加载图片
         * @param imgInfo 图片信息
         */
        public void displayImage(final ImageInfo imgInfo) {
            final ImageView imageView = imgInfo.getImageView();
            final String url = imgInfo.getUrl();
    
            imageViews.put(imageView, url);
    
            // 从存内缓存中找查
            Bitmap bitmap = memoryCache.get(url);
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap);
            } else {
                // 从文件缓存中找查
                final File file = fileCache.getFile(url);
                if (file.exists()) {
                    String pathName = file.getAbsolutePath();
                    System.out.println("pathName = " + pathName);
                    System.out.println("file.length() = " + file.length());
    
                    bitmap = BitmapFactory.decodeFile(pathName);
                    imageView.setImageBitmap(bitmap);
                } else {
                    // 开启线程加载图片
                    try {
                        AsyncBaseRequest asyncRequest = new AsyncHttpGet(url, null, null, new ResultCallback() {
    
                            @Override
                            public void onSuccess(Object obj) {
                                if (obj == null || !(obj instanceof InputStream)) {
                                    System.out.println("Loading image return Object is null or not is InputStream.");
                                    return;
                                }
    
                                try {
                                    // 根据指定的缩压比例,得获适合的Bitmap
                                    Bitmap bitmap = BitmapUtil.decodeStream((InputStream) obj, imgInfo.getWidth(), imgInfo.getHeight());
                                    
                                    if (imgInfo.isRounded()) {
                                         // 将图片酿成角圆
                                         // bitmap = BitmapUtil.drawRoundCorner(bitmap, 8);
                                         bitmap = BitmapUtil.drawRoundBitmap(bitmap, 8);
                                    }
                                    
                                    if (imgInfo.isCompress()) {
                                        // 对Bitmap行进量质缩压
                                        bitmap = BitmapUtil.compressBitmap(bitmap);
                                    }
                                    
                                    // 将Bitmap转换成ByteArrayInputStream
                                    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
                                    ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
                                    
                                    // 将行进量质缩压后的数据写入文件(文件缓存)
                                    fileCache.writeToFile(inStream, file);
                                    
                                    // 存入存内缓存中
                                    memoryCache.put(url, bitmap);
    
                                    // 止防图片错位
                                    String tag = imageViews.get(imageView);
                                    if (tag == null || !tag.equals(url)) {
                                        System.out.println("tag is null or url and ImageView disaccord.");
                                        return;
                                    }
                                    
                                    // 用ImageView对象表现图片
                                    final Bitmap btm = bitmap;
                                    mHandler.post(new Runnable() {
    
                                        @Override
                                        public void run() {
                                            imageView.setImageBitmap(btm);
                                        }
                                    });
                                    
                                    
                                } catch (IOException e) {
                                    // 这里不做理处,因为默许表现的图片在xml组件配置里已设置
                                    e.printStackTrace();
                                }
                                
                            }
    
                            @Override
                            public void onFail(int errorCode) {
                                System.out.println("Loading image error. errorCode = " + errorCode);
                            }
                        });
    
                        mDefaultThreadPool.execute(asyncRequest);
                        mAsyncRequests.add(asyncRequest);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

          三、在上述务业理处中程过,碰到的问题及处理思绪(记载理处进程)

               1、根据指定的缩压比例,得获适合的Bitmap,浏览如下码代:

    /**
         * 根据指定的缩压比例,得获适合的Bitmap
         * @param inStream InputStream
         * @param width 指定的宽度
         * @param height 指定的度高
         */
        public static Bitmap decodeStream(InputStream inStream, int width, int height) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inStream, null, options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
    
            return BitmapFactory.decodeStream(inStream, null, options);
        }

           注:inStream为从络网得获后,直接传进来的。

               行运面下的后,返回的Bitmap对象为null。究其原因,在设置 options.inJustDecodeBounds = true后,我们调用了BitmapFactory.decodeStream(inStream, null, options)方法得获图片的巨细,但是该方法在执行完后,该应在内部把传进去的InputStream关闭掉了。第二次的时候就读不到数据了。处理思绪,将从络网得获到的数据流先存保起来。处理方法一:

    /**
         * 根据指定的缩压比例,得获适合的Bitmap(方法一)
         * @param file File
         * @param width 指定的宽度
         * @param height 指定的度高
         * @return Bitmap
         */
        public static Bitmap decodeStream(File file, int width, int height) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(file.getAbsolutePath(), options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options = new BitmapFactory.Options();
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
    
            return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
        }

        处理方法二:

    /**
         * 根据指定的缩压比例,得获适合的Bitmap(方法二)
         * @param inStream InputStream
         * @param width 指定的宽度
         * @param height 指定的度高
         * @return Bitmap
         * @throws IOException
         */
        public static Bitmap decodeStream(InputStream inStream, int width, int height) throws IOException {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
    
            // 从输入流读取数据
            byte[] data = StreamTool.read(inStream);
            BitmapFactory.decodeByteArray(data, 0, data.length, options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }

        处理方法三:从络网返回的数据流中只读取图片的信息(宽度和度高),盘算缩压比例,后之再次从络网读取数据按第一次盘算出的缩压比例,得获适合的Bitmap。(这个是下下策,要问访两次络网)

           2、对Bitmap行进量质缩压,浏览如下码代:

    /**
         * 对Bitmap行进量质缩压
         * @param bitmap Bitmap
         * @return ByteArrayInputStream
         */
        public static Bitmap compressBitmap(Bitmap bitmap) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            // 图片量质默许值为100,表示不缩压
            int quality = 100;
            // PNG是无损的,将会略忽量质设置。因此,这里设置为JPEG
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
    
            // 判断缩压后图片的巨细否是大于100KB,大于则继承缩压
            while (outStream.toByteArray().length / 1024 > 100) {
                outStream.reset();
    
                // 缩压quality%,把缩压后的数据寄存到baos中
                bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
                quality -= 10;
            }
    
            System.out.println("quality = " + quality);
    
            byte[] data = outStream.toByteArray();
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }

            注意:  bitmap.compress(Bitmap.CompressFormat.PNG, quality, outStream);如果这么写,是没有缩压效果的。因为PNG是无损的,将会略忽量质设置。

        四、上述讲授中涉及到的类,整完的源文件如下:

        加载(装载)图片类

    package com.everyone.android.bitmap;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.SimpleDateFormat;
    import java.util.Collections;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Handler;
    import android.widget.ImageView;
    
    import com.everyone.android.AppBaseActivity;
    import com.everyone.android.callback.ResultCallback;
    import com.everyone.android.entity.ImageInfo;
    import com.everyone.android.net.AsyncBaseRequest;
    import com.everyone.android.net.AsyncHttpGet;
    import com.everyone.android.net.DefaultThreadPool;
    import com.everyone.android.utils.BitmapUtil;
    
    /**
     * 能功描述:加载(装载)图片
     * 
     * 在前以,一个非常行流的存内缓存的现实是用使SoftReference or WeakReference ,但是种这方法当初其实不荐推。
     * 从Android 2.3开始,垃圾收回器会更加踊跃的去收回软引用和弱引用引用的对象,这样致导种这做法相称的无效。
     * 另外,在Android 3.0之前,图片数据存保在地本存内中,它们不是以一种可见预的式方来放释的,
     * 这样可能会致导用应存内的消耗量现出暂短的超限,用应程序溃崩 。
     * 
     * @author android_ls
     */
    public class ImageLoader {
    
        /**
         * 存内缓存
         */
        private MemoryCache memoryCache;
    
        /**
         * 文件缓存
         */
        private FileCache fileCache;
    
        /**
         * 寄存图片的表现视图ImageView和图片的URL
         */
        private Map<ImageView, String> imageViews = Collections.synchronizedMap(new LinkedHashMap<ImageView, String>());
    
        private List<AsyncBaseRequest> mAsyncRequests;
    
        private DefaultThreadPool mDefaultThreadPool;
    
        private Handler mHandler;
    
        public ImageLoader(AppBaseActivity activity) {
            this.memoryCache = new MemoryCache();
            this.fileCache = new FileCache(activity.getContext());
            this.mAsyncRequests = activity.getAsyncRequests();
            this.mDefaultThreadPool = activity.getDefaultThreadPool();
            this.mHandler = activity.getHandler();
        }
    
        /**
         * 加载图片
         * @param imgInfo 图片信息
         */
        public void displayImage(final ImageInfo imgInfo) {
            final ImageView imageView = imgInfo.getImageView();
            final String url = imgInfo.getUrl();
    
            imageViews.put(imageView, url);
    
            // 从存内缓存中找查
            Bitmap bitmap = memoryCache.get(url);
            if (bitmap != null) {
                imageView.setImageBitmap(bitmap);
            } else {
                // 从文件缓存中找查
                final File file = fileCache.getFile(url);
                if (file.exists()) {
                    String pathName = file.getAbsolutePath();
                    System.out.println("pathName = " + pathName);
                    System.out.println("file.length() = " + file.length());
    
                    SimpleDateFormat mDateFormat = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss");
                    System.out.println("file.lastModified() = " + mDateFormat.format(file.lastModified()));
                    
                    bitmap = BitmapFactory.decodeFile(pathName);
                    imageView.setImageBitmap(bitmap);
                } else {
                    // 开启线程加载图片
                    try {
                        AsyncBaseRequest asyncRequest = new AsyncHttpGet(url, null, null, new ResultCallback() {
    
                            @Override
                            public void onSuccess(Object obj) {
                                if (obj == null || !(obj instanceof InputStream)) {
                                    System.out.println("Loading image return Object is null or not is InputStream.");
                                    return;
                                }
    
                                try {
                                    // 根据指定的缩压比例,得获适合的Bitmap
                                    Bitmap bitmap = BitmapUtil.decodeStream((InputStream) obj, imgInfo.getWidth(), imgInfo.getHeight());
                                    
                                    if (imgInfo.isRounded()) {
                                         // 将图片酿成角圆
                                         // bitmap = BitmapUtil.drawRoundCorner(bitmap, 8);
                                         bitmap = BitmapUtil.drawRoundBitmap(bitmap, 8);
                                    }
                                    
                                    if (imgInfo.isCompress()) {
                                        // 对Bitmap行进量质缩压
                                        bitmap = BitmapUtil.compressBitmap(bitmap);
                                    }
                                    
                                    // 将Bitmap转换成ByteArrayInputStream
                                    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
                                    ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
                                    
                                    // 将行进量质缩压后的数据写入文件(文件缓存)
                                    fileCache.writeToFile(inStream, file);
                                    
                                    // 存入存内缓存中
                                    memoryCache.put(url, bitmap);
    
                                    // 止防图片错位
                                    String tag = imageViews.get(imageView);
                                    if (tag == null || !tag.equals(url)) {
                                        System.out.println("tag is null or url and ImageView disaccord.");
                                        return;
                                    }
                                    
                                    // 用ImageView对象表现图片
                                    final Bitmap btm = bitmap;
                                    mHandler.post(new Runnable() {
    
                                        @Override
                                        public void run() {
                                            imageView.setImageBitmap(btm);
                                        }
                                    });
                                    
                                    
                                } catch (IOException e) {
                                    // 这里不做理处,因为默许表现的图片在xml组件配置里已设置
                                    e.printStackTrace();
                                }
                                
                            }
    
                            @Override
                            public void onFail(int errorCode) {
                                System.out.println("Loading image error. errorCode = " + errorCode);
                            }
                        });
    
                        mDefaultThreadPool.execute(asyncRequest);
                        mAsyncRequests.add(asyncRequest);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    }

        
    存内缓存类

    package com.everyone.android.bitmap;
    
    import java.util.Collections;
    import java.util.Iterator;
    import java.util.LinkedHashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import android.graphics.Bitmap;
    import android.util.Log;
    
    /**
     * 能功描述:存内缓存类
     * 
     * @author android_ls
     */
    public class MemoryCache {
    
        /**
         * 打印LOG的TAG
         */
        private static final String TAG = "MemoryCache";
    
        /**
         * 放入缓存时是个同步操作
         * LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近用使次数由少到多排列,
         * 这样的利益是如果要将缓存中的元素替换,则先遍历出最近最少用使的元来素替换以进步率效
         */
        private Map<String, Bitmap> cacheMap = Collections.synchronizedMap(new LinkedHashMap<String, Bitmap>(10, 1.5f, true));
    
        // 缓存只能占用的最大堆存内
        private long maxMemory;
    
        public MemoryCache() {
            // 用使25%的可用的堆巨细
            maxMemory = Runtime.getRuntime().maxMemory() / 4;
            Log.i(TAG, "MemoryCache will use up to " + (maxMemory / 1024 / 1024) + "MB");
        }
    
        /**
         * 根据key得获响应的图片
         * @param key
         * @return Bitmap
         */
        public Bitmap get(String key) {
            if (!cacheMap.containsKey(key)){
                return null;
            }
            return cacheMap.get(key);
        }
    
        /**
         * 添加图片到缓存
         * @param key
         * @param bitmap
         */
        public synchronized void put(String key, Bitmap bitmap) {
            checkSize();
            cacheMap.put(key, bitmap);
           
            Log.i(TAG, "cache size=" + cacheMap.size() + " bitmap size = " +  getBitmapSize(bitmap));
        }
    
        /**
         * 严格控制堆存内,如果过超将首先替换最近最少用使的那个图片缓存
         */
        private void checkSize() {
            long count = 0;
            Iterator<Entry<String, Bitmap>> iterator = cacheMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<String, Bitmap> entry = iterator.next();
                count += getBitmapSize(entry.getValue());
            }
    
            Log.i(TAG, "cache size=" + count + " length=" + cacheMap.size());
    
            if (count > maxMemory) {
                while (iterator.hasNext()) {
                    Entry<String, Bitmap> entry = iterator.next();
                    count -= getBitmapSize(entry.getValue());
    
                    iterator.remove();
                    if (count <= maxMemory) {
                        System.out.println("够用了,不用在删除了");
                        break;
                    }
                }
                Log.i(TAG, "Clean cache. New size " + cacheMap.size());
            }
        }
    
        /**
         * 得获bitmap的字节巨细
         * @param bitmap
         * @return
         */
        private long getBitmapSize(Bitmap bitmap) {
            if (bitmap == null) {
                return 0;
            }
            return bitmap.getRowBytes() * bitmap.getHeight();
        }
    
        /**
         * 空清缓存
         */
        public void clear() {
            cacheMap.clear();
        }
    
    }

        络网下载文件地本缓存类

    package com.everyone.android.bitmap;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Comparator;
    
    import android.content.Context;
    import android.os.StatFs;
    
    /**
     * 能功描述:络网下载文件地本缓存类
     * 
     * @author android_ls
     */
    public class FileCache {
    
        /**
         * 地本与我们用应程序关相文件寄存的根目录
         */
        private static final String ROOT_DIR_PATH = "CopyEveryone";
    
        /**
         * 下载文件寄存的目录
         */
        private static final String IMAGE_DOWNLOAD_CACHE_PATH = ROOT_DIR_PATH + "/Download/cache";
    
        /**
         * 默许的盘磁缓存巨细(20MB)
         */
        private static final int DEFAULT_DISK_CACHE_SIZE = 1024 * 1024 * 20;
    
        /**
         * 缓存文件寄存目录
         */
        private File cacheDir;
    
        /**
         * 缓存根目录
         */
        private String cacheRootDir;
        
        private Context mContext;
    
        public FileCache(Context context) {
            mContext = context;
            
            if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
                cacheRootDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();
            } else {
                cacheRootDir = mContext.getCacheDir().getAbsolutePath();
            }
    
            cacheDir = new File(cacheRootDir + File.separator + IMAGE_DOWNLOAD_CACHE_PATH);
            // 检测文件缓存目录否是存在,不存在则创立
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
        }
    
        /**
         * 得获下载的文件要寄存的缓存目录
         * /mnt/sdcard/CopyEveryone/Download/cache
         * @return 缓存目录的全路径
         */
        public String getCacheDirPath() {
            return cacheDir.getAbsolutePath();
        }
    
        /**
         * 根据URL从文件缓存中得获文件
         * @param url url的hashCode为缓存的文件名
         */
        public File getFile(String url) {
            if (!cacheDir.exists()) {
                cacheDir.mkdirs();
            }
    
            String filename = String.valueOf(url.hashCode());
            File file = new File(cacheDir, filename);
            return file;
        }
    
        /**
         * 盘算存储可用的巨细
         * @return
         */
        public long getAvailableMemorySize() {
            StatFs stat = new StatFs(cacheRootDir);
            long blockSize = stat.getBlockSize();
            long availableBlocks = stat.getAvailableBlocks();
            return availableBlocks * blockSize;
        }
    
        /**
         * 将指定的数据写入文件
         * @param inputStream InputStream
         * @param outputStream OutputStream
         * @throws IOException 
         */
        public synchronized void writeToFile(InputStream inputStream, File file) throws IOException {
            int fileSize  = inputStream.available();
            System.out.println("fileSize = " + fileSize);
            
            long enabledMemory  = getAvailableMemorySize();
            System.out.println("前当可用盘硬: " + (enabledMemory/1024/1024)); // 单位:MB
            
            // 前当可用存储空间缺乏20M
            if(DEFAULT_DISK_CACHE_SIZE > enabledMemory){
                if (fileSize > enabledMemory) {
                    // 检测可用空间巨细,若不够用则删除最早的文件
                    File[] files = cacheDir.listFiles();
                    Arrays.sort(files, new FileLastModifSort());
                    
                    int length = files.length;
                    for (int i = 0; i < length; i++) {
                        files[i].delete();
                        length = files.length;
                        
                        enabledMemory  = getAvailableMemorySize();
                        System.out.println("前当可用存内: " + enabledMemory);
                        
                        if (fileSize <= enabledMemory) {
                            System.out.println("够用了,不用在删除了");
                            break;
                        }
                    }
                }
            } else {
                int count = 0;
                File[] files = cacheDir.listFiles();
                for (int i = 0; i < files.length; i++) {
                    count += files[i].length();
                }
                
                System.out.println("file cache size = " + count);
                
                // 用使的空间大于下限
                enabledMemory = DEFAULT_DISK_CACHE_SIZE - count;
                if(fileSize > enabledMemory){
                    Arrays.sort(files, new FileLastModifSort());
                    
                    int length = files.length;
                    for (int i = 0; i < length; i++) {
                        count -= files[i].length();
                        files[i].delete();
                        length = files.length;
                       
                        enabledMemory = DEFAULT_DISK_CACHE_SIZE - count;
                        if (fileSize <= enabledMemory) {
                            System.out.println("够用了,不用在删除了");
                            break;
                        }
                    }
                }
            }
            
            if(enabledMemory == 0){
                return;
            }
            
            // 将数据写入文件存保
            FileOutputStream outStream = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inputStream.read(buffer)) != -1) {
                outStream.write(buffer, 0, len);
            }
            outStream.flush();
            outStream.close();
            inputStream.close();
            
            // 设置最后改修的间时
            long newModifiedTime = System.currentTimeMillis();
            file.setLastModified(newModifiedTime);
            
            System.out.println("file.length() = " + file.length());
            
            SimpleDateFormat mDateFormat = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss");
            System.out.println("writeToFile file.lastModified() = " + mDateFormat.format(file.lastModified()));
        }
    
       /**
        * 根据文件的最后改修间时行进排序
        * @author android_ls
        *
        */
        class FileLastModifSort implements Comparator<File> {
            public int compare(File file1, File file2) {
                if (file1.lastModified() > file2.lastModified()) {
                    return 1;
                } else if (file1.lastModified() == file2.lastModified()) {
                    return 0;
                } else {
                    return -1;
                }
            }
        }
    
        /**
         * 空清缓存的文件
         */
        public void clear() {
            if (!cacheDir.exists()) {
                return;
            }
    
            File[] files = cacheDir.listFiles();
            if (files != null) {
                for (File f : files) {
                    f.delete();
                }
            }
        }
    
    }

        图片信息实体类

    package com.everyone.android.entity;
    
    import android.widget.ImageView;
    
    /**
     * 能功描述:图片信息实体类
     * 
     * @author android_ls
     */
    public class ImageInfo {
    
        private int id; // 独一标识
    
        private ImageView imageView; // 用于表现的组件
    
        private String url; // 络网URL
    
        private int width; // 宽度
    
        private int height; // 度高
    
        private boolean rounded; // 否是要转换成角圆
    
        private boolean compress; // 否是要行进量质缩压
    
        public ImageInfo(ImageView imageView, String url) {
            this.imageView = imageView;
            this.url = url;
        }
    
        public ImageInfo() {
        }
    
        public ImageInfo(ImageView imageView, String url, int width, int height, boolean rounded, boolean compress) {
            this.imageView = imageView;
            this.url = url;
            this.width = width;
            this.height = height;
            this.rounded = rounded;
            this.compress = compress;
        }
    
        public ImageInfo(ImageView imageView, String url, boolean rounded) {
            this.imageView = imageView;
            this.url = url;
            this.rounded = rounded;
        }
    
        public ImageInfo(ImageView imageView, String url, int width, int height) {
            this.imageView = imageView;
            this.url = url;
            this.width = width;
            this.height = height;
        }
    
        public ImageInfo(ImageView imageView, String url, int width, int height, boolean rounded) {
            this.imageView = imageView;
            this.url = url;
            this.width = width;
            this.height = height;
            this.rounded = rounded;
        }
    
        public boolean isCompress() {
            return compress;
        }
    
        public void setCompress(boolean compress) {
            this.compress = compress;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public ImageView getImageView() {
            return imageView;
        }
    
        public void setImageView(ImageView imageView) {
            this.imageView = imageView;
        }
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public int getWidth() {
            return width;
        }
    
        public void setWidth(int width) {
            this.width = width;
        }
    
        public int getHeight() {
            return height;
        }
    
        public void setHeight(int height) {
            this.height = height;
        }
    
        public boolean isRounded() {
            return rounded;
        }
    
        public void setRounded(boolean rounded) {
            this.rounded = rounded;
        }
    
    }

        Bitmap加工理处具工类

    package com.everyone.android.utils;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    
    import android.graphics.Bitmap;
    import android.graphics.Bitmap.Config;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.PorterDuff;
    import android.graphics.PorterDuff.Mode;
    import android.graphics.PorterDuffXfermode;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    
    /**
     * 能功描述:Bitmap加工理处具工类
     * @author android_ls
     *
     */
    public class BitmapUtil {
    
        /**
         * 将图片酿成角圆(方法一)
         * @param bitmap Bitmap
         * @param pixels 角圆的弧度
         * @return 角圆图片
         */
        public static Bitmap drawRoundBitmap(Bitmap bitmap, float pixels) {
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            final Paint paint = new Paint();
            final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
            final RectF rectF = new RectF(rect);
    
            paint.setAntiAlias(true);
            canvas.drawARGB(0, 0, 0, 0);
            // paint.setColor()的参数,除不能为Color.TRANSPARENT外,可以意任写
            paint.setColor(Color.RED);
            canvas.drawRoundRect(rectF, pixels, pixels, paint);
    
            paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            canvas.drawBitmap(bitmap, rect, rect, paint);
    
            return output;
        }
    
        /**
         * 将图片酿成角圆(方法二)
         * @param bitmap Bitmap
         * @param pixels 角圆的弧度
         * @return 角圆图片
         */
        public static Bitmap drawRoundCorner(Bitmap bitmap, float pixels) {
            Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(output);
    
            RectF outerRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
            // paint.setColor()的参数,除不能为Color.TRANSPARENT外,可以意任写
            paint.setColor(Color.WHITE);
            canvas.drawRoundRect(outerRect, pixels, pixels, paint);
    
            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
            Drawable drawable = new BitmapDrawable(bitmap);
            drawable.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
            canvas.saveLayer(outerRect, paint, Canvas.ALL_SAVE_FLAG);
            drawable.draw(canvas);
            canvas.restore();
    
            return output;
        }
    
        /**
         * 对Bitmap行进量质缩压
         * @param bitmap Bitmap
         * @return ByteArrayInputStream
         */
        public static Bitmap compressBitmap(Bitmap bitmap) {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            // 图片量质默许值为100,表示不缩压
            int quality = 100;
            // PNG是无损的,将会略忽量质设置。因此,这里设置为JPEG
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
    
            // 判断缩压后图片的巨细否是大于100KB,大于则继承缩压
            while (outStream.toByteArray().length / 1024 > 100) {
                outStream.reset();
    
                // 缩压quality%,把缩压后的数据寄存到baos中
                bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outStream);
                quality -= 10;
            }
    
            System.out.println("quality = " + quality);
    
            byte[] data = outStream.toByteArray();
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }
    
        /**
         * 根据指定的缩压比例,得获适合的Bitmap(方法一)
         * @param file File
         * @param width 指定的宽度
         * @param height 指定的度高
         * @return Bitmap
         */
        public static Bitmap decodeStream(File file, int width, int height) {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(file.getAbsolutePath(), options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options = new BitmapFactory.Options();
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
    
            return BitmapFactory.decodeFile(file.getAbsolutePath(), options);
        }
    
        /**
         * 根据指定的缩压比例,得获适合的Bitmap(方法二)
         * @param inStream InputStream
         * @param width 指定的宽度
         * @param height 指定的度高
         * @return Bitmap
         * @throws IOException
         */
        public static Bitmap decodeStream(InputStream inStream, int width, int height) throws IOException {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
    
            // 从输入流读取数据
            byte[] data = StreamTool.read(inStream);
            BitmapFactory.decodeByteArray(data, 0, data.length, options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
            return BitmapFactory.decodeByteArray(data, 0, data.length);
        }
    
        /**
         * 根据指定的缩压比例,得获适合的Bitmap(会错出的方法,仅用于测试)
         * @param inStream
         * @param width
         * @param height
         * @return
         * @throws IOException
         */
        public static Bitmap decodeStreamError(InputStream inStream, int width, int height) throws IOException {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inStream, null, options);
    
            int w = options.outWidth;
            int h = options.outHeight;
    
            // 从服务器端得获的图片巨细为:80x120
            // 我们想要的图片巨细为:40x40
            // 缩放比:120/40 = 3,也就是说我们要的图片巨细为原图的1/3
    
            // 缩放比。由于是定固比例缩放,只用高或者宽其中一个数据行进盘算可即
            int ratio = 1; // 默以为不缩放
            if (w >= h && w > width) {
                ratio = (int) (w / width);
            } else if (w < h && h > height) {
                ratio = (int) (h / height);
            }
    
            if (ratio <= 0) {
                ratio = 1;
            }
    
            System.out.println("图片的缩放比例值ratio = " + ratio);
    
            options.inJustDecodeBounds = false;
            // 属性值inSampleSize表示缩略图巨细为原始图片巨细的几分之一,即如果这个值为2,
            // 则掏出的缩略图的宽和高都是原始图片的1/2,图片巨细就为原始巨细的1/4。
            options.inSampleSize = ratio;
    
            return BitmapFactory.decodeStream(inStream, null, options);
        }
    
    }

        
    单位转换具工类

    package com.everyone.android.utils;
    
    import android.content.Context;
    
    /**
     * 能功描述:单位转换具工类
     * @author android_ls
     *
     */
    public class DensityUtil {
    
        /**
         * 将单位为dip的值转换成单位为px的值
         * @param context Context
         * @param dipValue dip值
         * @return px值
         */
        public static int dip2px(Context context, float dipValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (dipValue * scale + 0.5f);
        }
    
        /**
         * 将单位为px的值转换成单位为dip的值
         * @param context Context
         * @param pxValue 像素值
         * @return dip值
         */
        public static int px2dip(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }
    
        /**
         * 将px值转换为sp值,保障文字巨细稳定
         * 
         * @param pxValue
         * @param fontScale(DisplayMetrics类中属性scaledDensity)
         * @return
         */
        public static int px2sp(Context context, float pxValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (pxValue / scale + 0.5f);
        }
    
        /**
         * 将sp值转换为px值,保障文字巨细稳定
         * 
         * @param spValue
         * @param fontScale(DisplayMetrics类中属性scaledDensity)
         * @return
         */
        public static int sp2px(Context context, float spValue) {
            final float scale = context.getResources().getDisplayMetrics().density;
            return (int) (spValue * scale + 0.5f);
        }
    }

        
    数据流理处具工类数据流理处具工类数据流理处具工类

    package com.everyone.android.utils;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    
    /**
     * 能功描述:数据流理处具工类
     * @author android_ls
     */
    public final class StreamTool {
    
        /**
         * 从输入流读取数据
         * 
         * @param inStream
         * @return
         * @throws IOException
         * @throws Exception
         */
        public static byte[] read(InputStream inStream) throws IOException {
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            outSteam.close();
            inStream.close();
            return outSteam.toByteArray();
        }
    
    }

        五、络网模块改修的文件源码:

              络网请求线程基类

    package com.everyone.android.net;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.Serializable;
    import java.net.HttpURLConnection;
    import java.util.Map;
    
    import org.json.JSONException;
    
    import com.everyone.android.callback.ParseCallback;
    import com.everyone.android.callback.ResultCallback;
    import com.everyone.android.utils.Constant;
    import com.everyone.android.utils.LogUtil;
    import com.everyone.android.utils.StreamTool;
    
    /**
     * 能功描述:络网请求线程基类
     * @author android_ls
     *
     */
    public abstract class AsyncBaseRequest implements Runnable, Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
    
        /**
         * LOG打印标签
         */
        private static final String TAG = "AsyncBaseRequest";
        
        /**
         * 络网连接超时,默许值为5秒
         */
        protected int connectTimeout = 5 * 1000;
    
        /**
         * 络网数据读取超时,默许值为5秒
         */
        protected int readTimeout = 5 * 1000;
    
        private boolean interrupted;
    
        public boolean isInterrupted() {
            return interrupted;
        }
    
        public void setInterrupted(boolean interrupted) {
            this.interrupted = interrupted;
        }
    
        protected void setConnectTimeout(int connectTimeout) {
            this.connectTimeout = connectTimeout;
        }
    
        protected void setReadTimeout(int readTimeout) {
            this.readTimeout = readTimeout;
        }
    
        protected String requestUrl;
    
        protected Map<String, String> parameter;
    
        private ParseCallback parseHandler;
    
        private ResultCallback requestCallback;
    
        protected HttpURLConnection mHttpURLConn;
    
        protected InputStream mInStream;
    
        public AsyncBaseRequest(String url, Map<String, String> parameter, ParseCallback handler, ResultCallback requestCallback) {
            this.parseHandler = handler;
            this.requestUrl = url;
            this.parameter = parameter;
            this.requestCallback = requestCallback;
        }
    
        /**
         * 发送络网请求
         * 
         * @return 络网请求返回的InputStream数据流
         * @throws IOException
         */
        protected abstract InputStream getRequestResult() throws IOException;
    
        @Override
        public void run() {
            if (interrupted) {
                LogUtil.i(TAG, "问访络网前中断务业理处线程(止终)");
                return;
            }
            
            try {
                mInStream = getRequestResult();
                if (mInStream != null) {
                    if (interrupted) {
                        LogUtil.i(TAG, "读取数据前中断务业理处线程(止终)");
                        return;
                    }
    
                    Object obj = null;
                    if(parseHandler != null){
                        byte[] data = StreamTool.read(mInStream);
                        if (interrupted) {
                            LogUtil.i(TAG, "剖析数据前中断务业理处线程(止终)");
                            return;
                        }
                        
                        String result = new String(data);
                        obj = parseHandler.parse(result);
                    }
                    
                    if (interrupted) {
                        LogUtil.i(TAG, "刷新UI前中断务业理处线程(止终)");
                        return;
                    }
                    
                    if(obj != null){
                        requestCallback.onSuccess(obj);
                    } else {
                        requestCallback.onSuccess(mInStream);
                    }
                   
                } else {
                    LogUtil.i(TAG, "get InputStream By HttpURLConnection return result is NULL.");
                    requestCallback.onFail(Constant.NETWORK_REQUEST_RETUN_NULL); // 络网请求返回NULL
                }
            } catch (JSONException e) {
                requestCallback.onFail(Constant.NETWORK_REQUEST_RESULT_PARSE_ERROR); // 络网请求返回结果剖析错出
                e.printStackTrace();
            } catch (IOException e) {
                requestCallback.onFail(Constant.NETWORK_REQUEST_IOEXCEPTION_CODE); // IO常异标识
                e.printStackTrace();
            }
            
        }
    
        public HttpURLConnection getRequestConn() {
            return mHttpURLConn;
        }
    
    }

              通过HTTP议协发送GET请求

    package com.everyone.android.net;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.util.Map;
    
    import org.apache.http.protocol.HTTP;
    
    import com.everyone.android.callback.ParseCallback;
    import com.everyone.android.callback.ResultCallback;
    
    /**
     * 能功描述:通过HTTP议协发送GET请求
     * @author android_ls
     *
     */
    public class AsyncHttpGet extends AsyncBaseRequest {
    
        /**
         * 
         */
        private static final long serialVersionUID = 2L;
    
        public AsyncHttpGet(String url, Map<String, String> parameter, ParseCallback handler, ResultCallback requestCallback) throws IOException {
            super(url, parameter, handler, requestCallback);
        }
    
        @Override
        protected InputStream getRequestResult() throws IOException {
            StringBuilder sb = new StringBuilder(requestUrl);
            if (parameter != null && !parameter.isEmpty()) {
                sb.append('?');
                for (Map.Entry<String, String> entry : parameter.entrySet()) {
                    sb.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), HTTP.UTF_8)).append('&');
                }
                sb.deleteCharAt(sb.length() - 1);
            }
    
            URL url = new URL(sb.toString());
            mHttpURLConn = (HttpURLConnection) url.openConnection();
            mHttpURLConn.setConnectTimeout(connectTimeout);
            mHttpURLConn.setRequestMethod("GET");
            if (mHttpURLConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                return mHttpURLConn.getInputStream();
            }
            return null;
        }
    
    }

        
    六、行运后的效果图:

        

         

         图片双缓存这块,拖了良久,这一篇博文我花了一晚上间时,搞了一个宵通,于终写完了。天亮了,说:友人们,晚安!

         

    文章结束给大家分享下程序员的一些笑话语录: 人工智能今天的发展水平:8乘8的国际象棋盘其实是一个体现思维与创意的强大媒介。象棋里蕴含了天文数字般的变化。卡斯帕罗夫指出,国际象棋的合法棋步共有1040。在棋局里每算度八步棋,里面蕴含的变化就已经超过银河系里的繁星总数。而地球上很少有任何数量达到这个级别。在金融危机之前,全世界的财富总和大约是1014人民币,而地球人口只有1010。棋盘上,所有可能的棋局总数达到10120,这超过了宇宙里所有原子的总数!经典语录网

  • 相关阅读:
    Matplotlib绘图双纵坐标轴设置及控制设置时间格式
    https://www.cnblogs.com/xubing-613/p/5895948.html
    Python科学计算技巧积累四——双y轴图像绘制
    卡尔曼滤波(Kalman Filter)
    python os.path模块常用方法详解 ZZ
    C/C++跨平台的的预编译宏
    WEB版一次选择多个图片进行批量上传(WebUploader)的解决方案
    WEB版一次选择多个文件进行批量上传(WebUploader)的解决方案
    学习ASP.NET MVC(十一)——分页
    学习ASP.NET MVC(十)——排序
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3020362.html
Copyright © 2020-2023  润新知