Aksiom
Aksiom

Reputation: 1585

IllegalArgumentException: Cannot draw recycled bitmaps

So I have a ExpandableListView and inside the child views I have a ListView. When I click on one of the items it opens another activity. The problem occurs when I press back and click on another list item. When I do that I get the mentioned exception. I never use a bitmap, so I really don't know what is causing the problem, is the redrawing of the items the problem or?

I read (ref. Caching Bitmaps ) that I should implement a caching mechanism, but I don't know how to start and what should I cache if I don't use any bitmaps? What am I missing here?

The Logcat:

09-10 05:48:03.345: E/AndroidRuntime(21011): FATAL EXCEPTION: main
09-10 05:48:03.345: E/AndroidRuntime(21011): java.lang.IllegalArgumentException: Cannot    draw recycled bitmaps
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:789)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.GLES20RecordingCanvas.drawBitmap(GLES20RecordingCanvas.java:118)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:393)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.ImageView.onDraw(ImageView.java:967)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13707)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12645)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12643)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13710)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.FrameLayout.draw(FrameLayout.java:467)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.ScrollView.draw(ScrollView.java:1576)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12645)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13710)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.FrameLayout.draw(FrameLayout.java:467)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.HorizontalScrollView.draw(HorizontalScrollView.java:1562)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12645)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12643)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12643)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12643)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13423)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.drawChild(ViewGroup.java:2928)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2797)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.draw(View.java:13710)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.widget.FrameLayout.draw(FrameLayout.java:467)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2211)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12645)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.View.getDisplayList(View.java:12689)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:1198)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewRootImpl.draw(ViewRootImpl.java:2173)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2045)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1854)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:989)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4351)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.Choreographer.doCallbacks(Choreographer.java:562)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.Choreographer.doFrame(Choreographer.java:532)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.os.Handler.handleCallback(Handler.java:725)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.os.Handler.dispatchMessage(Handler.java:92)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.os.Looper.loop(Looper.java:137)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at android.app.ActivityThread.main(ActivityThread.java:5191)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at java.lang.reflect.Method.invokeNative(Native Method)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at java.lang.reflect.Method.invoke(Method.java:511)
09-10 05:48:03.345: E/AndroidRuntime(21011):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
09-10 05:48:03.345: E/AndroidRuntime(21011):    a

The code:

My expandable list adapter:

public class StaffExpandableListAdapter extends BaseExpandableListAdapter {

private ArrayList<StaffGroup> staffGroups;
private LayoutInflater layoutInflater;
private Resources resource;
private RoomAdapter ra;

private Context context;

public StaffExpandableListAdapter(Context context,
        ArrayList<StaffGroup> staffGroups) {
    this.staffGroups = staffGroups;
    this.layoutInflater = LayoutInflater.from(context);
    this.resource = context.getResources();
    this.ra = new RoomAdapter(context);

    this.context = context;
}

@Override
public Object getChild(int groupPosition, int childPosition) {
    StaffChild staffChild = staffGroups.get(groupPosition)
            .getStaffDetails();
    return staffChild;
}

@Override
public long getChildId(int groupPosition, int childPosition) {
    return childPosition;
}

@Override
public View getChildView(int groupPosition, int childPosition,
        boolean isLastChild, View convertView, ViewGroup parent) {
    final StaffChild staffChildInfo = (StaffChild) getChild(groupPosition,
            childPosition);
    ViewHolderChild holder;
    if (convertView == null) {
        convertView = layoutInflater
                .inflate(R.layout.child_row_staff, null);
        holder = new ViewHolderChild();
        holder.contact = (TextView) convertView
                .findViewById(R.id.tv_staff_contact);
        holder.consultation = (TextView) convertView
                .findViewById(R.id.tv_staff_consultation);
        holder.locations = (ListView) convertView
                .findViewById(R.id.lv_staff_locations);

        holder.noRoomLocation = (TextView) convertView.findViewById(R.id.no_room_location);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolderChild) convertView.getTag();

    }

    holder.contact.setText(staffChildInfo.getContact().trim());

    holder.consultation.setText(staffChildInfo.getConsultation().trim());
    String roomId = staffChildInfo.getRoomId();

    final ArrayList<RoomLocation> roomLocationInfos = new ArrayList<RoomLocation>();
    String[] roomIdForSearch = roomId.split(":");
    if (roomIdForSearch.length <= 1) {
        holder.noRoomLocation.setVisibility(View.VISIBLE);
        holder.locations.setVisibility(View.GONE);
    }else{
        holder.noRoomLocation.setVisibility(View.GONE);
        holder.locations.setVisibility(View.VISIBLE);

        for (int i = 1; i < roomIdForSearch.length; i++) {
            ra.openToRead();
            roomLocationInfos.add(ra.getRoomLocation(Integer
                    .valueOf(roomIdForSearch[i].trim())));
            ra.close();
        }

        String[] items = new String[roomLocationInfos.size()];
        int i = 0;
        for (RoomLocation rl : roomLocationInfos) {
            items[i++] = formatLocationName(rl.getName());

        }

        ArrayAdapter<String> adapter = new ArrayAdapter<String>(context,
                R.layout.item_location, R.id.tv_item_location, items);
        holder.locations.setAdapter(adapter);
        adapter.notifyDataSetInvalidated();
        adapter.notifyDataSetChanged();
        Utility.setListViewHeightBasedOnChildren(holder.locations);

        holder.locations.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                startBuildnigPlanActivityInSearchMod(
                        roomLocationInfos.get(position).getX(),
                        roomLocationInfos.get(position).getY(),
                        roomLocationInfos.get(position).getBuildingId(),
                        roomLocationInfos.get(position).getFloorId());

            }

        });
        holder.locations.setFocusable(false);

    }

    return convertView;
}

@SuppressLint("DefaultLocale")
private String formatLocationName(String locationNumber) {
    String location1Format[] = locationNumber.split(":");
    String buildingName = location1Format[0].trim();
    String roomName = location1Format[1].trim();
    return roomName + " (" + buildingName.toUpperCase(Locale.getDefault())
            + ")";
}

@Override
public int getChildrenCount(int groupPosition) {
    return 1;
}

@Override
public Object getGroup(int groupPosition) {
    return staffGroups.get(groupPosition);
}

@Override
public int getGroupCount() {
    return staffGroups.size();
}

@Override
public long getGroupId(int groupPosition) {
    return groupPosition;
}

@Override
public View getGroupView(int groupPosition, boolean isExpanded,
        View convertView, ViewGroup parent) {
    StaffGroup staffGroupInfo = (StaffGroup) getGroup(groupPosition);

    ViewHolderGroup holder;
    if (convertView == null) {
        convertView = layoutInflater
                .inflate(R.layout.group_row_staff, null);
        holder = new ViewHolderGroup();
        holder.staffId = (TextView) convertView
                .findViewById(R.id.tv_staff_id);
        holder.staffName = (TextView) convertView
                .findViewById(R.id.tv_staff_name);
        holder.groupIndicator = (ImageView) convertView
                .findViewById(R.id.iv_group_indicator);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolderGroup) convertView.getTag();
    }

    if (isExpanded) {
        holder.groupIndicator.setImageDrawable(resource
                .getDrawable(R.drawable.iv_expanded));
    } else {
        holder.groupIndicator.setImageDrawable(resource
                .getDrawable(R.drawable.iv_not_expanded));
    }

    holder.staffId.setText(staffGroupInfo.getId().trim());
    if (staffGroupInfo.getTitle().trim().equals("No data")) {
        holder.staffName.setText(staffGroupInfo.getStaffName().trim());
    } else {
        holder.staffName.setText(staffGroupInfo.getStaffName().trim()
                + ", " + staffGroupInfo.getTitle().trim());
    }

    return convertView;

}

@Override
public boolean hasStableIds() {
    return true;
}

@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
    return true;
}

public void startBuildnigPlanActivityInSearchMod(){
    ...
}

/**
 * ViewHolderGroup class for group view
 * 
 * 
 * 
 */
static class ViewHolderGroup {
    TextView staffId;
    TextView staffName;
    ImageView groupIndicator;

}

/**
 * ViewHolderChild class for child view
 * 
 * 
 * 
 */
static class ViewHolderChild {
    ListView locations;
    TextView contact;
    TextView consultation;
    TextView noRoomLocation;
}

}

The ListView is created inside the getChildView and so is the setOnItemClickListener. In my Activity I call normally the ExpandableListView. Hope this helps?!

Upvotes: 0

Views: 6128

Answers (2)

Vince
Vince

Reputation: 219

I don't think you need answer anymore, but I had the same problem, and I found this solution : I was using this function :

Bitmap thumbnail = Bitmap.createScaledBitmap(bmp, w, h, true)
if (!bmp.isRecycled()) {
    bmp.recycle();
}
bmp = null;

By reading the description of this method, I have found :

"Creates a new bitmap, scaled from an existing bitmap, when possible. If the specified width and height are the same as the current width and height of the source bitmap, the source bitmap is returned and no new bitmap is created."

So basically, in this case, w and h are matching my "bmp" width and height, so the createScaledBitmap() function WILL NOT create a new object, but use the source one (bmp) and the "bmp" address will be used on my "thumbnail" variable. And if I try to recycle bmp (thinking that it will not be used anymore), I am wrong, because this same address is still used by the variable "thumbnail", and the rest of my code won't work.

So here is my simple solution :

Bitmap thumbnail = Bitmap.createScaledBitmap(bmp, w, h, true);
if (!thumbnail.equals(bmp)) {
    if (!bmp.isRecycled()) {
        bmp.recycle();
    }
    bmp = null;
}

Hope this will help someone !

Upvotes: 2

Rashmi.B
Rashmi.B

Reputation: 1787

Try using this:

if (!bitmap.isRecycled())
           {
             bitmap.recycle;
           }

and then create your bitmap.

Upvotes: 1

Related Questions