为了账号安全,请及时绑定邮箱和手机立即绑定
  • 扫描图片(接上一笔记) 2.线程中需要通过ContentResolver来扫描图片 Uri mImgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; ContentResolver cr = MainActivity.this.getContentResolver(); //使用ContentResolver Cursor cursor = cr.query(...); 3.遍历cursor获取每个图片,通过图片的位置获取所在的文件夹 while(cursor.moveToNext()){ String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); //获取当前图片的路径 File parentFile = new File(path).getParentFile(); //获取当前图片所在的目录 if(parentFile == null) continue; String dirPath = parentFile.getAbsolutePath(); //当前图片所在目录字符串 4.需要将遍历过的图片目录放在一个set集合中,避免重复遍历 假设当前有1000张图片,300+300+400分布于三个目录中,同一个目录下的所有图片都会重复遍历。 if(mDirPaths.contains(dirPath)) continue; //当前路径已经扫描过了 else { //当前的图片目录是第一次出现,将相关的属性存入folderBean中 mDirPaths.add(dirPath); folderBean = new FolderBean(); folderBean.setDir(dirPath); folderBean.setFirstImgPath(path); } 4.获取当前图片目录中图片的张数,但要过滤出图片 int picSize = parentFile.list(new FilenameFilter() { }).length; 5.注意: (1)ContentProvider在四大组件中学过 (2)看完整的代码
    查看全部
    0 采集 收起 来源:扫描图片

    2015-10-08

  • 重点。
    查看全部
  • 一、初始化控件 1.扫描完存储卡中的图片后会得到ListView的数据源集合,需要为这个ListView的item创建一个bean模型 参考:http://www.imooc.com/space/note/cid/365(BaseAdapter的使用) 如图,每个item都是一个文件夹,所以创建一个FolderBean的类 2.getter和setter方法 注意一点:setName()可以简化 public void setDir(String dir) { this.dir = dir; int lastIndexOf = this.dir.indexOf("/"); this.name = this.dir.substring(lastIndexOf); } 二、扫描图片 开启一个单独的线程,通过ContentProvider去扫描手机中的所有图片。 1.前期处理 private void initDatas() { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { Toast.makeText(this, "当前存储卡不可用!", Toast.LENGTH_SHORT).show(); return; } mProgressDialog = ProgressDialog.show(this, null, "正在加载..."); new Thread() { //扫描手机中的图片
    查看全部
    0 采集 收起 来源:初始化控件

    2018-03-22

  • 反射获取宽和高最大值 1.imageView.getMaxWidth()和imageView.getMaxHeight()都只是API16才有的接口,如何兼容以下API版本? private static int getImageViewFieldValue(Object object, String fieldName){ int value = 0; try { Field field = ImageView.class.getDeclaredField(fieldName); field.setAccessible(true); int fieldValue = field.getInt(object); if(fieldValue > 0 && fieldValue < Integer.MAX_VALUE){ value = fieldValue; } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } return value; } 然后将对应接口替换。
    查看全部
  • 利用信号量控制任务队列 1.根据目前的逻辑,拿到一个task就会加入到taskQueue中,然后立即会sendMessage()给mPoolThreadHandler,它会将task加入到自己的任务队列中执行。(如图) 这样做的结果是taskQzone中永远只有一个任务,不能体现任务队列的概念。 2.修改——使用信号量 (1)任务队列mTaskQueue和线程池mThreadPool一定要分清楚 (2)当获得一个Task之后,会调用addTasks(Runnable)将其加入到任务队列mTaskQueue中,注意此时不会执行 它会立即sendMessage给mPoolThreadHandler,线程池将其加入到自己的任务队列中(注意这时后台线程池的),然后执行 mThreadPool.execute(getTask()); (3)注意,执行过程是个耗时操作,执行过程中,当前线程会获取信号量 mSemaphoreThreadPool.acquire(); (4)假设当前线程池中指定为3个线程数,那么就会有另外两个也会这么执行 如果此时又有一个也要执行,但是信号量已经没了,就会阻塞。 (5)每个task执行完之后会释放信号量 mSemaphoreThreadPool.release(); 这样才能保证第四个task继续执行 3.不知道这么理解是不是对的.....真TM faint!
    查看全部
  • 后台轮询线程的并行操作 1.后台轮询线程handler是在init()函数中创建中,但注意它和其他函数是并行执行的,所以需要使用同步。 因为在创建一个task让后台轮询线程执行时,它的handler可能还没创建。 2.信号量 (1)新建一个信号量,默认为0个:private Semaphore mSemaphorePoolThreadHandler = new Semaphore(0); (2)在创建完mPoolThreadHandler之后,释放一个信号量 mSemaphorePoolThreadHandler.release(); (3)最后在使用mPoolThreadHandler时,判断是否已经存在,不存在的话就要阻塞等待 private synchronized void addTasks(Runnable runnable) { mTaskQueue.add(runnable); try { if (mPoolThreadHandler == null) //如果mPoolThreadHanlder为空,那就一直等待 mSemaphorePoolThreadHandler.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } mPoolThreadHandler.sendEmptyMessage(0x110); } 注意:为什么要加synchronized?因为可能同时其他线程也要获取信号量,不同步的话可能造成死锁。
    查看全部
  • 压缩图片(接上一笔记) 3.获取压缩比例的操作 private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { //图片实际宽和高 int width = options.outWidth; int height = options.outHeight; int inSampleSize = 1; if(width > reqWidth || height > reqHeight){ //不符比例,则调整尺寸 int widthRadio = Math.round(width*1.0f/reqWidth); int heightRadio = Math.round(height*1.0f/reqHeight); inSampleSize = Math.max(widthRadio, heightRadio); //去两者大值,就会显示完整图片;如果取小值,图片会超出显示区域(较大) } return inSampleSize; } 注意:假如一个300*500的图片,需要压缩为100*100的图片。如果取宽高笔记的较大值,那么最后效果是图片会显示完整,但会出现白边;如果取小值,那么最后效果是图片显示不完整,但会填充完整个imageView 4.将压缩后的图片加入缓存,并通知UIthread来设置imageView //1.获取图片缩略图需要显示的宽和高 ImageSize imageSize = getImageViewSize(imageView); //2.根据上面获得的图片显示宽高来压缩图片 Bitmap bm = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height); //3.将图片加入到缓存 addBitmapToLruCache(path, bm); //需要使用path来对应 //4.sendMessage()通知UI线程设置给imageView
    查看全部
    0 采集 收起 来源:压缩图片

    2018-03-22

  • 根据上一节获取的图片需要显示的宽和高来压缩图片 1.上一节讲了根据图片显示的imageView来获取图片需要显示的宽和高 接下来根据获得的图片显示宽高来压缩图片 2.创建一个函数来压缩图片,获得压缩后的bitmap Bitmap bm = decodeSampledBitmapFromPath(path, imageSize.width, imageSize.height); 实现: private Bitmap decodeSampledBitmapFromPath(String path, int width, int height) { //只是获得图片实际的宽和高,但并不加载图片到内存 BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); //获得图片实际的宽和高,保存在options中 options.inSampleSize = calculateInSampleSize(options, width, height); //使用获取到的inSampleSize再次解析图片,这一次加载图片到内存 options.inJustDecodeBounds = false; Bitmap bitmap = BitmapFactory.decodeFile(path, options); return bitmap; } 注意:1.获取实际图片尺寸 2.获取压缩比例 3.最后根据比例再次加载图片 3.获取压缩比例的操作 (下一笔记)
    查看全部
    0 采集 收起 来源:压缩图片

    2015-09-28

  • 获得图片显示的宽高 1.如果在LruCache中找不到path对应的bitmap,就会创建一个task添加到TaskQueue中。 addTasks(new Runnable(){ public void run() { //加载图片,涉及到图片的压缩 //获取图片缩略图需要显示的宽和高 ImageSize imageSize = getImageViewSize(imageView); }}); mPoolThreadHandler.sendEmptyMessage(0x110);//通知其去执行 2.private void addTasks(Runnable runnable) { mTaskQueue.add(runnable); } 3.后台轮询线程handler的handleMessage() public void handleMessage(Message msg) { //线程池取出一个任务执行 mThreadPool.execute(getTask()); } 4.获取图片要显示的宽和高 private ImageSize getImageViewSize(ImageView imageView) { ImageSize imageSize = new ImageSize(); DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics(); ViewGroup.LayoutParams lp = imageView.getLayoutParams(); int width = imageView.getWidth(); //获取imageView的实际宽度 if(width <= 0){ width = lp.width; //获取imageView在layout中声明的宽度 } if(width <= 0){ width = imageView.getMaxWidth(); //最大值 } if(width <= 0){ width = displayMetrics.widthPixels; //屏幕宽度 } height同上
    查看全部
  • 不能看
    查看全部
    0 采集 收起 来源:适配器

    2015-09-25

  • 初始化UIThread——loadImage() 6.UIThead中需要设置对应的imageView public void handleMessage(Message msg) { //获取到Bitmap格式的图片,为ImageView回调设置图片 ImageBeanHolder holder = (ImageBeanHolder) msg.obj; Bitmap bm = holder.bitmap; ImageView iamgeView = holder.imageView; String path = holder.path; //imageView和path是对应的,才会设置imageView if(iamgeView.getTag().toString().equals(path)){ imageView.setImageBitmap(bm); } } 为什么还要核对这里的imageView和path是否对应? 因为如果图片列表已经滑动到第二页,那么imageView没变,但是图片Bitmap已经变了,此时如果不判断就直接设置的话,就会把第二页的imageView也设置成第一张图片的内容。
    查看全部
    0 采集 收起 来源:初始化mUIHandler

    2015-09-25

  • 初始化UIThread——loadImage() 1.loadImage()根据图片的路径获得到图片的bitmap,然后设置到ImageView中 public void loadImage(String path, ImageView imageView) 2.ImageView和图片的path相对应 imageView.setTag(path); 3.创建更新UI的handler if(mUIHandler == null){ mUIHandler = new Handler(){ public void handleMessage(Message msg) { //获取到Bitmap格式的图片,为ImageView回调设置图片 } }; } 4.根据path在缓存中找到对应的缓存的图片bitmap(可能找不到) Bitmap bm = getBitmapFromLruCache(path); if(bm != null){ //bitmap在cache中,直接发送message给UIThread,更新UI Message msg = Message.obtain(); ImageBeanHolder holder = new ImageBeanHolder(); //创建一个ImageBeanHolder(下5) holder.bitmap = bm; holder.imageView = imageView; holder.path = path; msg.obj = holder; mUIHandler.sendMessage(msg); }else 5.创建一个ImageBeanHolder对象? private class ImageBeanHolder{ Bitmap bitmap; ImageView imageView; String path; } 原因:在loadImage()根据path获取的bitmap,可能是通过异步加载获取到的(cache中不存),然后sendMessage()进行更新ImageView时,获取到的这个bitmap是和path、ImageView是不能对应的。ImageBeanHolder可以让他们对应起来。
    查看全部
    0 采集 收起 来源:初始化mUIHandler

    2015-09-25

  • ImageLoader类中的变量初始化 1.构造函数,传入用于处理的线程数,以及任务队列的调度方式 private ImageLoader(int threadCount, Type type){ init(threadCount, type); } 2.初始化后台轮询线程 轮询线程需要一个Looper,还有一个用于处理消息的handleMessage() 参考:http://www.imooc.com/space/note/cid/267 mPoolThread = new Thread(){ public void run() { Looper.prepare(); mPoolThreadHandler = new Handler(){ public void handleMessage(Message msg) { //线程池取出一个任务执行 } }; Looper.loop(); //loop()就是发给handler本身 }; }; 3..LruCache的初始化 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheMemory = maxMemory/8; mLruCache = new LruCache<String, Bitmap>(cacheMemory){ protected int sizeOf(String key, Bitmap value) { return value.getRowBytes()*value.getHeight(); //重写sizeOf(),获取一张图片的占用大小 } }; 3.创建线程池,传入线程数 mThreadPool = Executors.newFixedThreadPool(threadCount); mTaskQueue = new LinkedList<Runnable>(); mType = type;
    查看全部
  • (接上一笔记) (5)后台轮询线程 private Thread mPoolThread; private Handler mPoolThreadHandler; //这个handler专门给后台轮询线程的messageQueue发送消息 (6)UI线程中的Handler,用于更新ui 当传入path获取一个Bitmap图片后,mUIHandler会发送一个message给UI线程用于更新图片,这是一个关键变量。 private Handler mUIHandler;
    查看全部
  • ImageLoader单例、变量 1.ImageLoader单例模式 ImageLoader的实例在项目中只有一个,ImageLoader类中会维护一个LruCache,LruCache会占用固定大小的内存。这里使用单例。 (1)将构造函数私有化 private ImageLoader(){ } (2)getInstance(),通过类.方法名()来调用 public static ImageLoader getInstance(){ if(mInstance == null){ //不使用同步,判断mInstance是否已存在,过滤掉存在的可能(这时可能多条线程在执行getInstance() synchronized (mInstance){ //做一下同步处理,多条线程进来 if(mInstance == null) //第一个线程满足条件,创建了ImageLoader实例,第二个线程就不再会创建了。 mInstance = new ImageLoader(); } } return mInstance; } 通过两个if判断,可以提高效率。 2.ImageLoader的变量 (1)LruCache用于缓存图片 private LruCache<String, Bitmap> mLruCache; (2)线程池,用于ImageLoader后台线程将线程取出来放入线程池中进行处理 private ExecutorService mThreadPool; private static final int DEFAULT_THREAD_COUNT = 1; //默认线程数 (3)队列调度方式 public enum Type{ FIFO, LIFO; } private Type mType = Type.LIFO; (4)任务队列 使用LinkedList是因为它有首尾去元素的接口,以及它是链表存储元素的方式(不占用连续内存) private LinkedList<Runnable> mTaskQueue; (下一笔记)
    查看全部
    0 采集 收起 来源:单例模式

    2018-03-22

举报

0/150
提交
取消
课程须知
1.掌握Java基础 2.熟练掌握Android常用技术
老师告诉你能学到什么?
1.单例模式在项目中的实践 2.图片的缓存与压缩 3.线程轮询与并行 4.反射机制在Android中的使用 5.Handler-线程间通信

微信扫码,参与3人拼团

微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号

友情提示:

您好,此课程属于迁移课程,您已购买该课程,无需重复购买,感谢您对慕课网的支持!