1. 程式人生 > >Android相簿解決載入大量圖片卡頓問題

Android相簿解決載入大量圖片卡頓問題

Android開發中載入相簿是很常用的功能,但相簿圖片過多正常載入會產生卡頓,即便使用執行緒非同步載入圖片卡頓問題依然得不到改善。
正常程式碼:

public class AlbumAdapter extends ?{
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        if(bitmap!=null){
            執行緒載入圖片
        }
        else
            讀取快取
    }
}

卡頓原因是無論怎樣優化讀取IO都是費時的工作,adapter又會一次例項多個子項,導致載入的圖片過多,記憶體佔用率過高產生了卡頓。
優化程式碼:

public class AlbumActivity extends AppCompatActivity{
    private RecyclerView mRecyclerView;
    private List<PhotoItem> photoItemList;
    private List<PhotoItem> selectItemList;
    private int[] photoLayout;
    private
AlbumAdapter mAdapter; private Handler handler; private Button submit; private GridLayoutManager gridLayoutManager; private static final String[] STORE_IMAGES = { MediaStore.Images.Media.DISPLAY_NAME, // 顯示的名字 MediaStore.Images.Media.LATITUDE, // 維度 MediaStore.Images.Media.LONGITUDE, // 經度
MediaStore.Images.Media._ID, // id MediaStore.Images.Media.BUCKET_ID, // dir id 目錄 MediaStore.Images.Media.BUCKET_DISPLAY_NAME, // dir name 目錄名字 MediaStore.Images.Media.DATA//路徑 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_album); submit = (Button)findViewById(R.id.submit); mRecyclerView = (RecyclerView)findViewById(R.id.list); gridLayoutManager = new GridLayoutManager(this, 3); mRecyclerView.setLayoutManager(gridLayoutManager); mRecyclerView.setHasFixedSize(true); photoLayout = new int[2]; photoLayout[0]=(ScreenHelper.getScreenWidth(this) - ScreenHelper.dp2px(this, 20)) / 3 - ScreenHelper.dp2px(this, 10); photoLayout[1] = ScreenHelper.dp2px(this, 110); gridLayoutManager.findFirstCompletelyVisibleItemPosition(); initPhoto(); notifySubmit(); mAdapter = new AlbumAdapter(mRecyclerView,photoItemList,selectItemList); mAdapter.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(RecyclerView.ViewHolder viewHolder, int position) { notifySubmit(); } }); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { //停止滑動後快取當前螢幕圖片 if(newState == 0){ new Thread(new Runnable() { @Override public void run() { for(int i=gridLayoutManager.findFirstVisibleItemPosition();i<gridLayoutManager.findLastVisibleItemPosition();i++){ cacheBitmap(i); } } }).start(); } } }); mRecyclerView.setAdapter(mAdapter); handler = new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message msg) { mAdapter.notifyImage((int)msg.obj); return false; } }); } private void initPhoto(){ photoItemList = new ArrayList<>(); selectItemList = (List<PhotoItem>)getIntent().getSerializableExtra(FinalHelper.IMAGE_PATH); if(selectItemList == null) selectItemList = new ArrayList<>(); String path=""; for(int i=0;i<selectItemList.size();i++){ path += selectItemList.get(i).getPath()+","; } Cursor cursor = MediaStore.Images.Media.query(getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, STORE_IMAGES,"width >0","date_modified desc"); cursor.moveToNext(); for (int i = 0; i < cursor.getCount(); i++) { PhotoItem photoItem = new PhotoItem(cursor.getInt(3),path.indexOf(cursor.getString(6))!=-1?true:false,cursor.getString(0),cursor.getString(6)); photoItemList.add(photoItem); cursor.moveToNext(); } //從前往後存快取縮圖 單執行緒輪播減少記憶體消耗確保螢幕不卡頓 new Thread(new Runnable() { @Override public void run() { for(int i=0;i<photoItemList.size();i++){ cacheBitmap(i); } } }).start(); } //快取bitmap public void cacheBitmap(int position){ if(CacheManager.get(photoItemList.get(position).getPath())==null){ Bitmap bitmap = ImageHelper.getSmallCropBitmap(photoItemList.get(position).getPath(), photoLayout[0], photoLayout[1]); CacheManager.put(photoItemList.get(position).getPath(),bitmap); Message message = new Message(); message.obj=position; handler.sendMessage(message); } } public void notifySubmit(){ if(selectItemList.size()>0){ submit.setBackgroundResource(R.drawable.bg_album_submit_enable); submit.setText(getString(R.string.submit) + "(" + selectItemList.size() + ")"); submit.setTextColor(ContextCompat.getColor(this, R.color.white)); submit.setAlpha(1f); submit.setClickable(true); } else { submit.setBackgroundResource(R.drawable.bg_album_submit); submit.setTextColor(ContextCompat.getColor(this, R.color.darkgray)); submit.setAlpha(.8f); submit.setText(getString(R.string.submit)); submit.setClickable(false); } } public void onSubmit(View view){ Intent intent = new Intent(); intent.putExtra(FinalHelper.IMAGE_PATH, (Serializable) selectItemList); setResult(Activity.RESULT_OK, intent); finish(); } public void onBack(View view){ finish(); } public void onCancel(View view){ finish(); } }

在讀取相簿的基本資料後,採用單執行緒輪播的方式順序快取圖片縮率圖,這樣便解決了卡頓問題,在配合快取類,再次載入相簿就可以瞬間全部載入完畢,推薦使用開源的第三方庫DiskLruCache實現圖片的縮圖快取。
QQ相簿初次載入相簿圖片也是一張一張的,仿QQ相簿例項:http://blog.csdn.net/lishengko/article/details/56495553