Reputation: 222
What I want
I want to greate an own gallery application for myself. For that I want to load every image on the phone into a RecyclerView by GridLayoutManager.
What does work
I got every image from external storage with path. Images are displayed by the first time the app is started.
What does not work
When I scroll down in my RecyclerView the immages will be distorted like in the screenshot below.
I also got this error by logcat:
Process: com.spicysoftware.gallery, PID: 12209
java.lang.RuntimeException: Canvas: trying to draw too large(115650308bytes) bitmap.
at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java)
at android.graphics.Canvas.drawBitmap(Canvas.java)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java)
at android.widget.ImageView.onDraw(ImageView.java)
at android.view.View.draw(View.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.View.draw(View.java)
at android.view.ViewGroup.drawChild(ViewGroup.java)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.View.draw(View.java)
at android.view.ViewGroup.drawChild(ViewGroup.java)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java)
at android.view.View.draw(View.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.View.draw(View.java)
at android.view.ViewGroup.drawChild(ViewGroup.java)
at android.support.v7.widget.RecyclerView.drawChild(RecyclerView.java:4477)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java)
at android.view.View.draw(View.java)
at android.support.v7.widget.RecyclerView.draw(RecyclerView.java:3869)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java)
at android.view.View.updateDisplayListIfDirty(View.java)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java)
at android.view.ViewRootImpl.draw(ViewRootImpl.java)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java)
at android.view.Choreographer.doCallbacks(Choreographer.java)
at android.view.Choreographer.doFrame(Choreographer.java)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java)
at android.os.Handler.handleCallback(Handler.java)
at android.os.Handler.dispatchMessage(Handler.java)
at android.os.Looper.loop(Looper.java)
at android.app.ActivityThread.main(ActivityThread.java)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java)
This is how I load the images
public void loadAllImages(){
String[] mProjection = {MediaStore.Images.Media.DATE_TAKEN,MediaStore.Images.Media.DATA};
Cursor cursorImagesExternal = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,mProjection,null,null,MediaStore.Images.Media.DATE_ADDED);
List<ItemObject> allItems = new ArrayList<ItemObject>();
int countImages = 0;
while(cursorImagesExternal.moveToNext()) {
long date = cursorImagesExternal.getLong(0);
String fileLoc = cursorImagesExternal.getString(1);
allItems.add(new ItemObject(fileLoc));
countImages ++;
}
Log.v("Image Count: ", ""+countImages);
List<ItemObject> rowListItem = allItems;
lLayout = new GridLayoutManager(MainActivity.this, 4);
RecyclerView rView = (RecyclerView)findViewById(R.id.recycler_view);
rView.setHasFixedSize(true);
rView.setLayoutManager(lLayout);
RecyclerViewAdapter rcAdapter = new RecyclerViewAdapter(MainActivity.this, rowListItem);
rView.setAdapter(rcAdapter);
}
This is the adapter
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewHolders> {
private List<ItemObject> itemList;
private Context context;
public RecyclerViewAdapter(Context context, List<ItemObject> itemList) {
this.itemList = itemList;
this.context = context;
}
@Override
public RecyclerViewHolders onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_list, null);
RecyclerViewHolders rcv = new RecyclerViewHolders(layoutView);
return rcv;
}
@Override
public void onBindViewHolder(final RecyclerViewHolders holder, int position) {
//holder.countryName.setText(itemList.get(position).getName());
Glide.with(context).asBitmap()
.load(itemList.get(position).getName())
.thumbnail(0.5f)
.into(holder.countryPhoto);
}
@Override
public int getItemCount() {
return this.itemList.size();
}
}
card_view_list.xml
<android.support.v7.widget.CardView
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/card_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="4"
card_view:cardUseCompatPadding="true"
android:layout_marginBottom="16dp">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/country_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/action_settings"
android:src="@drawable/ic_remove_red_eye_black_24dp"
android:scaleType="centerCrop" />
</RelativeLayout>
</android.support.v7.widget.CardView>
My Questions
Is there a better way to load images to a GridView smoothly?
If not, what is wrong with my code?
Upvotes: 1
Views: 2482
Reputation: 3346
You may need to lower thumbnail float something like 0.2f or 0.1f.
Also you can give it a try MediaStore.Images.Thumbnails or another way to get thumbnail with your projection. Its not guaranteed that every image has thumbnail. You need to control it also.
In your glide request, you can remove .asBitmap()
if you dont mind to use callback to hang with bitmap.
You can inflate like
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_list, parent, false);
instead
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_list, null);
to get layout params.
You may give it a try to CursorLoaders to load images as async. So UI wont be struggled.
Good luck
Emre
Upvotes: 1
Reputation: 1720
int defaultImagePath = R.drawable.default_thumb;
int errorImagePath = R.drawable.damaged_image;
holder.countryPhoto.setImageResource(defaultImagePath);
String uri = itemList.get(position).getName();
loadImageWithGlide(mContext, holder.countryPhoto, uri, defaultImagePath,
errorImagePath);
public static void loadImageWithGlide(final Context context, ImageView theImageViewToLoadImage,
String theLoadImagePath, int theDefaultImagePath, int tehErrorImagePath) {
if (context == null) return;
//placeHolderUrl=R.drawable.ic_user;
//errorImageUrl=R.drawable.ic_error;
Glide.with(context) //passing context
.load(theLoadImagePath) //passing your url to load image.
.placeholder(theDefaultImagePath) //this would be your default image (like default profile or logo etc). it would be loaded at initial time and it will replace with your loaded image once glide successfully load image using url.
.error(tehErrorImagePath)//in case of any glide exception or not able to download then this image will be appear . if you won't mention this error() then nothing to worry placeHolder image would be remain as it is.
.diskCacheStrategy(DiskCacheStrategy.ALL) //using to load into cache then second time it will load fast.
//.animate(R.anim.fade_in) // when image (url) will be loaded by glide then this face in animation help to replace url image in the place of placeHolder (default) image.
//.fitCenter()//this method help to fit image into center of your ImageView
.into(theImageViewToLoadImage); //pass imageView reference to appear the image.
/* Normal way to Load Image with Glide.
Glide.with(theContext)
.load(theImagePath)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(theImageView);*/
}
Upvotes: 0