本文共 3716 字,大约阅读时间需要 12 分钟。
一、背景
ByPhoto是个安卓图片选择库, 在启动渲染速度上做了很多优化; 荣耀8真机测试,图库里有3000多张图片。 冷启动图片选择页渲染完成需800ms左右, 热启动(即第二次打开Activity)渲染需要300ms。 真正实现了秒开的用户体验。三、核心代码
@Override protected ListdoInBackground(String... strings) { ... while (cursor.moveToNext()) { ... //每隔10个图片报一次, 即分段通知UI数据变化 if (i % Constants.PHOTO_COUNT_PER_TIME == 0 && i > 0) { ImageItem[] segData = new ImageItem[Constants.PHOTO_COUNT_PER_TIME]; for (int k = 0; k < Constants.PHOTO_COUNT_PER_TIME; k++) { segData[k] = itemList.get(i - Constants.PHOTO_COUNT_PER_TIME + k); } publishProgress(segData); } return null; }
预加载前几张图片到Glide缓存中, 默认加载前15张;
public static void preloadData(final Context ctx) { ... while (cursor.moveToNext() && i < Constants.MAX_PRELOAD_PHOTO_NUMS) { final String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); if (path != null && new File(path).exists()) { Log.d("brycegao", "文件已存在:" + path); } sHandler.post(new Runnable() { @Override public void run() { Glide.with(ctx) .load(new File(path)) .addListener(new RequestListener() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { return false; } }) .preload(Constants.getScreenWidth(context), Constants.getScreenWidth(context)); } }); i++; } ... }
在Activity的onCreate最开始启动线程加载数据, 注意:这里不会出现并发问题, 原因是子线程通过Handler执行UI线程的函数。 onCreate必须执行完成才可能响应子线程触发的回调;
protected void onCreate(Bundle savedInstanceState) { //在子线程加载数据 initData(); super.onCreate(savedInstanceState); ...}
重写RecyclerView并处理滑动事件, 逻辑是判断横向滑动时勾选经过的item, 纵向滑动时不做处理; 通过坐标(x,y)找到匹配的RecyclerView条目;
private boolean processTouchEvent(MotionEvent event) { int x = (int) event.getX(); int y = (int) event.getY(); //记录点击屏幕时的初始坐标 if (event.getAction() == MotionEvent.ACTION_DOWN) { mDownX = x; mDownY = y; } //抬起手指时重置 if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { mDownY = 0; mDownX = 0; mLastX = 0; mLastY = 0; } if (event.getAction() == MotionEvent.ACTION_MOVE) { double distance = Math.sqrt(Math.abs(x - mLastX) * Math.abs(x - mLastX) + Math.abs(y - mLastY) * Math.abs(y - mLastY)); //如果是横向滑动且滑动距离超过阈值,则判断经过的item并勾选 if (distance > MIN_DISTANCE && Math.abs(x - mDownX) > Math.abs(y - mDownY)) { mLastY = y; mLastX = x; doCheckSingleFinger(x, y); } } return false; }
控件:设置控件固定宽高, 减少测量时间;
四、总结
todo:手指滑动时取消勾选状态; 手指滑动时RecyclerView不动;通过各种技术措施, 尽可能减少渲染时间; 目前最耗时的部分是Glide加载文件并绘制到控件; 监听DrawListener回调, 显示第一个图片(不是背景图,是目标图片)需要800ms左右(冷启动),UI体验看上去就是RecyclerView控件白了一下; 大概写了2天, 有一些收获。 欢迎技术交流~~~
转载地址:http://wkqvb.baihongyu.com/