如何通过在自定义列表视图适配器本身中收集消息来显示聊天?

How to show chats by collecting messages in the custom list view adapter itself?

所以,我想做的是使用自定义列表视图适配器在 activity 中显示聊天记录。

I have a HTTPTask Activity handling the server side interaction and responding with a JSONObject. So, every server side interaction is working fine.

What I want to do is keep updating the messages in the chat by keep checking with the API at a set interval to populate messages in the chat if there are any.

我的问题是,这个填充过程应该在适配器中完成还是在 activity 中完成以及如何完成?

还有,viewHolder 在适配器中有什么帮助?

这是我的Activity

public class ChatActivity extends Activity {

TextView toUsername;
EditText replyText;
JSONObject resultObject;
StringBuilder reply,from_user_id,c_id;
MessageListViewAdapter myAdapter;
ListView listView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_chat);

    toUsername = (TextView) findViewById(R.id.toUsername);
    replyText = (EditText) findViewById(R.id.replyText);
    reply = new StringBuilder("");
    listView = (ListView) findViewById(R.id.messages);
}

@Override
public void onResume(){
    super.onResume();

    Bundle bundle = getIntent().getExtras();
    if(bundle != null){
        toUsername.setText("" + bundle.get("ToUsername").toString());
        c_id = new StringBuilder(bundle.get("c_id").toString());
        from_user_id = new StringBuilder(bundle.get("FromUserId").toString());
    }

    myAdapter = new MessageListViewAdapter(getBaseContext(),c_id.toString(),from_user_id.toString());
    listView.setAdapter(myAdapter);
}

public void sendTextMsg(View view){
    reply.delete(0,reply.length());
    reply.append(replyText.getText().toString());
    if(!reply.toString().equals("")){
        Log.d("Values: ","c_id: " + c_id.toString() + " FromUserId: " + from_user_id.toString() + "ReplyText: " + reply.toString());

        try{
            resultObject = new HttpTask(getBaseContext()).doInBackground("replyInChat",c_id.toString(),replyText.getText().toString(),from_user_id.toString());
            if(resultObject.get("status").toString().equals("true")) {
                Toast.makeText(getBaseContext(), "Sent.", Toast.LENGTH_SHORT).show();
                replyText.setText("");
            }
            else {
                Toast.makeText(getBaseContext(), "Try Again.", Toast.LENGTH_SHORT).show();
            }
        }
        catch(JSONException e){ }

    }
}
}

我的适配器似乎不工作。

public class MessageListViewAdapter extends BaseAdapter implements ListAdapter{

private ArrayList<String> list = new ArrayList<String>();
private Context context;
private StringBuilder conversation_id, user_id;
private static int cr_id;
private JSONArray messages;
private JSONObject resultObject;
private ViewHolder viewHolder;
private View rowView;

public MessageListViewAdapter(Context context, String conversation_id, String user_id) {
    this.context = context;
    this.conversation_id = new StringBuilder(conversation_id.toString());
    this.user_id = new StringBuilder(user_id.toString());
    cr_id=0;
}

@Override
public int getCount() {
    return list.size();
}

@Override
public Object getItem(int pos) {
    return list.get(pos);
}

@Override
public long getItemId(int pos) {
    //return list.get(pos).getId();
    //just return 0 if your list items do not have an Id variable.
    return 0;
}

@Override
public boolean isEnabled(int position){
    return false;
}

static class ViewHolder{
    public TextView ItemText;
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    rowView = convertView;

    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.message_list_layout, null);
        //configure view holder
        viewHolder = new ViewHolder();
        viewHolder.ItemText = (TextView) rowView.findViewById(R.id.list_item_text);
        rowView.setTag(viewHolder);
    }
    else {
        //fill data
        viewHolder = (ViewHolder) rowView.getTag();
    }

    try{
        Log.d("cr_id: ",String.valueOf(cr_id).toString());
        //This is where the population should've taken place but didn't.
        resultObject = new HttpTask(context).doInBackground("sendMessages",conversation_id.toString(),String.valueOf(cr_id));
        if(resultObject.get("status").toString().equals("true")) {
            messages = resultObject.getJSONArray("messages");
            Log.d("Messages: ",messages.toString());
            for(int i=0;i<=messages.length();i++){
                list.add(messages.getJSONObject(i).get("reply_text").toString());
            }
        }
    }
    catch(JSONException e){ }

    //Handle TextView and display string from your list
    //final TextView listItemText = (TextView)rowView.findViewById(R.id.list_item_text);
    //listItemText.setText(list.get(position));
    viewHolder.ItemText.setText(list.get(position));

    return rowView;
}
}

如果一切正常,而您在适配器中显示最新的聊天消息时遇到问题,只需像这样更改您的代码:

try{
        Log.d("cr_id: ",String.valueOf(cr_id).toString());
        //This is where the population should've taken place but didn't.
        resultObject = new HttpTask(context).doInBackground("sendMessages",conversation_id.toString(),String.valueOf(cr_id));
        if(resultObject.get("status").toString().equals("true")) {
            messages = resultObject.getJSONArray("messages");
            Log.d("Messages: ",messages.toString());
            for(int i=0;i<=messages.length();i++){
                list.add(messages.getJSONObject(i).get("reply_text").toString());
                this.notifyDataSetChanged(); // add this line
            }
        }
    }
    catch(JSONException e){ }

在下方评论以获取更多信息

就我个人而言,我会在适配器之外进行网络调用。使用当前的代码,如果用户要上下滚动列表,网络调用将调用多次,这是我确定你不想要的。

可能更好的解决方案是在 activity 中有一个方法来执行调用,然后设置一个计时器,每 2 - 3 分钟调用一次该方法以节省网络调用,您还可以为用户添加一个刷新按钮,让他们可以选择自己刷新数据,这只会调用相同的方法。

View Holder 设计模式可以帮助加快列表视图的速度并保持其流畅,这样想,当页面首次加载时,将多次调用 getView 来填充列表视图。在 getView 方法中,您实例化 UI 小部件,即 textview = (TextView)findviewbyid。现在视图持有者所做的是保留对这些 ui 元素的引用,这意味着您不必继续调用 findViewById.

这里有一篇文章对其进行了更好的解释,并提供了一些示例。

http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html

假设您在 activity 中编写网络代码。当您收到回复时,您只需将消息添加到列表中,然后 notifyDataSetChanged();

So, Finally I got it working with some experimentation. Many thanks to Manikanta and Andy Joyce for their valuable answers. If it weren't for them i wouldn't have gone any further from where I was stuck.

这是我在自定义适配器中所做的更改。

public void add(ArrayList<String> list){
    this.list.clear();
    this.list.addAll(list);
    Log.d("List: ",this.list.toString());
    this.notifyDataSetChanged();
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    rowView = convertView;

    if (rowView == null) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        rowView = inflater.inflate(R.layout.message_list_layout, null);
        //configure view holder
        viewHolder = new ViewHolder();
        viewHolder.ItemText = (TextView) rowView.findViewById(R.id.list_item_text);
        rowView.setTag(viewHolder);
    }

    else {
        //fill data
        viewHolder = (ViewHolder) rowView.getTag();
    }

    viewHolder.ItemText.setText(list.get(position));

    return rowView;
}

这是我添加到我的 activity

    @Override
public void onResume(){
    super.onResume();

    Bundle bundle = getIntent().getExtras();
    if(bundle != null){
        toUsername.setText("" + bundle.get("ToUsername").toString());
        c_id = new StringBuilder(bundle.get("c_id").toString());
        from_user_id = new StringBuilder(bundle.get("FromUserId").toString());
        //list.add(c_id.toString());
        //list.add(from_user_id.toString());
    }

    myAdapter = new MessageListViewAdapter(getBaseContext(),c_id.toString(),from_user_id.toString());
    listView.setAdapter(myAdapter);

    callAsynchronousTask();
    //myAdapter.add(list);
}
@Override
public void onPause(){
    super.onPause();
    timer.cancel();
}
public void callAsynchronousTask() {
    final Handler handler = new Handler();
    timer = new Timer();
    TimerTask doAsynchronousTask = new TimerTask() {
        @Override
        public void run() {
            handler.post(new Runnable() {
                public void run() {
                    //list.clear();
                    try{
                        resultChatObject = new HttpTask(getBaseContext()).doInBackground("sendMessages",c_id.toString(),String.valueOf(cr_id));
                        if(resultChatObject.get("status").toString().equals("true")) {
                            //list.clear();
                            messages = resultChatObject.getJSONArray("messages");
                            Log.d("Messages: ",messages.toString());
                            for (int i = 0; i <= messages.length(); i++) {
                                list.add(messages.getJSONObject(i).get("reply_text").toString());
                                if (cr_id < Integer.parseInt(messages.getJSONObject(i).get("cr_id").toString()))
                                    cr_id = Integer.parseInt(messages.getJSONObject(i).get("cr_id").toString());
                            }
                        }
                    }
                    catch (JSONException e) { }

                    myAdapter.add(list);
                }
            });
        }
    };
    timer.schedule(doAsynchronousTask, 0, 10000); //execute in every 10000 ms
}

大家干杯!!!