i have a grid view with 6 cells loading in adapter. when i click each cell,i am going to add image either from taking photos or choosing images from gallery.after selecting images, the grid view is showing empty only. though i set image in one cell,when go for another cell,the previous selection is gone. how to make it done?.. plea help me. if i am anything wrong , please guide me.
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.fpc_document_view, null);
TextView textView = (TextView) grid.findViewById(R.id.grid_text);
imageView = (ImageView) grid.findViewById(R.id.grid_image);
if (fileList.size() == 0) {
textView.setText(DOCUMENT_NAME_LIST[position].toString());
for (int i = 0; i <= 6; i++) {
imageView.setImageResource(R.mipmap.ic_add_document);
}
} else {
Bitmap bitmapResized = null;
for (int i = 0; i < fileList.size(); i++) {
if (!fileList.get(i).equals("")) {
System.out.println("fileList here ,,,," + fileList.get(i).toString());
Drawable drawable = mContext.getResources().getDrawable(R.mipmap.ic_add_document);
bitmapResized = ((BitmapDrawable) drawable).getBitmap();
} else {
Uri selectedImageUri = Uri.fromFile(fileList.get(i));
bitmapResized = ImageRelatedStuff.convertURIToBitmap(selectedImageUri, mContext);
if (bitmapResized != null) {
Bitmap bitmapTemp = bitmapResized;
bitmapResized = null;
bitmapResized = ImageRelatedStuff.getResizedBitmap(bitmapTemp, 500, 500, 0);
}
}
imageView.setImageBitmap(ImageRelatedStuff.getRoundedCornerBitmap(bitmapResized, 15));
}
}
} else {
grid = convertView;
imageView = (ImageView) grid.findViewById(R.id.grid_image);
}
Change your code like this:
if (convertView == null) {
grid = new View(mContext);
grid = inflater.inflate(R.layout.fpc_document_view, null);
TextView textView = (TextView) grid.findViewById(R.id.grid_text);
imageView = (ImageView) grid.findViewById(R.id.grid_image);
} else {
grid = convertView;
imageView = (ImageView) grid.findViewById(R.id.grid_image);
}
if (fileList.size() == 0) {
textView.setText(DOCUMENT_NAME_LIST[position].toString());
for (int i = 0; i <= 6; i++) {
imageView.setImageResource(R.mipmap.ic_add_document);
}
} else {
Bitmap bitmapResized = null;
for (int i = 0; i < fileList.size(); i++) {
if (!fileList.get(i).equals("")) {
System.out.println("fileList here ,,,," + fileList.get(i).toString());
Drawable drawable = mContext.getResources().getDrawable(R.mipmap.ic_add_document);
bitmapResized = ((BitmapDrawable) drawable).getBitmap();
} else {
Uri selectedImageUri = Uri.fromFile(fileList.get(i));
bitmapResized = ImageRelatedStuff.convertURIToBitmap(selectedImageUri, mContext);
if (bitmapResized != null) {
Bitmap bitmapTemp = bitmapResized;
bitmapResized = null;
bitmapResized = ImageRelatedStuff.getResizedBitmap(bitmapTemp, 500, 500, 0);
}
}
imageView.setImageBitmap(ImageRelatedStuff.getRoundedCornerBitmap(bitmapResized, 15));
}
}
Problem is when your convertView is not equals null you are not setting anything image on imageView. That is why on 2nd cell where convertView is null you are getting image while on previous cell which is not null you are getting nothing.
public class MyAdapter extends BaseAdapter{
private final int GRID_COUNT = 6;
// you need an array save bitmap with position
Bitmap[] bitmapArray;
public MyAdapter(){
bitmapArray = new Bitmap[GRID_COUNT];
}
#Override
public int getCount() {
return 6;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null){
// inflater your layout
}
ImageView imageView = (ImageView) convertView.findViewById(R.id.grid_image);
// get the bitmap in array by position
Bitmap bitmap = bitmapArray[position];
// when bitmap is null ,show default picture
if (bitmap == null){
imageView.setBackgroundResource(R.drawable.ic_default);
}else{
imageView.setImageBitmap(bitmap);
}
return convertView;
}
// activity or fragment use this method call adapter refresh
public void setBitmap(int position, Bitmap bitmap){
bitmapArray[position] = bitmap;
notifyDataSetChanged();
}
}
update my answer, hope help you
Related
Hello I am using listview and display images from server into it.
But the problem is that all loaded images are displayed in last item one by one instead display on respective position.
please help me to display that images in respective position
public class Offer_adapter extends ArrayAdapter<String> {
Context context1;
String[] offer_title;
String[] offerimg1;
String[] mrp;
String[] offerprice;
String[] you_save;
String[] imgURLArray;
Bitmap bitmap;
ImageView offerimg;
int a;
LayoutInflater inflater1;
public Offer_adapter(Context context1, String[] offer_title, String[] offerimg1, String[] mrp, String[] you_save, String[] offerprice) {
super(context1, R.id.offer_list, offer_title);
this.context1 = context1;
this.offer_title = offer_title;
this.offerimg1 = offerimg1;
this.mrp = mrp;
this.offerprice = offerprice;
this.you_save = you_save;
}
private static class ViewHolder {
String offerimg;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
inflater1 = (LayoutInflater) context1.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater1.inflate(R.layout.offer_list, null);
viewHolder = new ViewHolder();
}
android.util.Log.v("abhi", "" + position);
imgURLArray = new String[position + 1];
for (int i = 0; i <= position; i++) {
android.util.Log.v("abhijit", "" + position);
imgURLArray[i] = "http://www.surun.co/preost/mod_offer/images/" + offerimg1[position];
android.util.Log.v("abhi", "" + imgURLArray[position]);
}
a=position;
viewHolder = (ViewHolder) convertView.getTag();
TextView offertitle = (TextView) convertView.findViewById(R.id.ofrtitle);
TextView offermrp = (TextView) convertView.findViewById(R.id.offeroriginal);
offermrp.setPaintFlags(offermrp.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
TextView offersave = (TextView) convertView.findViewById(R.id.saveoffer);
TextView ofrprice = (TextView) convertView.findViewById(R.id.priceoffer);
offerimg = (ImageView) convertView.findViewById(R.id.ofr_img);
offertitle.setText(offer_title[position]);
offermrp.setText("Original Price: \u20B9" + mrp[position]);
offersave.setText("You Save: \u20B9" + you_save[position]);
ofrprice.setText("Offer Price: \u20B9" + offerprice[position]);
// Bitmap imageBitmap = null;
new DownloadAsyncTask().execute(imgURLArray[position]);
Log.v("abhi","async");
return convertView;
}
private class DownloadAsyncTask extends AsyncTask<String, String, Bitmap> {
protected Bitmap doInBackground(String... args) {
try {
Log.v("abhi","in do background");
bitmap = BitmapFactory.decodeStream((InputStream) new URL(args[0]).getContent());
bitmap = Bitmap.createScaledBitmap(bitmap, 270, 375, true);
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (bitmap !=null) {
offerimg.setImageBitmap(bitmap);
} else {
offerimg.setImageResource(R.drawable.nooffer);
}
}
}
}
All images are shown in last item one after another. I just want to show it on respective position.
you should use lazyloading instead of downloading image as bitmap.
Bitmap will create problem sometime or will give you outofmemory error in some devices
There are lots of image loading library available for android.
Have a look at these
https://github.com/square/picasso
https://github.com/nostra13/Android-Universal-Image-Loader
https://code.google.com/p/android-query/wiki/ImageLoading
https://android.googlesource.com/platform/frameworks/volley
https://github.com/koush/UrlImageViewHelper
https://github.com/novoda/image-loader
I know that this question is asked many times.. But I cant get any proper solution, In my app I use AsyncTask for loading a image. I use AsyncTask because I want smooth scrolling listview.. and after implement AsyncTask My listView get smoothly scrolling.. But now problem is that Image is changing after scrolling... What should I do?
MyAdapter Class
package com.example.adapter;
public class DisplayAllFeedAdapter extends ArrayAdapter<DisplayAllFeedItem> {
private final List<DisplayAllFeedItem> list;
private final Activity context;
ExifInterface exif;
public DisplayAllFeedAdapter(Activity context, List<DisplayAllFeedItem> list) {
super(context, R.layout.feed_screen, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
public TextView optionalDesc, reportedBy;
public LinearLayout layout;
public ImageView displayFeedimg, channelIcon;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.display_all_feed_listitem, null);
viewHolder = new ViewHolder();
viewHolder.optionalDesc = (TextView) convertView.findViewById(R.id.txtFeedOptionalDesc);
viewHolder.reportedBy = (TextView) convertView.findViewById(R.id.txtFeedReportedBy);
viewHolder.displayFeedimg = (ImageView) convertView
.findViewById(R.id.imgFeedDisplayImage);
viewHolder.layout = (LinearLayout) convertView.findViewById(R.id.layoutChannelImgView);
convertView.setTag(viewHolder);
convertView.setTag(R.id.txtFeedOptionalDesc, viewHolder.optionalDesc);
convertView.setTag(R.id.txtFeedReportedBy, viewHolder.reportedBy);
convertView.setTag(R.id.imgFeedDisplayImage, viewHolder.displayFeedimg);
convertView.setTag(R.id.layoutChannelImgView, viewHolder.layout);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
String temp;
String drawableImagePath = list.get(position).getMediaChannelName();
List<String> channelList = new ArrayList<String>();
while (drawableImagePath.length() > 0) {
if (drawableImagePath.indexOf(",") == -1) {
temp = drawableImagePath.substring(0);
channelList.add(temp);
break;
} else {
temp = drawableImagePath.substring(0, drawableImagePath.indexOf(","));
}
channelList.add(temp);
drawableImagePath = drawableImagePath.substring(drawableImagePath.indexOf(",") + 1);
}
viewHolder.layout.removeAllViews();
for (int i = 0; i < channelList.size(); i++) {
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(dpToPx(30),
dpToPx(30));
ImageView imageView = new ImageView(context);
layoutParams.setMargins(0, 0, 10, 0);
imageView.setLayoutParams(layoutParams);
imageView.setImageResource(Integer.parseInt(channelList.get(i)));
viewHolder.layout.addView(imageView);
}
String tempPath = list.get(position).getMediaPath();
File mediaFile = new File(tempPath);
Bitmap bitmap;
viewHolder.optionalDesc.setText(list.get(position).getMediaDesc());
viewHolder.reportedBy.setText("Reported By " + list.get(position).getMediaDisplayName());
if (viewHolder != null) {
new LoadImage(viewHolder).execute(tempPath);
}
return convertView;
}
private class LoadImage extends AsyncTask<String, String, Bitmap> {
// File mediaFile = new File(tempPath);
Bitmap bitmap, displayBitmap;
File mediaFile;
String mediaPath;
private final ViewHolder imageViewReference;
public LoadImage(ViewHolder viewHolder) {
imageViewReference = viewHolder;
}
#Override
protected Bitmap doInBackground(String... params) {
// File f = new File(params[0]);
mediaPath = params[0];
mediaFile = new File(mediaPath);
if (mediaFile.exists()) {
if (isImage(mediaPath)) {
Bitmap myBitmap = BitmapFactory.decodeFile(mediaFile.getAbsolutePath());
int height = (myBitmap.getHeight() * 512 / myBitmap.getWidth());
Bitmap scale = Bitmap.createScaledBitmap(myBitmap, 512, height, true);
int rotate = 0;
try {
exif = new ExifInterface(mediaFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
rotate = 0;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
displayBitmap = Bitmap.createBitmap(scale, 0, 0, scale.getWidth(),
scale.getHeight(), matrix, true);
} else {
displayBitmap = ThumbnailUtils.createVideoThumbnail(mediaPath,
Thumbnails.MICRO_KIND);
}
}
return displayBitmap;
}
#Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
if (imageViewReference != null) {
imageViewReference.displayFeedimg.setImageBitmap(result);
}
// tempView.displayFeedimg.setImageBitmap(result);
}
}
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int px = Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
return px;
}
public static boolean isImage(String str) {
boolean temp = false;
String[] arr = { ".jpeg", ".jpg", ".png", ".bmp", ".gif" };
for (int i = 0; i < arr.length; i++) {
temp = str.endsWith(arr[i]);
if (temp) {
break;
}
}
return temp;
}
}
I am not clear on your problem (need better clarification) but I know there are issues on loading images about the lag in performance.
Please Look at Google's web Making a Standard Request.
Search for (Universal) Image Loader, text "Use ImageLoader and NetworkImageView".
You can further improve performance by caching, located below that text.
Code snippet from the webpage:
ImageLoader mImageLoader;
ImageView mImageView;
// The URL for the image that is being loaded.
private static final String IMAGE_URL =
"http://developer.android.com/images/training/system-ui.png";
...
mImageView = (ImageView) findViewById(R.id.regularImageView);
// Get the ImageLoader through your singleton class.
mImageLoader = MySingleton.getInstance(this).getImageLoader();
mImageLoader.get(IMAGE_URL, ImageLoader.getImageListener(mImageView,
R.drawable.def_image, R.drawable.err_image));
There seems a good tutorial in Solving the Android image loading problem... by a knowledgeable author.
Have fun with this. And someday I may have to solve this problem as well. Pls keep us posted.
Besides my previous answer, there is another possible solution. But it is somewhat different than Google's recommendation, so beware...
Look at Stackoverflow discussion ListView like in universal image loader sample app. Checkout code in that page. In CarListAdapter:
ImageLoader = ImageLoader.getInstance();
imageLoader.init(ImageLoaderConfiguration.createDefault(context));
...In another method:
imageLoader.displayImage(...);
Both of my answers lead to one point, use the (Universal) Image Loader.
I use custom ArrayAdapter to populate listview.
I use Picasso to load images, before loading image I calculate height and width for each image. Thus dynamic ImageView has different height and width.
When I scroll up the listview, everything is smooth. But when I scroll the listview down, list starts to jump, when it comes to the rows with images.
I think, it caused by listview elements recycle, it forgets dynamic imageviews heights and produce this jumping effect when it recalculating imageviews again. I attach my dynamic imageview to Holder, but it doesn't help.
Part of my adapter looks like this:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ChatMessageElement el = list.get(position);
ViewHolder holder = null;
NewMessagesLabelHolder labelHolder = null;
if (convertView == null) {
convertView = el.getView(inflater, parent);
if (el.isMessage()) {
holder = new ViewHolder();
holder.messageLayout = (RelativeLayout) convertView.findViewById(R.id.message_container);
holder.messageContent = (LinearLayout) convertView.findViewById(R.id.message_content);
holder.bottomIndicator = (LinearLayout) convertView.findViewById(R.id.bottom_indicators);
holder.dateTextView = (TextView) convertView.findViewById(R.id.message_date);
holder.timeAgo = (TextView) convertView.findViewById(R.id.time_ago);
holder.nameTextView = (TextView) convertView.findViewById(R.id.user_name);
convertView.setTag(holder);
}
} else {
if (el.isMessage()) {
holder = (ViewHolder) convertView.getTag();
}
}
if (el.isMessage()) {
Message currentMessage = (Message) el;
drawMessage(holder, currentMessage, position);
}
return convertView;
}
private void drawMessage(ViewHolder holder, Message message, int position) {
String date = message.getCreatedAt();
String formattedDate = Helper.getInstance().formatDate("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", "HH:mm", date);
String userName = message.getUserName();
holder.likesLabelImageView.setVisibility(View.GONE);
holder.likesCountTextView.setVisibility(View.GONE);
holder.nameTextView.setText(userName);
holder.dateTextView.setText(formattedDate);
if (message.isLiked()) {
holder.likesCountTextView.setText(Integer.toString(message.getLikesCount()));
holder.likesCountTextView.setVisibility(View.VISIBLE);
holder.likesLabelImageView.setVisibility(View.VISIBLE);
}
List<MessageComponent> messageComponentList;
messageComponentList = message.getMessageComponents();
drawMessageContent(holder, messageComponentList, message);
holder.nameTextView.setTag(position);
holder.avatarImageView.setTag(position);
holder.nameTextView.setOnClickListener(userClickListener);
holder.avatarImageView.setOnClickListener(userClickListener);
// hang empty onLingClickListener to display context menu when
// long click on whole message
holder.nameTextView.setOnLongClickListener(longClickListener);
holder.avatarImageView.setOnLongClickListener(longClickListener);
}
private void drawMessageContent(ViewHolder holder, final List<MessageComponent> messageComponentList, final Message msg) {
holder.messageContent.removeAllViewsInLayout();
int messageComponentListSize = messageComponentList.size();
for (final MessageComponent messageComponent : messageComponentList) {
messageComponentListSize--;
if (messageComponentListSize == 0)
iAmLast = true;
final String type = messageComponent.getType();
if (type.equals(MessageComponent.MESSAGE_COMPONENT_TEXT_TYPE)) {
TextView textView = new TextView(context);
textView.setText(messageComponent.getText());
setViewBackground(textView, msg);
//reset margins for texts, caused by margin changes for images
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) holder.bottomIndicator.getLayoutParams();
params.setMargins(45, -82, 0, 0);
holder.bottomIndicator.setLayoutParams(params);
holder.messageContent.addView(textView);
}
if (type.equals(MessageComponent.MESSAGE_COMPONENT_IMAGE_TYPE)) {
ViewGroup.LayoutParams params = new ActionBar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
thumbHeight
);
final RoundedImageView imageView = new RoundedImageView(context);
imageView.setPadding(20, 0, 20, 20);
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setCornerRadius(15.0f);
mHandler.post(new Runnable() {
#Override
public void run() {
drawPreview(messageComponent, imageView);
}
});
imageView.setLayoutParams(params);
// hang empty onLingClickListener to display context menu when
// long click on whole message
imageView.setOnLongClickListener(longClickListener);
final RelativeLayout mediaContainer = new RelativeLayout(context);
mediaContainer.addView(imageView);
}
}
}
// Calculates restricted dimensions with a maximum of $goal_width by $goal_height
private ImageSize resize_dimensions(float goal_width, float goal_height, float width, float height) {
float ratio = Math.min(goal_width/width, goal_height/height);
int nwidth = Math.round(width*ratio);
int nheight = Math.round(height*ratio);
if(nwidth>nheight*2)
nheight = 400;
if(nheight>nwidth*2)
nwidth = 600;
ImageSize imageSize = new ImageSize(nwidth, nheight);
return imageSize;
}
private void drawPreview(MessageComponent messageComponent, final ImageView imageView) {
String type = messageComponent.getType();
String mediaPath = messageComponent.getMediaPath();
String thumbPath = messageComponent.getThumbPath();
String thumbUrl = messageComponent.getThumbUrl();
String videoThumbPath = messageComponent.getVideoThumbPath();
Uri uri = null;
if (type.equals(MessageComponent.MESSAGE_COMPONENT_IMAGE_TYPE)) {
if (!TextUtils.isEmpty(mediaPath)) {
uri = Uri.parse("file://" + mediaPath);
File file = new File(uri.getPath());
if (file.exists()) {
resizeAndLoadThumbnail(uri, imageView);
return;
}
}
if (!TextUtils.isEmpty(thumbPath)) {
uri = Uri.parse("file://" + mediaPath);
File file = new File(uri.getPath());
if (file.exists()) {
resizeAndLoadThumbnail(uri, imageView);
return;
}
}
if (thumbUrl != null) {
uri = Uri.parse(thumbUrl);
}
if (uri != null) {
resizeAndLoadThumbnail(uri, imageView);
return;
}
}
}
private void resizeAndLoadThumbnail(Uri uri, final ImageView imageView) {
Picasso.with(context).load(uri).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
ImageSize imgSize = resize_dimensions(900, 900, width, height);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
imgSize.width,
imgSize.height
);
imageView.setLayoutParams(params);
imageView.setImageBitmap(bitmap);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
I am getting listView items duplicated if I play a song in the background and go back to the app on clicking the notification icon. While opening the app for the first time, items are not duplicated. What could be wrong? Posting below my adapter class.
Adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder = null;
final int pos = position;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (RelativeLayout) inflater.inflate(R.layout.song, parent,
false);
holder = new ViewHolder();
holder.tvTitle = (TextView) view.findViewById(R.id.tv_song_title);
holder.tvArtist = (TextView) view.findViewById(R.id.tv_song_artist);
holder.imgAlbumArt = (ImageView) view
.findViewById(R.id.img_lv_album_art);
holder.tvArtist.setText(songs.get(position).getArtist());
holder.tvTitle.setText(songs.get(position).getTitle());
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
int id = (int) songs.get(position).getId();
if (bitmaps == null) {
Bitmap bm = MainActivity.getCachedArtwork(mContext,
id, MainActivity.getDefaultArtwork(mContext));
holder.imgAlbumArt.setImageBitmap(bm);
bitmaps.put(id, bm);
Log.d("inside null", "key=" + id + "bm=" + bm + "pos" + position);
} else if (bitmaps.containsKey(id)) {
Bitmap bm = bitmaps.get(id);
holder.imgAlbumArt.setImageBitmap(bm);
bitmaps.put(id, bm);
Log.d("inside contains key", "key=" + id + "bm=" + bm + "pos"
+ position);
} else {
Bitmap bm = MainActivity.getCachedArtwork(mContext,
id, MainActivity.getDefaultArtwork(mContext));
holder.imgAlbumArt.setImageBitmap(bm);
bitmaps.put(id, bm);
Log.d("inside else", "key=" + id + "bm=" + bm + "pos" + position);
}
return view;
}
MainActivity:
public static Bitmap getCachedArtwork(Context context, int artIndex,
Bitmap defaultArtwork) {
Bitmap d = null;
synchronized (sArtCache) {
d = sArtCache.get(artIndex);
}
if (d == null) {
d = defaultArtwork;
final Bitmap icon = defaultArtwork;
int w = icon.getWidth();
int h = icon.getHeight();
Bitmap b = getArtworkQuick(context, artIndex, w, h);
if (b != null) {
d = b;// new FastBitmapDrawable(b);
synchronized (sArtCache) {
// the cache may have changed since we checked
Bitmap value = sArtCache.get(artIndex);
if (value == null) {
sArtCache.put(artIndex, d);
} else {
d = value;
}
}
}
}
return d;
}
// Get album art for specified album. This method will not try to
// fall back to getting artwork directly from the file, nor will
// it attempt to repair the database.
private static Bitmap getArtworkQuick(Context context, int album_id, int w, int h) {
// NOTE: There is in fact a 1 pixel frame in the ImageView used to
// display this drawable. Take it into account now, so we don't have to
// scale later.
w -= 2;
h -= 2;
ContentResolver res = context.getContentResolver();
Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
if (uri != null) {
ParcelFileDescriptor fd = null;
try {
fd = res.openFileDescriptor(uri, "r");
int sampleSize = 1;
// Compute the closest power-of-two scale factor
// and pass that to sBitmapOptionsCache.inSampleSize, which will
// result in faster decoding and better quality
sBitmapOptionsCache.inJustDecodeBounds = true;
BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, sBitmapOptionsCache);
int nextWidth = sBitmapOptionsCache.outWidth >> 1;
int nextHeight = sBitmapOptionsCache.outHeight >> 1;
while (nextWidth>w && nextHeight>h) {
sampleSize <<= 1;
nextWidth >>= 1;
nextHeight >>= 1;
}
sBitmapOptionsCache.inSampleSize = sampleSize;
sBitmapOptionsCache.inJustDecodeBounds = false;
Bitmap b = BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, sBitmapOptionsCache);
if (b != null) {
// finally rescale to exactly the size we need
if (sBitmapOptionsCache.outWidth != w || sBitmapOptionsCache.outHeight != h) {
Bitmap tmp = Bitmap.createScaledBitmap(b, w, h, true);
b.recycle();
b = tmp;
}
}
return b;
} catch (FileNotFoundException e) {
} finally {
try {
if (fd != null)
fd.close();
} catch (IOException e) {
}
}
}
return null;
}
I hope the title is not mis-leading. I am trying to implement onRetainNonConfigurationInstance() of an AsyncTask of loading images and am getting this error "Java.lang.RuntimeException:Unable to retain Activity". Here is my code for onRetainNonConfigurationInstance():
public Object onRetainNonConfigurationInstance(){
//final ListView listview = list;
final int count = list.getChildCount();
final LoadedImage[] mylist = new LoadedImage[count];
for(int i = 0; i < count; i++){
final ImageView v = (ImageView)list.getChildAt(i); // getting error here
mylist[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
}
return mylist;
}
Here is the Logcat:
05-18 08:43:15.385: E/AndroidRuntime(28130): java.lang.RuntimeException: Unable to retain activity {com.MyApps.ImageGen/com.MyApps.ImageGen.Wallpapers}: java.lang.ClassCastException: android.widget.LinearLayout
05-18 08:43:15.385: E/AndroidRuntime(28130): at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:2989)
05-18 08:43:15.385: E/AndroidRuntime(28130): at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3100)
05-18 08:43:15.385: E/AndroidRuntime(28130): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3216)
05-18 08:43:15.385: E/AndroidRuntime(28130): at android.app.ActivityThread.access$1600(ActivityThread.java:132)
Here is my layout with the ListView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:listSelector="#android:color/transparent" >
</ListView>
</LinearLayout>
Here is how I setup the ListView:
private void setupViews() {
list = (ListView)findViewById(android.R.id.list);
list.setDivider(null);
list.setDividerHeight(0);
imageAdapter = new ImageAdapter(getApplicationContext());
list.setAdapter(imageAdapter);
list.setOnItemClickListener(this);
}
my async task and Item Adapter:
class LoadImagesFromSDCard extends AsyncTask<Object, LoadedImage, Object> {
#Override
protected Object doInBackground(Object... params) {
Bitmap bitmap = null;
Bitmap newbitmap = null;
Uri uri = null;
String [] img = {MediaStore.Images.Media._ID};
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, img, null, null, null);
} else {
// cursor = getContentResolver().query(MediaStore.Images.Media.INTERNAL_CONTENT_URI, img, null, null, null);
inInternalStorage = true;
}
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID);
int size = cursor.getCount();
if(size == 0){
//Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();
//System.out.println("size equals zero");
Wallpaper.this.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "There are no Images on the sdcard", Toast.LENGTH_SHORT).show();
}
});
return params;
}else {
}
for(int i = 0; i < size; i++){
cursor.moveToPosition(i);
int ImageId = cursor.getInt(column_index);
if(inInternalStorage == true){
uri = Uri.withAppendedPath(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "" + ImageId);
}else {
uri = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + ImageId);
}
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
Log.i(TAG, "imageheight = " + imageHeight);
Log.i(TAG, "imagewidth = " + imageWidth);
Log.i(TAG, "imageType = " + imageType);
//options.inSampleSize=4;
options.inSampleSize = calculateInSampleSize(options, imageWidth, imageHeight);
options.inJustDecodeBounds = false;
//bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri), null, options);
if(bitmap != null){
newbitmap = Bitmap.createScaledBitmap(bitmap, 180, 180, true);
bitmap.recycle();
}
if(newbitmap != null){
publishProgress(new LoadedImage(newbitmap));
}
}catch(IOException e){
}
//cursor.close();
}
cursor.close();
return null;
}
#Override
public void onProgressUpdate(LoadedImage... value){
addImage(value);
}
#Override
protected void onPostExecute(Object result) {
setProgressBarIndeterminateVisibility(false);
}
}
private static class LoadedImage {
Bitmap mBitmap;
LoadedImage(Bitmap bitmap) {
mBitmap = bitmap;
}
public Bitmap getBitmap() {
return mBitmap;
}
}
/*Image Adapter to populate grid view of images*/
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();
public ImageAdapter(Context context){
this.mContext = context;
}
public void addPhotos(LoadedImage photo){
photos.add(photo);
}
#Override
public int getCount() {
return photos.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView image;
ViewHolder holder;
if(convertView == null){
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//convertView = inflater.inflate(R.layout.image_list,null);
convertView = inflater.inflate(R.layout.media_view, null);
holder = new ViewHolder();
holder.image = (ImageView)convertView.findViewById(R.id.media_image_id);
//holder.item_name = (TextView)convertView.findViewById(R.id.media_image_id);
convertView.setTag(holder);
} else{
holder = (ViewHolder)convertView.getTag();
}
//holder.image.setLayoutParams(new GridView.LayoutParams(100, 100));
//String item_name = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME));
holder.image.setImageBitmap(photos.get(position).getBitmap());
//holder.item_name.setText(item_name);
return convertView;
}
}
static class ViewHolder {
ImageView image;
TextView item_name;
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Cursor cursor = null;
int image_column_index = 0;
String[] proj = {MediaStore.Images.Media.DATA};
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
cursor = managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,proj,null, null,null);
}else{
cursor = managedQuery(MediaStore.Images.Media.INTERNAL_CONTENT_URI,proj,null, null,null);
}
cursor.moveToPosition(position);
image_column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
String info = cursor.getString(image_column_index);
Intent imageviewer = new Intent(getApplicationContext(), ViewImage.class);
imageviewer.putExtra("pic_name", info);
startActivity(imageviewer);
cursor.close();
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 2;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
/*final int REQUIRED_SIZE = 180;
int scale = 1;
if(reqWidth > REQUIRED_SIZE || reqHeight > REQUIRED_SIZE){
scale = (int)Math.pow(2, (int)Math.round(Math.log(REQUIRED_SIZE/(double)Math.max(reqHeight, reqWidth)) / Math.log(0.5)));
}*/
return inSampleSize;
}
other Methods within Async Task:
private void loadImages() {
final Object data = getLastNonConfigurationInstance();
if(data == null){
new LoadImagesFromSDCard().execute();
}else {
final LoadedImage[] photos = (LoadedImage[])data;
if(photos.length == 0){
new LoadImagesFromSDCard().execute();
}
for(LoadedImage photo:photos){
addImage(photo);
}
}
}
private void addImage(LoadedImage... value) {
for(LoadedImage photo: value){
imageAdapter.addPhotos(photo);
imageAdapter.notifyDataSetChanged();
}
}
I am assuming I should first get the root element before I get the ListView from the logcat error, but I don't know how, I can't seem to find a suitable method from the documentation.
P.S: I am using an Activity and not a ListActivity.
The exception tells you that you try to do an invalid cast. My guess is that your row layout isn't a simple ImageView like you assume with the cast in the onRetainNonConfigurationInstance(), instead your row layout probably has a parent Linearlayout that wraps the ImageView(and other views?!). When you call the method getChildAt you get that parent Linearlayout which you try to cast to a ImageView. Instead you should do this:
//...
for(int i = 0; i < count; i++){
LinearLayout parent = (LinearLayout)list.getChildAt(i);
final ImageView v = (ImageView) parent.findViewById(R.id.the_id_of_the_imageview_from_theRow_layout);
mylist[i] = new LoadedImage(((BitmapDrawable) v.getDrawable()).getBitmap());
}
Note: The getChildAt method returns the rows views for the visible rows only so if you try to access the View for a row that isn't currently visible you'll most likely end up with a NullPointerException(you should get the drawables directly from the adapter and not from parsing all the rows Views).
Edit based on the comments:
If I understood your problem, the behavior you see it's normal. You didn't say how you ended up getting the bitmaps in the onRetainNonConfigurationInstance but my guess is that you just save the images from the ListView rows that are currently visible to the user. When it's time to restore the adapter with the images from getLastNonConfigurationInstance() you end up getting only those images which were previously visible. This will get worse if you rotate the phone again as, most likely, there are fewer images visible in landscape orientation then in the portrait orientation.
I don't know if this will work but you could try to modify the LoadedImage class to store the id of the image from MediaStore.Images.Media. When it's time to save the configuration, stop the LoadImagesFromSDCard task and nullify all the images(remove the Bitmap to which LoadedImage points)from the LoadedImages ArrayList(in the adapter) except the ones that are currently visible to the user. Send the photos ArrayList from your adapter through
onRetainNonConfigurationInstance.
When it's time to restore the adapter set the photos ArrayList of your new adapter to the one you got back and put the ListView to the position of the visible images(so the user sees the sent images). In the getView method of your adapter you'll put a default image(like loading...) when you have a null value for the Bitmap in the associated LoadedImage class. Start a new LoadImagesFromSDCard task to get the images and parse them again. When you get the id from MediaStore.Images.Media you'll check if a LoadedImage with this id exists in the adapter and if it has a Bitmap set to it. If it doesn't exist(or it doesn't have a Bitmap associated) then load the image and put it in the adapter, if not the image already exists and move to the next one.
I don't know if the solution above will work or if it's efficient. I would recommend you to modify the code and load images on demand instead of loading all up in a big task.