一个聊天对话窗口,类似于微信。源代码来自EOE。我想扩展一下图片和消息时间等功能。聊天的消息能准确无误的传值到对应的控件,但是聊天的消息传送过去的时候会发送“错位”现象,比如2011-10-01 12:01第一条消息
2011-10-01 12:02第二条消息
2011-10-01 12:03第三条消息结果运行出来后就是部分的时间错位但内容不错位(而且消息的时间不是固定的错位):2011-10-01 12:01第一条消息
2011-10-01 12:02第二条消息
2011-10-01 12:01第三条消息
贴代码。希望高人指点一下!刚接触才几天,以前也没接触过JAVA……
package cn.itcast.test.chat.adapter;public class ChatMessage { public static final int MESSAGE_FROM = 0;
public static final int MESSAGE_TO = 1; private int direction; private String content; public ChatMessage(int direction, String content) {
super();
this.direction = direction;
this.content = content;
} public int   getDirection() { return direction;}
public void  setDirection(int direction) {this.direction = direction;} public void setContent(String content) {this.content = content;} public CharSequence getContent() {return content;}}package cn.itcast.test.chat.adapter;import java.util.List;import jinnuo.test.R;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;public class ChattingAdapter extends BaseAdapter {
protected static final String TAG = "ChattingAdapter";
private Context context; private List<ChatMessage> chatMessages;
//private List<ChatMessage> chatSendTime; public ChattingAdapter(Context context, List<ChatMessage> messages) {
super();
this.context = context;
this.chatMessages = messages;
}
public int getCount() {
return chatMessages.size();
}
public Object getItem(int position) {
return chatMessages.get(position);
}
public long getItemId(int position) {
return position;
} public View getView(int position, View convertView , ViewGroup parent) {

ViewHolder holder = null;
ViewHolder holder1 = null; ChatMessage message = chatMessages.get(position);

        String ChatListMsg [] =message.getContent().toString().split("#ApE8#");


if (convertView == null || (holder = (ViewHolder) convertView.getTag()).flag != message.getDirection()) 
{
holder = new ViewHolder();
    holder1 = new ViewHolder();
holder.flag = ChatMessage.MESSAGE_FROM;
holder1.flag = ChatMessage.MESSAGE_FROM;
convertView = LayoutInflater.from(context).inflate(R.layout.chatting_item_from, null);
convertView.setTag(holder); }

holder.text = (TextView) convertView.findViewById(R.id.chatting_content_itv);//这个是绑定到消息内容控件
holder.text.setText(ChatListMsg[3].toString()+ "_" + ChatListMsg[2].toString()) ;

try{
holder1.text = (TextView) convertView.findViewById(R.id.chatting_time_tv);//这个是绑定到消息时间控件,另外这里不TRY就报错,我怀疑原因就在这里,但是死活搞不明白具体怎么弄
holder1.text.setText("_" + ChatListMsg[2].toString()) ;
}catch(Exception e){}
return convertView;
}
static class ViewHolder {
TextView text;
int flag;
}}<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout 
android:orientation="vertical" 
android:paddingLeft="6.0dip" 
android:paddingRight="6.0dip" 
android:layout_width="fill_parent" 
android:layout_height="wrap_content"
   xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView 
     android:id="@+id/chatting_time_tv" 
     style="@style/ChattingUISplit" android:text="aaaaaa" android:gravity="left"/>
    
      <TextView 
     android:id="@+id/chatting_content_itv" 
     android:autoLink="web" 
     android:background="@drawable/chatfrom_bg" 
     style="@style/ChattingUIText" />
</LinearLayout>

解决方案 »

  1.   

    我重新发一下
    //窗口代码
    package cn.itcast.test.chat;import java.util.ArrayList;
    import java.util.List;import cn.itcast.test.chat.adapter.ChatMessage;
    import cn.itcast.test.chat.adapter.ChattingAdapter;import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.Window;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ImageView;
    import android.widget.ListView;
    import android.widget.PopupWindow;public class MainActivity extends Activity {
    protected static final String TAG = "MainActivity";
    private ChattingAdapter chatHistoryAdapter;
    private List<ChatMessage> messages = new ArrayList<ChatMessage>(); private ListView chatHistoryLv;
    private Button sendBtn;
    private EditText textEditor;
    private ImageView sendImageIv;
    private ImageView captureImageIv;
    private View recording;
    private PopupWindow menuWindow = null; @Override
    public void onCreate(Bundle savedInstanceState) {
    requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.chatting);
    getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.chatting_title_bar);
    chatHistoryLv = (ListView) findViewById(R.id.chatting_history_lv);
    setAdapterForThis();
    sendBtn = (Button) findViewById(R.id.send_button);
    textEditor = (EditText) findViewById(R.id.text_editor);
    sendImageIv = (ImageView) findViewById(R.id.send_image);
    captureImageIv = (ImageView) findViewById(R.id.capture_image);
    sendBtn.setOnClickListener(l);
    sendImageIv.setOnClickListener(l);
    captureImageIv.setOnClickListener(l);
    recording = findViewById(R.id.recording);
    recording.setOnTouchListener(new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) {
    int action = event.getAction(); switch (action) {
    case MotionEvent.ACTION_UP:
    v.setBackgroundResource(R.drawable.hold_to_talk_normal);
    if (menuWindow != null)
    menuWindow.dismiss();
    Log.d(TAG, "---onTouchEvent action:ACTION_UP");
    break;
    case MotionEvent.ACTION_DOWN:
    v.setBackgroundResource(R.drawable.hold_to_talk_pressed);
    ViewGroup root = (ViewGroup) findViewById(R.id.chat_root);
    View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.audio_recorder_ring, null);
    menuWindow = new PopupWindow(view, 180, 180);
    // @+id/recorder_ring
    view.findViewById(R.id.recorder_ring).setVisibility(View.VISIBLE);
    view.setBackgroundResource(R.drawable.pls_talk);
    menuWindow.showAtLocation(root, Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL, 0, 0);
    Log.d(TAG, "---onTouchEvent action:ACTION_DOWN");
    // AudioRecorder recorder=new AudioRecorder(); break; } return true;
    }
    }); } // 设置adapter
    private void setAdapterForThis() {
    initMessages();
    chatHistoryAdapter = new ChattingAdapter(this, messages);
    chatHistoryLv.setAdapter(chatHistoryAdapter);
    } // 为listView添加数据
    private void initMessages() {
    messages.add(new ChatMessage(ChatMessage.MESSAGE_FROM, "1#ApE8#" +"hello"));
    messages.add(new ChatMessage(ChatMessage.MESSAGE_TO, "2#ApE8#" + "hello"));
    messages.add(new ChatMessage(ChatMessage.MESSAGE_FROM,  "3#ApE8#" +"你好吗?"));
    messages.add(new ChatMessage(ChatMessage.MESSAGE_TO, "4#ApE8#" + "非常好!"));
    messages.add(new ChatMessage(ChatMessage.MESSAGE_FROM,  "5#ApE8#" +"欢迎光临我的博客,http://hi.csdn.net/lyfi01"));
    messages.add(new ChatMessage(ChatMessage.MESSAGE_TO,"6#ApE8#" + "恩,好的,谢谢"));
    } /**
     * 按键时间监听
     */
    private View.OnClickListener l = new View.OnClickListener() { public void onClick(View v) { if (v.getId() == sendBtn.getId()) {
    String str = textEditor.getText().toString();
    String sendStr;
    if (str != null
    && (sendStr = str.trim().replaceAll("\r", "").replaceAll("\t", "").replaceAll("\n", "")
    .replaceAll("\f", "")) != "") {
    sendMessage(sendStr); }
    textEditor.setText(""); } else if (v.getId() == sendImageIv.getId()) {
    Intent i = new Intent();
    i.setType("image/*");
    i.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(i, Activity.DEFAULT_KEYS_SHORTCUT);
    } else if (v.getId() == captureImageIv.getId()) {
    Intent it = new Intent("android.media.action.IMAGE_CAPTURE");
    startActivityForResult(it, Activity.DEFAULT_KEYS_DIALER);
    }
    } // 模拟发送消息
    private void sendMessage(String sendStr) {
    messages.add(new ChatMessage(ChatMessage.MESSAGE_TO, sendStr));
    chatHistoryAdapter.notifyDataSetChanged();
    } };}
    //包cn.itcast.test.chat.adapter 中的 ChatMessage.java
    package cn.itcast.test.chat.adapter;public class ChatMessage { public static final int MESSAGE_FROM = 0;
    public static final int MESSAGE_TO = 1; private int direction;
    private String content; public ChatMessage(int direction, String content) {
    super();
    this.direction = direction;
    this.content = content;
    } public int getDirection() {
    return direction;
    } public void setDirection(int direction) {
    this.direction = direction;
    } public void setContent(String content) {
    this.content = content;
    } public CharSequence getContent() {
    return content;
    }}//包cn.itcast.test.chat.adapter 中的 ChattingAdapter.java
    package cn.itcast.test.chat.adapter;import java.util.List;import cn.itcast.test.chat.R;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;public class ChattingAdapter extends BaseAdapter {
    protected static final String TAG = "ChattingAdapter";
    private Context context; private List<ChatMessage> chatMessages; public ChattingAdapter(Context context, List<ChatMessage> messages) {
    super();
    this.context = context;
    this.chatMessages = messages; }
    public int getCount() {
    return chatMessages.size();
    }
    public Object getItem(int position) {
    return chatMessages.get(position);
    }
    public long getItemId(int position) {
    return position;
    } public View getView(int position, View convertView , ViewGroup parent) {

    ViewHolder holder = null;
    ViewHolder holder1 = null; ChatMessage message = chatMessages.get(position);

            String ChatListMsg [] =message.getContent().toString().split("#ApE8#");


    if (convertView == null || (holder = (ViewHolder) convertView.getTag()).flag != message.getDirection()) 
    {
    holder = new ViewHolder();
    holder1 = new ViewHolder();

    if (message.getDirection() == ChatMessage.MESSAGE_FROM) {
    holder.flag = ChatMessage.MESSAGE_FROM;
    holder1.flag = ChatMessage.MESSAGE_FROM;
                    convertView = LayoutInflater.from(context).inflate(R.layout.chatting_item_from, null);
    } else {
    holder.flag = ChatMessage.MESSAGE_TO;
    holder1.flag = ChatMessage.MESSAGE_TO;
                    convertView = LayoutInflater.from(context).inflate(R.layout.chatting_item_to, null);
    }

    holder.text = (TextView) convertView.findViewById(R.id.chatting_content_itv);
    holder1.text = (TextView) convertView.findViewById(R.id.chatting_time_tv);
    holder1.text.setText(ChatListMsg[0]);
    convertView.setTag(holder);

    } holder.text.setText(ChatListMsg[1]+" _文字") ; return convertView;
    }
    /*public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    ChatMessage message = chatMessages.get(position);
    if (convertView == null || (holder = (ViewHolder) convertView.getTag()).flag != message.getDirection()) { holder = new ViewHolder();
    if (message.getDirection() == ChatMessage.MESSAGE_FROM) {
    holder.flag = ChatMessage.MESSAGE_FROM; convertView = LayoutInflater.from(context).inflate(R.layout.chatting_item_from, null);
    } else {
    holder.flag = ChatMessage.MESSAGE_TO;
    convertView = LayoutInflater.from(context).inflate(R.layout.chatting_item_to, null);
    } holder.text = (TextView) convertView.findViewById(R.id.chatting_content_itv);
    convertView.setTag(holder);
    }
    holder.text.setText(message.getContent()); return convertView;
    }*/
    //优化listview的Adapter
    static class ViewHolder {
    TextView text;
    int flag;
    }}
      

  2.   


    package cn.itcast.test.ui;
    import cn.itcast.test.chat.R;
    import android.content.Context;
    import android.os.Handler;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.View;
    import android.widget.LinearLayout;public class ResizeLayout extends LinearLayout { int count = 0;
    int count1 = 0;
    int count2 = 0;
    //定义默认的软键盘最小高度,这是为了避免onSizeChanged在某些下特殊情况下出现的问题。
    private static final int SOFTKEYPAD_MIN_HEIGHT = 50;
    private Handler uiHandler = new Handler();
    private static final String TAG = "ResizeLayout"; public ResizeLayout(Context context) {
    super(context);
    } public ResizeLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    } @Override
    protected void onSizeChanged(int w, final int h, int oldw, final int oldh) {
    super.onSizeChanged(w, h, oldw, oldh); Log.i(TAG, "onSizeChanged " + count++ + "=>onResize called! w=" + w + ",h=" + h + ",oldw=" + oldw + ",oldh=" + oldh); uiHandler.post(new Runnable() {
    public void run() {
    if (oldh - h > SOFTKEYPAD_MIN_HEIGHT)
    // 必须设置为View.GONE不占空间
    findViewById(R.id.talk_panel).setVisibility(View.GONE);
    else
    findViewById(R.id.talk_panel).setVisibility(View.VISIBLE);
    }
    });
    }
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    Log.e(TAG, "onLayout " + count1++ + "=>OnLayout called! l=" + l + ", t=" + t + ",r=" + r + ",b=" + b);
    }
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.e(TAG, "onMeasure " + count2++ + "=>onMeasure called! widthMeasureSpec=" + widthMeasureSpec + ", heightMeasureSpec="
    + heightMeasureSpec); }
    }
    //布局XML<?xml version="1.0" encoding="UTF-8"?>
    <LinearLayout 
    android:orientation="vertical" 
    android:paddingLeft="6.0dip" 
    android:paddingRight="6.0dip" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
       xmlns:android="http://schemas.android.com/apk/res/android">
        <TextView 
         android:id="@+id/chatting_time_tv" 
         style="@style/ChattingUISplit" />
        
          <TextView 
         android:id="@+id/chatting_content_itv" 
         android:autoLink="web" 
         android:background="@drawable/chatfrom_bg" 
         style="@style/ChattingUIText" />
    </LinearLayout>
    <?xml version="1.0" encoding="UTF-8"?>
    <LinearLayout android:orientation="vertical" android:paddingLeft="6.0dip" android:paddingRight="6.0dip" android:layout_width="fill_parent" android:layout_height="wrap_content"
      xmlns:android="http://schemas.android.com/apk/res/android">
        <TextView 
         android:id="@+id/chatting_time_tv" 
         style="@style/ChattingUISplit" />
        <LinearLayout 
         android:orientation="horizontal" 
         android:layout_width="fill_parent" 
         android:layout_height="wrap_content">
            <TextView 
             android:layout_width="wrap_content" 
             android:layout_height="wrap_content" 
             android:layout_weight="1.0" />
            <ImageView 
             android:id="@+id/chatting_state_iv" 
             android:layout_width="wrap_content" 
             android:layout_height="wrap_content" />
              <TextView 
             android:autoLink="web" 
             android:id="@+id/chatting_content_itv" 
             android:background="@drawable/chatto_bg" 
             style="@style/ChattingUIText" />
        </LinearLayout>
    </LinearLayout>
    代码就这些。这个代码是我在EOE的这篇帖子(http://www.eoeandroid.com/thread-74595-1-1.html)略加修改的,其实也没修改,就把原来没有显示的用于显示消息时间的空间拿出来绑定了一下…
      

  3.   

    问题在于convertView.setTag(holder);你的holder1木有添加进去。
      

  4.   


    感谢您的回复,能否详细指点一下我该怎么添加 convertView.setTag(holder1); ?
    我尝试 holder.text = (TextView) convertView.findViewById(R.id.chatting_content_itv);
    holder1.text = (TextView) convertView.findViewById(R.id.chatting_time_tv);
    holder1.text.setText(ChatListMsg[0]);
    convertView.setTag(holder);
    convertView.setTag(holder1);但这样更乱了
      

  5.   

     if (convertView == null || (holder = (ViewHolder) convertView.getTag()).flag != message.getDirection()) 这个判断后半句
     和convertView.setTag(holder);的问题你参照apidemo里面Adapter的用法改下就好了,判断里面只要 if (convertView == null )后面convertView.setTag(holder)放外面就行了测试通过,就是这个毛病,改过来就好了!!!!!