自定义ArrayAdapter仅重复显示1个JSON项

时间:2016-02-16 22:40:57

标签: android json listview android-arrayadapter getview

我正在使用自定义ArrayAdapter的Android应用中的消息传递屏幕上工作,因此成员之间发送的消息将显示为聊天气泡。在onCreate()期间下载数据,并在onPostExecute()中解析JSON并将其一次加载到适配器中,一次一条消息。日志证实了这一部分。

适配器被加载到位于EditText字段上方的listView和新消息的Send按钮。这是片段java,其中包括修改后的ArrayAdapter类,以及UI和消息行布局的两个XML文件。

package com.davepeyton.android.seekbromance;

import android.annotation.TargetApi;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;

/*
 * This fragment displays a simple list view using a custom array adapter, with a TextEdit
 * field for sending new messages.
 *
 * The layout 'dresses up' the messages (of class BroChatMsg) to look like chat balloons.
 */

public class BrofileBroChatFragment extends Fragment {

    public static final String EXTRA_BROFILE_ID = "com.davepeyton.android.seekbromance.brofile_id";
    // no need to fetch the whole brofile here - it doesn't get displayed or altered
    // private static final String url_fetch_brofile = "http://www.seekbromance.com/android_connx/fetch_brofile.php";
    private static final String url_fetch_messages = "http://www.seekbromance.com/android_connx/fetch_messages.php";

    private int mCurrUserMemberId; // the member ID for the logged-in user
    // private String brofile_id; // parameter for fetch_brofile.php

    private int mConnectFailed = 0; // for HTTP exceptions and the like

    int brofileId;

    // parameters for fetch_message.php
    private String sender_id = "19";
    private String receiver_id = "2905";
    private int sid;
    private int rid;

    // JSON parser class
    JSONParser jsonParser = new JSONParser();

    // JSON node names to be used in this fragment
    private static final String TAG_SUCCESS = "success";
    private static final String TAG_MESSAGES = "messages";
    private static final String TAG_SID = "sid";
    private static final String TAG_RID = "rid";
    private static final String TAG_BODY = "body";
    private static final String TAG_TIMESTAMP = "timestamp";

    private static BroChatMsg sBroChatMsg;
    private ArrayList<BroChatMsg> mRetrievedMessages; // originally took the message data, now used only to initialize the adapter.
    private MessageAdapter mAdapter;

    private String mQuickString = "";

    private EditText mNewMsgField;
    private Button mSendMessageBtn;
    private ListView mLv;

    private String newMessageBody = "";


    public static BrofileBroChatFragment newInstance(int brofileId) {
        Bundle args = new Bundle();
        args.putInt(EXTRA_BROFILE_ID, brofileId);

        BrofileBroChatFragment fragment = new BrofileBroChatFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);

        //Will probably need these later to get back to calling intent
        // get the ID of the Brofile to display from the calling intent
        brofileId = getArguments().getInt(EXTRA_BROFILE_ID);
        mCurrUserMemberId = 19; // quick set for testing


        //mCurrUserBrofileId = 25;  // this is a "full" dummy profile in the SB database; used for testing*/

        sBroChatMsg = new BroChatMsg();
        mRetrievedMessages = new ArrayList<BroChatMsg>();
        mAdapter = new MessageAdapter(mRetrievedMessages);

        //sid 19 and rid 2905 are for testing
        sid = 19;
        rid = 2905;
        sender_id = String.valueOf(sid);
        receiver_id = String.valueOf(rid);

        String logMsg = "Requesting sid = " + sender_id + " receiver_id = " + receiver_id;
        Log.d("Actions OnCreate", logMsg);

        new FetchMessages().execute();
    }

    class FetchMessages extends AsyncTask<String, Void, JSONObject> {

        @Override
        protected JSONObject doInBackground(String... strings) {
            JSONObject json = null;

            // Set up parameters for the PHP
            List<NameValuePair> parameters = new ArrayList<NameValuePair>();
            parameters.add(new BasicNameValuePair("id1", sender_id));
            parameters.add(new BasicNameValuePair("id2", receiver_id));

            // Make the HTTP request
            json = jsonParser.makeHttpRequest(url_fetch_messages, "GET", parameters);

            // Log the JSON response
            Log.d("Single Message Details", json.toString());

            return json;
        }

        @Override
        protected void onPostExecute(JSONObject messagesStuff) {

            int success = 0; // JSON Success tag
            JSONArray messagesArray = null;
            JSONObject message = null;
            BroChatMsg broChatMsgObj = new BroChatMsg();
            // ArrayList<BroChatMsg> messagesList = new ArrayList<BroChatMsg>(); (use the adapter instead)
            long timestamp;
            String msgDate;

            try {
                success = messagesStuff.getInt(TAG_SUCCESS);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            if (success == 1) {

                try {
                    messagesArray = messagesStuff.getJSONArray(TAG_MESSAGES);
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                mAdapter.clear();

                for (int i = 0; i < messagesArray.length(); i++) {

                    //Populate the broChat object
                    try {

                        message = messagesArray.getJSONObject(i);

                        mQuickString = message.getString(TAG_SID);
                        broChatMsgObj.setSenderId(mQuickString);

                        mQuickString = message.getString(TAG_RID);
                        broChatMsgObj.setReceiverId(mQuickString);

                        mQuickString = message.getString(TAG_BODY);
                        mQuickString = mQuickString.replaceAll("\\r\\n", "");
                        broChatMsgObj.setMsgBody(mQuickString);

                        mQuickString = message.getString(TAG_TIMESTAMP);
                        broChatMsgObj.setTimestampStr(mQuickString);

                        timestamp = Long.valueOf(mQuickString) * 1000; //Used to format date
                        broChatMsgObj.setTimestamp(timestamp);

                        Date msgTime = new Date(timestamp);
                        broChatMsgObj.setMsgTime(msgTime);

                        msgDate = new SimpleDateFormat("MM/dd/yy h:mm a").format(msgTime);
                        broChatMsgObj.setMsgDate(msgDate);

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    sBroChatMsg = broChatMsgObj;

                    Log.d("sBroChat Message: ", String.valueOf(i));
                    Log.d("sBroChat SID ", sBroChatMsg.getSenderId());
                    Log.d("sBroChat RID ", sBroChatMsg.getReceiverId());
                    Log.d("sBroChat BODY ", sBroChatMsg.getMsgBody());
                    Log.d("sBroChat TIMESTAMP ", sBroChatMsg.getMsgDate());

                    mAdapter.add(sBroChatMsg);
                    // mAdapter.notifyDataSetChanged();

                    // mRetrievedMessages.add(broChatMsgObj);

                    /* This is pretty much redundant.
                    for (i = 0; i < mRetrievedMessages.size(); i++) {
                        Log.d("message ", String.valueOf(i));
                        Log.d("message ", mRetrievedMessages.get(i).getId().toString());
                        Log.d("message TIMESTAMP ", mRetrievedMessages.get(i).getMsgDate());
                        Log.d("message SID ", mRetrievedMessages.get(i).getSenderId());
                        Log.d("message RID ", mRetrievedMessages.get(i).getReceiverId());
                        Log.d("message BODY ", mRetrievedMessages.get(i).getMsgBody());
                    }
                    */

                } // end message parsing

                // sBroChat.setMessages(mRetrievedMessages); (no longer used)

                // refresh the list view
                mAdapter.notifyDataSetChanged();

            } else {
                // no matching messages turned up
                try {
                    mQuickString = messagesStuff.getString("message");
                } catch (JSONException e) {
                    e.printStackTrace();
                }
                if (mQuickString == "Connection error") {
                    mConnectFailed = 1;
                }
            }

            // return control to the main fragment
            // onFetchBrofileTaskComplete.setFetchBrofileTaskComplete();
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState) {

        View v = inflater.inflate(R.layout.brochat_fragment, container, false);
        /* This View holds the list and an edit window for new messages.

        NOTE!: Nothing from the list is being inflated here! The adapter does all that.
         */

        mLv = (ListView) v.findViewById(R.id.listView1);
        mLv.setAdapter(mAdapter);
        mLv.setEmptyView(v.findViewById(R.id.emptyElement));


        mNewMsgField = (EditText) v.findViewById(R.id.editText1);
        mNewMsgField.setText(newMessageBody);
        mNewMsgField.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence c, int start, int before, int count) {
                newMessageBody = c.toString();
            }

            @Override
            public void onTextChanged(CharSequence c, int start, int count, int after) {
                // This method intentionally left blank
            }

            @Override
            public void afterTextChanged(Editable c) {
                // This one too
            }
        });

        mSendMessageBtn = (Button)v.findViewById(R.id.new_chat_msg_button);
        mSendMessageBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO: Prepare new message, check sending privilege, send if allowed.
            }
        });

        return v;
    }

    private class MessageAdapter extends ArrayAdapter<BroChatMsg> {

        public MessageAdapter (ArrayList<BroChatMsg> chatter) {
            super(getActivity(), 0, chatter);
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // Displays one item at "position"
            boolean isLoggedUser = false;   // determines whether to show chat bubble on left or right
            boolean hasPrevious = false;    // false if this balloon is the oldest message

            String dateStr = "";
            BroChatMsg last_bcm = new BroChatMsg();
            long prevTimeStamp = 0;

            // If we weren't given a view, inflate one
            if (convertView == null) {
                convertView = getActivity().getLayoutInflater().inflate(R.layout.list_item_brochat, null);
            }

            // Configure the view for this message
            BroChatMsg bcm = getItem(position);
            if (position > 0) { hasPrevious = true; }
            if (hasPrevious) { last_bcm = getItem(position - 1); }
            if (bcm.getSid() == mCurrUserMemberId) {isLoggedUser = true; }
            Date itemDate = bcm.getMsgTime();
            long itemTimestamp = bcm.getTimestamp();
            dateStr = new SimpleDateFormat("E, MMM dd, h:mm a").format(itemDate);
            // don't print date if under 5 minutes since last message
            if (hasPrevious) {
                prevTimeStamp = last_bcm.getTimestamp();
                if ((itemTimestamp - prevTimeStamp) < 600000) { dateStr = "";}
            }
            TextView MsgTextView = (TextView)convertView.findViewById(R.id.comment);
            TextView DateTextView = (TextView)convertView.findViewById(R.id.timelabel);
            LinearLayout wrapper = (LinearLayout)convertView.findViewById(R.id.wrapper);

            MsgTextView.setText(bcm.getMsgBody());
            DateTextView.setText(dateStr);
            MsgTextView.setBackgroundResource(isLoggedUser ? R.drawable.bubble_yellow : R.drawable.bubble_green);
            wrapper.setGravity(isLoggedUser ? Gravity.LEFT : Gravity.RIGHT);

            return convertView;
        }

    }

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

        if (mConnectFailed == 1) {
            FragmentManager fm = getActivity().getSupportFragmentManager();
            CantConnectDialogFragment connectDialog = new CantConnectDialogFragment();
            connectDialog.show(fm, "Not connected");
        }
    }


}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_above="@+id/form"
        android:layout_alignParentLeft="true">
    </ListView>

    <TextView
        android:id="@+id/emptyElement"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="No messages"
        android:textSize="24dp"
        android:gravity="center_vertical|center_horizontal" />

    <RelativeLayout
        android:id="@+id/form"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:orientation="vertical">

        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:ems="10"
            android:inputType="text"
            android:layout_toLeftOf="@+id/new_chat_msg_button"
            android:layout_toStartOf="@+id/new_chat_msg_button" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send"
            android:id="@+id/new_chat_msg_button"
            android:layout_alignParentRight="true" />
    </RelativeLayout>

</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_above="@+id/form"
        android:layout_alignParentLeft="true">
    </ListView>

    <TextView
        android:id="@+id/emptyElement"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="No messages"
        android:textSize="24dp"
        android:gravity="center_vertical|center_horizontal" />

    <RelativeLayout
        android:id="@+id/form"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:orientation="vertical">

        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:ems="10"
            android:inputType="text"
            android:layout_toLeftOf="@+id/new_chat_msg_button"
            android:layout_toStartOf="@+id/new_chat_msg_button" />
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send"
            android:id="@+id/new_chat_msg_button"
            android:layout_alignParentRight="true" />
    </RelativeLayout>

</RelativeLayout>

目前,显示正确的数量下载的消息,但它们都是从JSON结构中检索到的最后一项的重复项。据我所知,XML布局不是罪魁祸首。发现的其他邮件发生了什么?

1 个答案:

答案 0 :(得分:0)

在您的周期中使用相同的实例broChatMsgObj会发生这种情况 所以所有项都指的是同一个对象的最后一个值。

    for (int i = 0; i < messagesArray.length(); i++) {

          //You have to create a new object
          broChatMsgObj = new BroChatMsg();

          //Populate the broChat object
          try {

                 message = messagesArray.getJSONObject(i);

                 mQuickString = message.getString(TAG_SID);
                 broChatMsgObj.setSenderId(mQuickString);
                 //....
              }

         //....
    }