0

I'm working on my own message app that send and receive messages to/from the server.

I'm using an integer array called Status that indicates message is outgoing or incoming.

When I comment below line in my MessageActivity , listview shows me some messages, but when I scroll down, my app crashes and I get choreographer error.

holder.ivReceiveUser.setImageBitmap(BitmapFactory.decodeFile(userImage));           

Also, when I don't comment above line, I get BitmapFactory error. (I'm sure that imagePath is true, because I used it on my other activities)

Any suggestion would be appreciated ...

MessageActivity

private void initListview()
{
    lv = (ListView) findViewById(R.id.lv_messages);
    MessagesList = dbh.getAllMessagesOfSpecificUser(TargetUserID);
    final String img = TargetModel.getImagePath();
    String username = TargetModel.getName();
    String[] Content = new String[MessagesList.size()]; 
    String[] MessageID = new String[MessagesList.size()];
    String[] SendDate = new String[MessagesList.size()];
    int[] Status = new int[MessagesList.size()];
    String[] ReadDate = new String[MessagesList.size()];
    for(int i=0; i<MessagesList.size(); i++)
    {
        Content[i] = MessagesList.get(i).getContent(); 
        MessageID[i] = MessagesList.get(i).getMessageID();
        SendDate[i] = MessagesList.get(i).getSendDate();
        Status[i] = MessagesList.get(i).getStatus();
        ReadDate[i] = MessagesList.get(i).getReadDate();
    }       
    mAdapter = new AdapterMessagesII(MessagesActivity.this, MessageID, Content, SendDate, ReadDate, Status, username, img);     
    lv.setAdapter(mAdapter);
}

AdapterMessagesII

package  MyPackageName.Adapters;
import  MyPackageName.R;
import com.pkmmte.circularimageview.CircularImageView;
import android.content.Context;
import android.graphics.Typeface;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;

public class AdapterMessagesII extends BaseAdapter {

private LayoutInflater inflater;
private Typeface tf;    
private CharSequence time;
private String[] MessageID; 
private String[] Content;
private String[] SendDate;
private String[] ReadDate;
private int[] Status;   
private String Username;
private String userImage;   

public AdapterMessagesII(Context context, String[] MessageID, String[]   Content, String[] SendDate, String[] ReadDate, int[] Status, String Username, String userImage)
{
    inflater = LayoutInflater.from(context);
    this.MessageID = MessageID;
    this.Content = Content;
    this.SendDate = SendDate;
    this.ReadDate = ReadDate;
    this.Status = Status;   
    this.Username = Username;       
    this.userImage = userImage;
    tf = Typeface.createFromAsset(context.getAssets(),"fonts/MJ_DINAR ONE LIGHT.TTF");      
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return MessageID.length;
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return MessageID[position];
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    ViewHolder holder = null;
    if (convertView == null)
    {
        holder = new ViewHolder();
        switch (Status[position])
        {
        case 0: //Send
            convertView = inflater.inflate(R.layout.list_messages_row_send, null);
            holder.tvSendContent = (TextView) convertView.findViewById(R.id.tv_send_message_content);
            holder.tvSendTimestamp = (TextView) convertView.findViewById(R.id.tv_send_message_timestamp);
            holder.tvSendReadDate = (TextView) convertView.findViewById(R.id.tv_send_message_read_status);              
            holder.layoutReadStatus = (LinearLayout) convertView.findViewById(R.id.layout_send_message_read_status);
            break;
        case 1: //Receive
            convertView = inflater.inflate(R.layout.list_messages_row_receive, null);
            holder.tvUsername = (TextView) convertView.findViewById(R.id.tv_receive_message_username);
            holder.tvReceiveContent = (TextView) convertView.findViewById(R.id.tv_receive_message_content);
            holder.tvReceiveTimestamp = (TextView) convertView.findViewById(R.id.tv_receive_message_timestamp);
            holder.ivReceiveUser = (CircularImageView) convertView.findViewById(R.id.iv_receive_message);
            break;
        }
        convertView.setTag(holder);
    } 
    else
    {
        holder = (ViewHolder) convertView.getTag();
    }


    switch (Status[position])
    {
    case 0: //Send
        holder.tvSendContent.setText(Content[position]);
        time = DateUtils.getRelativeTimeSpanString(Long.parseLong(SendDate[position]),
                System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS);
        holder.tvSendTimestamp.setText(time);   
        switch(ReadDate[position])
        {           
        case "x": 
            break;
        default:
            holder.layoutReadStatus.setVisibility(View.VISIBLE);
            time = DateUtils.getRelativeTimeSpanString(Long.parseLong(ReadDate[position]),
                    System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS);
            holder.tvSendReadDate.setText(time);
            break;
        }
        break;
    case 1: //Receive           
        switch(userImage)
        {
        case "x":    holder.ivReceiveUser.setImageResource(R.drawable.avatar_male_dark);
            break;
        default:    holder.ivReceiveUser.setImageBitmap(BitmapFactory.decodeFile(userImage));           
            break;
        }
        holder.tvUsername.setText(Username);
        holder.tvUsername.setTypeface(tf);
        holder.tvReceiveContent.setText(Content[position]);
        time = DateUtils.getRelativeTimeSpanString(Long.parseLong(SendDate[position]),
                System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS); 
        holder.tvReceiveTimestamp.setText(time);
        break;
    }
    return convertView;
}

static class ViewHolder
{
    TextView tvUsername;
    TextView tvReceiveContent;
    TextView tvReceiveTimestamp;
    CircularImageView ivReceiveUser;
    TextView tvSendContent;
    TextView tvSendTimestamp;
    TextView tvSendReadDate;        
    LinearLayout layoutReadStatus;
}   
}

list_messages_row_receive

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/ MyPackageName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/BackgrounColor"
android:orientation="vertical" >

<LinearLayout
    android:id="@+id/layout_receive_messages"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="5dp"
    android:layout_marginTop="5dp"
    android:orientation="horizontal"
    android:paddingLeft="5dp" >

    <LinearLayout
        android:id="@+id/qq"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="vertical" >

        <com.pkmmte.circularimageview.CircularImageView
            android:id="@+id/iv_receive_message"
            android:layout_width="45dp"
            android:layout_height="45dp"
            app:border="true"
            app:border_color="@color/LightGray"
            app:border_width="0dp" />

        <TextView
            android:id="@+id/tv_receive_message_timestamp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceSmall"
            android:textColor="@color/messagesTimestamp"
            android:textSize="8sp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:gravity="left"
        android:orientation="vertical"
        android:paddingTop="5dp" >

        <TextView
            android:id="@+id/tv_receive_message_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="@color/colorPrimary"
            android:textSize="12sp" />

        <TextView
            android:id="@+id/tv_receive_message_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:background="@drawable/receive_message"
            android:gravity="right"
            android:lineSpacingMultiplier="1.5"
            android:maxWidth="350dp"
            android:minWidth="35dp"
            android:paddingBottom="5dp"
            android:paddingLeft="10dp"
            android:paddingRight="10dp"
            android:paddingTop="10dp"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="@color/darkGray"
            android:textSize="9sp" />
    </LinearLayout>
</LinearLayout>    
</LinearLayout>

list_messages_row_send

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_send_messages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginTop="5dp"
android:background="@color/BackgrounColor"
android:orientation="vertical" >

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="right"
    android:orientation="horizontal"
    android:paddingRight="5dp" >

    <TextView
        android:id="@+id/tv_send_message_timestamp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginRight="5dp"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="@color/messagesTimestamp"
        android:textSize="8sp" />

    <TextView
        android:id="@+id/tv_send_message_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:background="@drawable/send_message"
        android:gravity="right"
        android:lineSpacingMultiplier="1.5"
        android:maxWidth="350dp"
        android:minWidth="35dp"
        android:paddingBottom="5dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="10dp"            
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@color/white"
        android:textSize="9sp" />        
</LinearLayout>

<LinearLayout
    android:id="@+id/layout_send_message_read_status"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginRight="5dp"
    android:layout_marginTop="2dp"
    android:gravity="right|center_vertical"
    android:paddingRight="5dp"
    android:visibility="gone"
    android:orientation="horizontal" >

    <ImageView                
        android:layout_width="12dp"
        android:layout_height="12dp"
        android:layout_marginRight="2dp"
        android:src="@drawable/icon_correct" />

    <TextView
        android:id="@+id/tv_send_message_read_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="@color/messagesTimestamp"
        android:textSize="8sp" />        
</LinearLayout>    
</LinearLayout>

UPDATE:

This is Logcat:

08-08 16:45:39.604: I/LOG_ITEM_IMG(2872):  /storage/emulated/0/MyAppName/UserImage/010DEC12-A89A-4ACC-B6BE-7FCC677D9526.jpg
08-08 16:45:39.656: D/dalvikvm(2872): GC_FOR_ALLOC freed 1296K, 26% free 43552K/58680K, paused 4ms, total 6ms
08-08 16:45:39.660: I/dalvikvm-heap(2872): Grow heap (frag case) to 55.924MB for 14017548-byte allocation
08-08 16:45:39.664: D/dalvikvm(2872): GC_FOR_ALLOC freed 16K, 3% free 57225K/58680K, paused 7ms, total 7ms
08-08 16:45:39.736: W/Settings(2872): Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
08-08 16:45:39.788: D/dalvikvm(2872): GC_FOR_ALLOC freed 17191K, 32% free 40169K/58680K, paused 6ms, total 6ms
08-08 16:45:39.800: I/dalvikvm-heap(2872): Grow heap (frag case) to 59.047MB for 20756748-byte allocation
08-08 16:45:39.808: D/dalvikvm(2872): GC_FOR_ALLOC freed 1K, 24% free 60438K/78952K, paused 6ms, total 6ms
08-08 16:45:39.860: D/dalvikvm(2872): GC_FOR_ALLOC freed 1K, 20% free 63864K/78952K, paused 4ms, total 4ms
08-08 16:45:39.860: I/dalvikvm-heap(2872): Grow heap (frag case) to 75.760MB for 14017548-byte allocation
08-08 16:45:39.868: D/dalvikvm(2872): GC_FOR_ALLOC freed <1K, 2% free 77553K/78952K, paused 8ms, total 8ms
08-08 16:45:44.380: E/InputEventReceiver(2872): Exception dispatching input event.

UPDATE 2:

On my idea the mistake must be in list_messages_row_send.xml and list_messages_row_receive.xml layouts or using them in my adapter.

Because when I just pass messages with status 0 or 1 into adapter, there is no error when I scroll listview.

But when I pass one message with Status 1 or 0 (inverse of first Status), the error occurs.

Farshad Kazemi
  • 358
  • 1
  • 4
  • 16
  • I think you get OOM ( out of memory ). what is size of your images? – Shayan Pourvatan Aug 08 '15 at 10:50
  • put `Log.i("LOG_ITEM_IMG", "" + img);` after `final String img = TargetModel.getImagePath();` and check the logcat with **tag:LOG_ITEM_IMG** filter, and tell output – The Badak Aug 08 '15 at 10:57
  • @AwaisKing, This is output: /storage/emulated/0/MyAppname/UserImage/01.jpg – Farshad Kazemi Aug 08 '15 at 11:05
  • @shayanpourvatan, That's Around 2MB. Is there any way to reduce size of bitmap image before using it ?! – Farshad Kazemi Aug 08 '15 at 11:07
  • @FarshadKazemi can you put your logcat in post? – The Badak Aug 08 '15 at 11:12
  • you can compress that before saving, but you can use Universal Image Loader, i think this can help you. but this size is very big for mobile device, think about low range device. – Shayan Pourvatan Aug 08 '15 at 11:13
  • @AwaisKing, After "LOG_ITEM_IMG" tag, Logcat just show this tag: "InputEventReceiver" : "Exception dispatching input event" – Farshad Kazemi Aug 08 '15 at 11:25
  • @shayanpourvatan, I've used Picasso library with this syntax {Piccaso.with(this).load(userImage).into(ivReceiveUser)} but it doesn't show me any image on my imageview. Also, I've tested with images with smaller sizes (200kb) but i got erroe again – Farshad Kazemi Aug 08 '15 at 11:28
  • @FarshadKazemi try my answer, I hope that works. – The Badak Aug 08 '15 at 11:28
  • In.addition to suggestions given above, you should also consider that operation in AysncTask or IntentService for performance efficiency. – Want2bExpert Aug 08 '15 at 11:29
  • @Want2bExpert, I've tried using **AsyncTask** and again I got the same error. – Farshad Kazemi Aug 08 '15 at 11:58
  • When you scroll up and down you images created might have be garbage collected which mean ListView ua trying to recreate those images again that's why it crashes. You need to cache the.images See my Answer below hope it helps.. – Want2bExpert Aug 08 '15 at 12:01

2 Answers2

1

add this function to adapter:

private Bitmap decodeFile(File f) {
    try {
        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f),null,o);

        //The new size we want to scale to
        final int REQUIRED_SIZE=70;

        //Find the correct scale value. It should be the power of 2.
        int scale=1;
        while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
            scale*=2;

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {}
    return null;
}

(source: Bitmap Out Of Memory Issues)

and change holder.ivReceiveUser.setImageBitmap(BitmapFactory.decodeFile(userImage));

to holderholder.ivReceiveUser.setImageBitmap(decodeFile(new File(userImage));

I hope that works

Community
  • 1
  • 1
The Badak
  • 2,010
  • 2
  • 16
  • 28
  • I used your function and it solved **BitmapFactory** error. But again when I scroll down and up for 2-3 times, I get **Choreographer** error ! – Farshad Kazemi Aug 08 '15 at 11:42
  • hmmm, so no OOM error? can you post your new logcat? – The Badak Aug 08 '15 at 11:44
  • There is nothing after **LOG_ITEM_IMG**. Now I get an new error **ViewRootImpl.deliverInputEvent(ViewRootImpl$QuededInputEvent)** – Farshad Kazemi Aug 08 '15 at 11:57
  • I mean all the log, not **LOG_ITEM_IMG**, everything in logcat – The Badak Aug 08 '15 at 12:00
  • I don't think that `08-08 16:45:44.380: E/InputEventReceiver(2872): Exception dispatching input event.` is the cause of this problem can you please put screenshot of your logcat at the end? or you could pm me on my fb – The Badak Aug 08 '15 at 13:46
1

When you scroll up and down you images created might have be garbage collected which mean ListView is trying to recreate those images again that's why it crashes.

You need to cache your images using Either LruCache or DiskLruCache.

Please read this Android link, it will help you.

http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

public View getView(int position, View convertView,     ViewGroup parent) 
{

ViewHolder holder = null;
if (convertView == null)
{
holder = new ViewHolder();
switch (Status[position])
{
case 0: //Send
convertView = inflater.inflate(R.layout.list_messages_row_send, null);
holder.tvSendContent = (TextView) convertView.findViewById(R.id.tv_send_message_content);
holder.tvSendTimestamp = (TextView) convertView.findViewById(R.id.tv_send_message_timestamp);
holder.tvSendReadDate = (TextView) convertView.findViewById(R.id.tv_send_message_read_status);              
holder.layoutReadStatus = (LinearLayout) convertView.findViewById(R.id.layout_send_message_read_status);
break;
case 1: //Receive
convertView = inflater.inflate(R.layout.list_messages_row_receive, null);
holder.tvUsername = (TextView) convertView.findViewById(R.id.tv_receive_message_username);
holder.tvReceiveContent = (TextView) convertView.findViewById(R.id.tv_receive_message_content);
holder.tvReceiveTimestamp = (TextView) convertView.findViewById(R.id.tv_receive_message_timestamp);
holder.ivReceiveUser = (CircularImageView) convertView.findViewById(R.id.iv_receive_message);
break;
}

convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } switch (Status[position]) { case 0: //Send holder.tvSendContent.setText(Content[position]); time = DateUtils.getRelativeTimeSpanString(Long.parseLong(SendDate[position]), System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS); holder.tvSendTimestamp.setText(time);
if (ReadDate[position] != null) { holder.layoutReadStatus.setVisibility(View.VISIBLE); time = DateUtils.getRelativeTimeSpanString(Long.parseLong(ReadDate[position]), System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS); holder.tvSendReadDate.setText(time); }// End if break; case 1: //Receive
if (userImage != null) { holder.ivReceiveUser.setImageResource(R.drawable.avatar_male_dark); } else{ holder.ivReceiveUser.setImageBitmap(BitmapFactory.decodeFile(userImage)); } holder.tvUsername.setText(Username); holder.tvUsername.setTypeface(tf); holder.tvReceiveContent.setText(Content[position]); time = DateUtils.getRelativeTimeSpanString(Long.parseLong(SendDate[position]), System.currentTimeMillis(),DateUtils.SECOND_IN_MILLIS); holder.tvReceiveTimestamp.setText(time); break; }// End switch (Status[position])

return convertView;
}

What I will recommend for simplicity and Clarit, Create 2 AdapterClasses as below; AdapterClass1 AdapterClass2 class SwitchView extends AsyncTask { @override protected void doInBackground(Integer...params) { int whichView = params[0]; switch(whichView) { case 0: // Load AdapterClass 1 break; case 1; // Load AdapterClass 2 break; } // End switch } // End doInBackgroud protected void onPostExecute() { // Dismiss ProgressDialog } }// End SwitchView

Want2bExpert
  • 527
  • 4
  • 11