jess-anders / two-way-gridview

An Android GridView that can be configured to scroll horizontally or vertically
650 stars 261 forks source link

Two-way-gridview with simple cursor adapter jumbles images during update #32

Open lgorse opened 9 years ago

lgorse commented 9 years ago

I use your two-way-gridview (congrats on the simplicity of it by the way) to show a horizontal list of photos my user has taken. The gridview is backed by a simple cursor adapter, and it updates every time the user takes a picture (the photos are in reverse order of creation date). I do use a viewbinder because the picture loading is really slow on the default cursor adapter class.

The problem is that when the photos update, they listview will appear to run the cursor backa nd forth and update the imageviews multiple times. It's very confusing to the user as the imageviews update onces, then again, before re-updating a final time.

Here's the link of what that looks like: http://youtu.be/PZvKeKsQBUE

I'm guessing this is due to some confusion in the manipulation of columns to get the gridview to scroll horizontally - but hopefully there's a way around it? Here are the methods that update the gridview:

String[] from = {MediaStore.Images.ImageColumns.DATA};
        int[] to = {R.id.imageContent};
        TwoWayGridView imageListView = (TwoWayGridView) view.findViewById(R.id.imagelist);
        getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
        mMediaAdapter = new SimpleCursorAdapter(getActivity(), R.layout.imagelistview, null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        mMediaAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
            @Override
            public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
                if(view.getId() == R.id.imageContent){
                    BitmapWorkerTask task = new BitmapWorkerTask((ImageView) view, TwitterFragment.this);
                    task.execute(cursor.getString(columnIndex));
                    return true;
                }
                return false;
            }
        });
        imageListView.setAdapter(mMediaAdapter);
    }

 @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        switch(id){
            case CURSOR_LOADER_ID:
                if (args!= null){
                    String filePath = (String) args.get("uri");
                    File temp = new File(filePath);
                    getActivity().sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(temp)) );
                }
                Uri imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                Uri queryUri = imageUri.buildUpon().appendQueryParameter("limit", "10").build();
                Log.i("THE IMAGE PATH", String.valueOf(MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
                String queryFolder = "%streem%";
                String[] where = new String[]{queryFolder};
                return new CursorLoader(getActivity(), queryUri, null, MediaStore.Images.Media.DATA + " LIKE ? ", new String[]{queryFolder}, MediaStore.Images.ImageColumns.DISPLAY_NAME + " DESC");
            default:
                return null;
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        mMediaAdapter.changeCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        mMediaAdapter.changeCursor(null);

    }

///This gets called after a photo is successfully taken, so that the gridview can get updated.
 public void updatePhoto(ScreenShot screenShot){
                    if (screenShot != null){
                Bundle bundle = new Bundle();
                bundle.putString("uri", screenShot.getFilePath());
                getLoaderManager().restartLoader(CURSOR_LOADER_ID, bundle, this);
           }
    }

    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight){
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth){
            final int halfHeight = height /2;
            final int halfWidth = width / 2;

            while ((halfHeight/inSampleSize) > reqHeight
                && (halfWidth / inSampleSize > reqWidth)) {

              inSampleSize *=2;

            }
        }
        return inSampleSize;
    }

    private static Bitmap decodeSampledBitmapFromResource(String filePath, int reqWidth, int reqHeight){
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        Bitmap file = BitmapFactory.decodeFile(filePath, options);

        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filePath, options);
    }

    class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
        private final WeakReference<ImageView> imageViewReference;
        private int data = 0;
        private String filePath;
        private TwitterFragment activity;

        public BitmapWorkerTask(ImageView imageView, TwitterFragment activity){
            imageViewReference = new WeakReference<ImageView>(imageView);
            this.activity = activity;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            this.filePath = params[0];
          Bitmap bmp = decodeSampledBitmapFromResource(filePath, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);
          return bmp;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap){
            if (imageViewReference != null && bitmap != null){
                final ImageView imageView = imageViewReference.get();
                if (imageView != null){
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
    }
jess-anders commented 9 years ago

The video is private, but my guess is that you are not correctly recycling the view. You probably want to set the ImageView image to null when you start the task to reload it. You also should really cache the images in an LRUCache.

demilaram commented 8 years ago

i have the same issue working with twowaygridview library, i am using lrucache already, and every time i call notifydatasetchanged() on list adapter it refreshes everything, casing list view to flicker a lot. any help please?