Android基础知识复习(四)

学习内容

  1. Google Android Training
    http://developer.android.com/training/index.html
  2. Github托管
    https://github.com/kesenhoo/android-training-course-in-chinese
  3. 中文阅读地址
    http://hukai.me/android-training-course-in-chinese/index.html

以下是仅对我个人有意义的笔记

4. Android图像与动画

4.1. 高效显示Bitmap(如何在加载并处理bitmaps的同时保持用户界面响应,防止超出内存限制。)

4.1.1. 高效加载大图(实现方式:加载一个缩小版本的图片)

  1. 实现缩放展示图片

    • 缩放的方法

      public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
          int reqWidth, int reqHeight) {
      // First decode with inJustDecodeBounds=true to check dimensions;inJustDecodeBounds 值设为true,不返回实际的bitmap,也不给其分配内存空间这样就避免内存溢出了。但允许查询图片的信息(大小)
      final BitmapFactory.Options options = new BitmapFactory.Options();
      options.inJustDecodeBounds = true;
      //获取图片的信息
      BitmapFactory.decodeResource(res, resId, options);
      
      // Calculate inSampleSize;计算inSampleSize,不过这种也是预先设置了要变成什么尺寸的图片,然后计算出inSampleSize应该设为什么值
      options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
      
      // Decode bitmap with inSampleSize set;设置为false之后,就返回bitmap真实值了
      options.inJustDecodeBounds = false;
      return BitmapFactory.decodeResource(res, resId, options);
      }
      
    • 实现

      mImageView.setImageBitmap(
                  decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));
      

4.1.2. 非UI线程处理Bitmap(非本地图片资源)

  1. 跟上一节相比,这里展示了用异步来实现bitmap缩放展示。

    • 异步方法

      class BitmapWorkerTask extends AsyncTask {
          private final WeakReference imageViewReference;
          private int data = 0;
      
          public BitmapWorkerTask(ImageView imageView) {
              // Use a WeakReference to ensure the ImageView can be garbage collected
              imageViewReference = new WeakReference(imageView);
          }
      
          // Decode image in background.
          @Override
          protected Bitmap doInBackground(Integer... params) {
              data = params[0];
              return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
          }
      
          // Once complete, see if ImageView is still around and set bitmap.
          @Override
          protected void onPostExecute(Bitmap bitmap) {
              if (imageViewReference != null && bitmap != null) {
                  final ImageView imageView = imageViewReference.get();
                  if (imageView != null) {
                      imageView.setImageBitmap(bitmap);
                  }
              }
          }
       }
      
    • 实现

      public void loadBitmap(int resId, ImageView imageView) {
      BitmapWorkerTask task = new BitmapWorkerTask(imageView);
      task.execute(resId);
      }
      

4.1.3. 缓存Bitmap

  1. 这个就是为了处理并发的问题(listview……),所以对于AsyncTask进行扩展

    • 方法

      static class AsyncDrawable extends BitmapDrawable {
          private final WeakReference bitmapWorkerTaskReference;
      
          public AsyncDrawable(Resources res, Bitmap bitmap,
                  BitmapWorkerTask bitmapWorkerTask) {
              super(res, bitmap);
              bitmapWorkerTaskReference =
                  new WeakReference(bitmapWorkerTask);
          }
      
          public BitmapWorkerTask getBitmapWorkerTask() {
              return bitmapWorkerTaskReference.get();
          }
      }
      
    • 使用

      public void loadBitmap(int resId, ImageView imageView) {
          if (cancelPotentialWork(resId, imageView)) {
          //新建 异步下载所需要展示的图片,并设置展示在imageview上
              final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
              //为这个异步设定一个占位图
              final AsyncDrawable asyncDrawable =
                      new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
                      //为这个imageview设置异步展现图片
              imageView.setImageDrawable(asyncDrawable);
              task.execute(resId);
          }
      }
      
  2. 取消 例如,两个异步都对同一个imageview进行了操作,取消其中一个操作

    • 实现

      public static boolean cancelPotentialWork(int data, ImageView imageView) {
          final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);
      
          if (bitmapWorkerTask != null) {
              final int bitmapData = bitmapWorkerTask.data;
              if (bitmapData == 0 || bitmapData != data) {
                  // Cancel previous task;取消前一个操作
                  bitmapWorkerTask.cancel(true);
              } else {
                  // The same work is already in progress
                  return false;
              }
          }
          // No task associated with the ImageView, or an existing task was cancelled
          return true;
         }
      
    • 方法

          private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {
         if (imageView != null) {
             final Drawable drawable = imageView.getDrawable();
             if (drawable instanceof AsyncDrawable) {
                 final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
                 return asyncDrawable.getBitmapWorkerTask();
             }
          }
          return null;
      }
      
  3. BitmapWorkerTask的onPostExecute() 方法里面做更新操作:

        class BitmapWorkerTask extends AsyncTask {
        ...
    
        @Override
        protected void onPostExecute(Bitmap bitmap) {
            if (isCancelled()) {
                bitmap = null;
            }
    
            if (imageViewReference != null && bitmap != null) {
                final ImageView imageView = imageViewReference.get();
                final BitmapWorkerTask bitmapWorkerTask =
                        getBitmapWorkerTask(imageView);
                if (this == bitmapWorkerTask && imageView != null) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
      }
    

4.1.4. 管理Bitmap的内存(原理)

  1. 管理Android 3.0及其以上版本的内存(以下的那些版本,就暂时不看了)

    • 3.0以后,BitmapFactory.Options.inBitmap,decode方法会在加载Bitmap数据的时候去重用已在内存中已存在的Bitmap。然而,在Android 4.4 (API level 19)之前,只有同等大小的bitmap才可以被重用。
    • 那么,如何保存已存在的bitmap以供之后使用呢?(系统提供的方法,了解一下原理即可,当一个应用运行在Android 3.0或者更高的平台上并且Bitmap从LruCache中移除时,Bitmap的一个软引用会被存放在Hashset中,这样便于之后可能被inBitmap重用)
    • 如何使用缓存的bitmap

      • decodeSampledBitmapFromFile

        //这句就是重点了,就是在这里去查询cache是不是有存储bitmap
        addInBitmapOptions(options, cache);
        
      • addInBitmapOptions

        // Try to find a bitmap to use for inBitmap.重点代码,主要就是这句话
        Bitmap inBitmap = cache.getBitmapFromReusableSet(options);
        
      • getBitmapFromReusableSet

        //最主要是这句代码,判断是否可以返回存储的bitmap使用
        canUseForInBitmap(item, options)
        
      • canUseForInBitmap(重点,大意就是存储的图片能达到使用要求就表示可用)

                static boolean canUseForInBitmap(
                Bitmap candidate, BitmapFactory.Options targetOptions) {
        
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                // From Android 4.4 (KitKat) onward we can re-use if the byte size of
                // the new bitmap is smaller than the reusable bitmap candidate
                // allocation byte count.
                int width = targetOptions.outWidth / targetOptions.inSampleSize;
                int height = targetOptions.outHeight / targetOptions.inSampleSize;
                int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
                return byteCount <= candidate.getAllocationByteCount();
            }
        
            // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
            return candidate.getWidth() == targetOptions.outWidth
                    && candidate.getHeight() == targetOptions.outHeight
                    && targetOptions.inSampleSize == 1;
        }
        
        /**
         * A helper function to return the byte usage per pixel of a bitmap based on its configuration.分辨率转换
         */
        static int getBytesPerPixel(Config config) {
            if (config == Config.ARGB_8888) {
                return 4;
            } else if (config == Config.RGB_565) {
                return 2;
            } else if (config == Config.ARGB_4444) {
                return 2;
            } else if (config == Config.ALPHA_8) {
                return 1;
            }
            return 1;
        }
        

4.1.5. 在UI上显示Bitmap(使用)

  1. ViewPager+FragmentStatePagerAdapter(基本就是结合上述bitmap的所有知识点显示图片)

  2. GridView

4.2. 使用OpenGL ES显示图像(一组可以显示高级动画和图形的工具集)(太复杂了,暂时不看)

  1. OpenGL ES 1.0和2.0的接口不通用。
  2. 2.

4.2.1. 建立OpenGL ES的环境

4.2.2. 定义Shapes

4.2.3. 绘制Shapes

4.2.4. 运用投影与相机视图

4.2.5. 添加移动

4.2.6. 响应触摸事件

4.3. 添加动画(如何给你的用户界面添加过渡动画。)

4.3.1. View间渐变

  1. 关键在于Alpha值(0→1)+view(gone→visible),淡入;
  2. onAnimationEnd()中设置,visible→gone,淡出。

4.3.2. 使用ViewPager实现屏幕滑动

  1. viewpage本身带有左右移动,所以,实现屏幕滑动动画的时候,根据position来设置alpha的值和ScaleX、ScaleY就可以了。

4.3.3. 展示Card翻转动画

  1. 自定义animation里面的属性需要了解清楚,这样才好知道为什么会出现这样的效果。

4.3.4. 缩放View

  1. zoom 动画,计算画面大小+自定义动作

4.3.5. 布局变更动画

  1. 为创建的布局加上这个属性

    <LinearLayout android:id="@+id/container"
    android:animateLayoutChanges="true"
    .../>
    
  2. 在布局中设置add/del/update

    private void addItem() {
    View newView;
    ...
    mContainerView.addView(newView, 0);}
    

猜你喜欢

转载自blog.csdn.net/sunyejia/article/details/78455646