1

I recently started working on an Android project and given my lack of understanding of UI programming, I find myself in a fix, when I try to dynamically add a entry to the UI.

I am working on a chat-application in which when a new message is received, it should be added at the bottom. For that I need to notify that the data-set has changed. When I was directly calling data-set has changed, I was getting an error. So I used a local broadcast reciever on the adapter.

Unfortunately, I don't know how to pass the ArrayList which contains a HashMap. I will post the code of the adapter and where I am trying to notify where data has changed. I hope someone can help me out. THanks a lot.. :-)

Code :

    public static void recieveUpdatedMessage(String channelName, Map<String, Object> input){

//The input here contains message from our PUSH system 

  Intent intent = new Intent();
                    HashMap<String, String> insertMap = new HashMap<>();
                    insertMap.put(chatText, String.valueOf(input.get("text")));
                    insertMap.put(firstName,String.valueOf("firstname"));
                    insertMap.put(groupChannel, "/service/chat" + String.valueOf(groupAccountId));

                    ArrayList<HashMap<String, String>> chatMessagesHashMapList = new ArrayList<HashMap<String, String>>();
                    chatMessagesHashMapList.add(insertMap);

// Below is where I am trying to send data.
                 //  intent.putExtra(chatMessagesHashMapList);//send any data to your adapter
                    intent.setAction("myaction");
                    LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

The adapter code, it's in same java file :

public class ChatMessagesAdapter extends BaseAdapter {


private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent)
    {

        if(intent.getAction().equals("MYREFRESH"))
        {
            notifyDataSetChanged();
        }
    }
};

    private Activity activity = null;
    private ArrayList<HashMap<String, String>> data;
    private LayoutInflater inflater = null;


    public ChatMessagesAdapter(Activity a, ArrayList<HashMap<String, String>> d) {

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("MYREFRESH");
        LocalBroadcastManager.getInstance(context).registerReceiver(broadcastReceiver, intentFilter);

        activity = a;
        data = d;
        inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    }

    @Override
    public int getCount() {
        return data.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) {


        View vi = convertView;
        if (convertView == null)
            vi = inflater.inflate(R.layout.chat_messages_row, parent, false);

        TextView chatText = (TextView) vi.findViewById(R.id.chatText);
        ImageView userImage = (ImageView) vi.findViewById(R.id.chatImage);
        TextView firstName = (TextView) vi.findViewById(R.id.personName);

        HashMap<String, String> chatList = new HashMap<>();
        chatList = data.get(position);

        chatText.setText(chatList.get(ChatMessagesActivity.chatText));
        userImage.setImageBitmap(convertByteArrayToBitmap(chatList.get(ChatMessagesActivity.chatImage)));
        firstName.setText(chatList.get(ChatMessagesActivity.firstName));
        return vi;
    }

}

I hope I was clear. If there is anything missing, kindly let me know. How can I tell the activity that there is a new message and put it at the bottom.

user1140237
  • 5,015
  • 1
  • 28
  • 56
We are Borg
  • 5,117
  • 17
  • 102
  • 225
  • You can pass HashMap in intent from `recieveUpdatedMessage` this method you can fetch data from `intent` which you can get in `onReceive` of `broadcastReceiver ` How to Pass HashMap from intent please check http://stackoverflow.com/a/10024875/1140237 – user1140237 Jan 12 '16 at 15:03
  • Your action name does not match what you are expecting is one problem. You are setting it as `myaction` but are checking for `MYREFRESH`. Also I do not see where you are actually adding the new entry to your `data` `ArrayList` in your `Adapter`. – George Mulligan Jan 12 '16 at 15:05
  • @GeorgeMulligan : My bad, changed to MYREFRESH on both sides. – We are Borg Jan 12 '16 at 15:07
  • @user1140237 : That seems very complicated, do you have something simpler? – We are Borg Jan 12 '16 at 15:08
  • 1
    This is also an awkward way of notifying a change. Your first approach sounded correct to simply add it to the adapter and call `notifyDataSetChanged()`. What was your error? – George Mulligan Jan 12 '16 at 15:09
  • @WeareBorg i gave based on you Approach because registered broadcast on adapter is not good practice. – user1140237 Jan 12 '16 at 15:14

2 Answers2

2

You can pass latest data in your case you are creating data with HashMap directly into intent using bundle. & retrive it from the onReceive method of BroadCastReceiver

How to Pass data check your updated method recieveUpdatedMessage below recieveUpdatedMessage

public static void recieveUpdatedMessage(String channelName, Map<String, Object> input) {

//The input here contains message from our PUSH system

        Intent intent = new Intent();
        HashMap<String, String> insertMap = new HashMap<>();
        insertMap.put(chatText, String.valueOf(input.get("text")));
        insertMap.put(firstName, String.valueOf("firstname"));
        insertMap.put(groupChannel, "/service/chat" + String.valueOf(groupAccountId));

        ArrayList<HashMap<String, String>> chatMessagesHashMapList = new ArrayList<HashMap<String, String>>();
        // Added your map into Bundler as a Serializable
        Bundle bundle = new Bundle();
        bundle.putSerializable("chatMapKey", insertMap);
//        after adding map into bundle . bundle is added into Intent
        intent.putExtras(bundle);
// Below is where I am trying to send data.
        //  intent.putExtra(chatMessagesHashMapList);//send any data to your adapter
        intent.setAction("MYREFRESH");
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
    }

How to retrive data from bundle & update it in listview check your ChatMessagesAdapter updated code.

ChatMessagesAdapter

public class ChatMessagesAdapter extends BaseAdapter {


        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {

                if (intent.getAction().equals("MYREFRESH")) {
                    Bundle bundle = intent.getExtras();
                    // Get the bundle from intent
                    if (bundle!=null && bundle.containsKey("chatMapKey")) {
//                        get the Serializable object which is pass as a broadcast from the Bundle
                        refreshChat((HashMap<String, String>) bundle.getSerializable("chatMapKey"));
                    }

                }
            }
        };

        private Activity activity = null;
        private ArrayList<HashMap<String, String>> data;
        private LayoutInflater inflater = null;
        private int size = 0;

        public ChatMessagesAdapter(Activity a, ArrayList<HashMap<String, String>> d) {

            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("MYREFRESH");
            LocalBroadcastManager.getInstance(context).registerReceiver(broadcastReceiver, intentFilter);

            activity = a;
            data = d;
            if (data != null)
                size = data.size();
            inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        }

        public void refreshChat(HashMap<String, String> newChatMap) {
            if (data == null) {// Added Condition for safe side you can remove it
                data = new ArrayList<HashMap<String, String>>();
            }
            data.add(newChatMap);
            size = data.size();
            notifyDataSetChanged();
        }

        @Override
        public int getCount() {
            return 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) {


            View vi = convertView;
            if (convertView == null)
                vi = inflater.inflate(R.layout.chat_messages_row, parent, false);

            TextView chatText = (TextView) vi.findViewById(R.id.chatText);
            ImageView userImage = (ImageView) vi.findViewById(R.id.chatImage);
            TextView firstName = (TextView) vi.findViewById(R.id.personName);

            HashMap<String, String> chatList = new HashMap<>();
            chatList = data.get(position);

            chatText.setText(chatList.get(ChatMessagesActivity.chatText));
            userImage.setImageBitmap(convertByteArrayToBitmap(chatList.get(ChatMessagesActivity.chatImage)));
            firstName.setText(chatList.get(ChatMessagesActivity.firstName));
            return vi;
        }

    }

Suggestions

  • Avoid using Broadcast reciver like you have used. Register it in Activity onReusme/onStart & Unregister it in its onPause/onStop method check this The visible lifetime

  • Try to maintain data with database like at the time of message receive insert it in database & at the time of refreshing data get the data from database

user1140237
  • 5,015
  • 1
  • 28
  • 56
2

You really should not use a BroadcastReceiver that way. Try adding an add method to the Adapter to make it easier to add an item and automatically notify a change.

public void add(HashMap<String, String> item) {
    data.add(item);
    notifyDataSetChanged();
}

Then in the recieveUpdatedMessage method you can do something similar to the following.

public void recieveUpdatedMessage(String channelName, Map<String, Object> input) {
    HashMap<String, String> insertMap = new HashMap<>();
    insertMap.put(chatText, input.get("text").toString());
    insertMap.put(firstName, input.get("firstname").toString());
    insertMap.put(groupChannel, "/service/chat" + input.get("groupaccountid").toString());

    myAdapter.add(insertMap);
}

A few notes for improvement

Instead of using a HashMap it would be better to create a class to hold the data for you.

Since your BaseAdapter is already using a List you could extend an ArrayAdapter instead since that already has an add method that also calls notifyDataSetChanged() by default.

George Mulligan
  • 11,813
  • 6
  • 37
  • 50