关于即时通讯高度解耦合框架之一 适配器中不同类型消息框架

先介绍BaseHolder类,这个类是聊天类型的控件载体,包含通用的contentview,由initBaseHolder里面的参数传递

public class BaseHolder {
   
   /**
    * row type {@link ChattingRowType}
    */
   protected int type;

   /**
    * for upload message .
    */
   protected ProgressBar progressBar;
   protected ImageView chattingAvatar;
   protected TextView chattingTime;
   protected TextView chattingUser;
   
   protected ImageView uploadState;
   protected View baseView;
   protected View clickAreaView;
   
   public BaseHolder(int type) {
      this.type = type;
   }

   /**
    * @param baseView
    */
   public BaseHolder(View baseView) {
      super();
      this.baseView = baseView;
   }
   
   public void initBaseHolder(View baseView) {
      this.baseView = baseView;
      chattingTime = (TextView) baseView.findViewById(R.id.chatting_time_tv);
      chattingAvatar = (ImageView) baseView.findViewById(R.id.chatting_avatar_iv);
      clickAreaView = baseView.findViewById(R.id.chatting_click_area);
      uploadState  = (ImageView) baseView.findViewById(R.id.chatting_state_iv);
   }
   
  /**
    * @return the baseView
    */
   public View getBaseView() {
      return baseView;
   }

   /**
    * @return the type
    */
   public int getType() {
      return type;
   }

   /**
    * @return the progressBar
    */
   public ProgressBar getUploadProgressBar() {
      return progressBar;
   }

   /**
    * @return the chattingAvatar
    */
   public ImageView getChattingAvatar() {
      return chattingAvatar;
   }

   /**
    * @return the chattingTime
    */
   public TextView getChattingTime() {
      return chattingTime;
   }

   /**
    * @param chattingTime the chattingTime to set
    */
   public void setChattingTime(TextView chattingTime) {
      this.chattingTime = chattingTime;
   }

   /**
    * @return the chattingUser
    */
   public TextView getChattingUser() {
      return chattingUser;
   }

  /**
    * @return the uploadState
    */
   public ImageView getUploadState() {
      return uploadState;
   }

   /**
    * @return the clickAreaView
    */
   public View getClickAreaView() {
      return clickAreaView;
   }

 }
再看他的子类CardViewHolder,initBaseHolder方法中条用父类的initBaseHolder加载的通用控件,在扩展了自己的新增控件
public class CardViewHolder extends  BaseHolder{

    private TextView content;
    private TextView nick;
    private ImageView avatar;
    private LinearLayout ll_click;
    public LinearLayout getLl_click() {
        if(ll_click==null){
            ll_click = (LinearLayout)baseView.findViewById(R.id.bg_ll);
        }
        return ll_click;
    }

    public ImageView getAvatar() {
        if(avatar==null){
            avatar = (ImageView)baseView.findViewById(R.id.avatar);
        }
        return avatar;
    }

    public TextView getContent() {
        if(content==null){
            content =(TextView) baseView.findViewById(R.id.content);
        }
        return content;
    }

    public TextView getNick() {
        if(nick==null){
            nick = (TextView)baseView.findViewById(R.id.nick);
        }
        return nick;
    }


    public CardViewHolder(int type) {
        super(type);
    }


    public BaseHolder initBaseHolder(View baseView , boolean receive) {
        super.initBaseHolder(baseView);//父类通用控件,以下为扩展的控件
        content =(TextView) baseView.findViewById(R.id.content);
        nick = (TextView)baseView.findViewById(R.id.nick);
        avatar = (ImageView)baseView.findViewById(R.id.avatar);
        ll_click = (LinearLayout)baseView.findViewById(R.id.bg_ll);
        return this;
    }

}
以上为各个item对应holder控件,以下是用数据实例化holder里面控件的接口类
public interface IChattingRow {

    /**
     * 获取实例的convertView,由具体的item子类重写实现,并给具体的子类的convertView设置tag为子类的holder以供复用
     */
    View buildChatView(LayoutInflater inflater, View convertView);

    /**
     *给baseHolder里面的控件填充数据
     */
    void buildChattingBaseData(Context context, BaseHolder baseHolder, ECMessage detail, int position);

    /**
     * @return 返回具体的item类型,有具体子类实现
     */
    int getChatViewType();

}
接下来写一个abstract类来实现IChattingRow接口,这个类为所有item通用的控件填充数据
public abstract class BaseChattingRow implements IChattingRow {
   int mRowType;

   public BaseChattingRow(int type) {
      mRowType = type;
   }

   /**
    * 处理消息的发送状态设置
    * 
    * @param position
    *            消息的列表所在位置
    * @param holder
    *            消息ViewHolder
    * @param l
    */
   protected static void getMsgStateResId(int position, BaseHolder holder,
         ECMessage msg, View.OnClickListener l) {
      if (msg != null && msg.getDirection() == ECMessage.Direction.SEND) {
         ECMessage.MessageStatus msgStatus = msg.getMsgStatus();
         if (msgStatus == ECMessage.MessageStatus.FAILED) {
            holder.getUploadState().setImageResource(
                  R.drawable.msg_state_failed_resend);
            holder.getUploadState().setVisibility(View.VISIBLE);
            if (holder.getUploadProgressBar() != null) {
               holder.getUploadProgressBar().setVisibility(View.GONE);
            }
         } else if (msgStatus == ECMessage.MessageStatus.SUCCESS
               || msgStatus == ECMessage.MessageStatus.RECEIVE) {
            holder.getUploadState().setImageResource(0);
            holder.getUploadState().setVisibility(View.GONE);
            if (holder.getUploadProgressBar() != null) {
               holder.getUploadProgressBar().setVisibility(View.GONE);
            }

         } else if (msgStatus == ECMessage.MessageStatus.SENDING) {
            holder.getUploadState().setImageResource(0);
            holder.getUploadState().setVisibility(View.GONE);
            if (holder.getUploadProgressBar() != null) {
               holder.getUploadProgressBar().setVisibility(View.VISIBLE);
            }
            
         } else {
            if (holder.getUploadProgressBar() != null) {
               holder.getUploadProgressBar().setVisibility(View.GONE);
            }
            LogUtil.d(TAG, "getMsgStateResId: not found this state");
         }

         ViewHolderTag holderTag = ViewHolderTag.createTag(msg,
               ViewHolderTag.TagType.TAG_RESEND_MSG, position);
         holder.getUploadState().setTag(holderTag);
         holder.getUploadState().setOnClickListener(l);
      }
   }
   protected abstract void buildChattingData(Context context,
         BaseHolder baseHolder, ECMessage detail, int position);//填充扩展的holder里面控件的数据,由具体子类实现

   @Override
   public void buildChattingBaseData(Context context, BaseHolder baseHolder,
         ECMessage detail, int position) {

      // 处理其他使用逻辑
      buildChattingData(context, baseHolder, detail, position);
      String sid = detail.getSessionId();
      String avatar = "";
      String nick = "";
      if (detail.getDirection() == ECMessage.Direction.SEND) {//如果是信息发送出去,则处理自己头像和昵称数据
      } else {//如果是接收的别人的信息,则处理对方头像和昵称数据
      }
      //填充头像,昵称,以及通用的点击事件
      // 头像
      setContactPhoto(baseHolder, avatar);
      // 昵称
      setDisplayName(baseHolder, nick);
      // 头像点击事件
      setContactPhotoClickListener(context, baseHolder, detail);
   }

   private void setContactPhotoClickListener(final Context context,
         BaseHolder baseHolder, final ECMessage detail) {
      if (baseHolder.getChattingAvatar() != null && detail != null) {
         baseHolder.getChattingAvatar().setOnClickListener(
               new View.OnClickListener() {
                  @Override
                  public void onClick(View v) {
                  }
               });
      }
   }
	
  public static void setDisplayName(BaseHolder baseHolder, String displayName) {
      if (baseHolder == null || baseHolder.getChattingUser() == null) {
         return;
      }

      if (TextUtils.isEmpty(displayName)) {
         baseHolder.getChattingUser().setVisibility(View.GONE);
         return;
      }
      baseHolder.getChattingUser().setText(displayName);
      baseHolder.getChattingUser().setVisibility(View.VISIBLE);
   }

   
   /**
    * 添加用户头像
    * 
    * @param baseHolder
    */
   private void setContactPhoto(BaseHolder baseHolder, String avatar) {
      if (baseHolder.getChattingAvatar() != null) {
         try {
            ImageUtils.setHeadImage(avatar, baseHolder.getChattingAvatar());
         } catch (Exception e) {
         }
      }
   }
 }
以下为具体的实现类
public class SendTCardRow extends BaseChattingRow{
    public SendTCardRow(int type) {
        super(type);
    }
    @Override
    protected void buildChattingData(final Context context, BaseHolder baseHolder, ECMessage detail, int position) {//填充扩展数据
        CardViewHolder holder = (CardViewHolder) baseHolder;
        ECMessage message = detail;
        if(message != null && message.getType() == ECMessage.Type.TXT){
            if(message.getDirection()==ECMessage.Direction.SEND){
                holder.getContent().setText("已向对方推荐个人名片");
            }else {
                holder.getContent().setText("对方向您推荐个人名片");
            }
            String jstr = message.getUserData();
            final JSONObject obj = (JSONObject) JSONObject.parse(jstr);
            ImageUtils.setHeadImage((String) obj.get("avatar"),holder.getAvatar());
            holder.getNick().setText((String) obj.get("nick"));
            holder.getLl_click().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                }
            });
        }
    }

    @Override
    public View buildChatView(LayoutInflater inflater, View convertView) {//获取具体化的itemView
        if (convertView == null) {
            convertView = new ChattingItemContainer(inflater,
                    R.layout.chatting_item_send_card);
            CardViewHolder holder = new CardViewHolder(mRowType);
            convertView.setTag(holder.initBaseHolder(convertView, true));
        }
        return convertView;
    }

    @Override
    public int getChatViewType() {//获取Item的类型
        return ChattingRowType.SEND_TCARD_ROW.ordinal();
    }
  }
以下为不同的item类型的枚举类
public enum ChattingRowType {

    /**
     * display a image of message received
     */
    IMAGE_ROW_RECEIVED("C200R" , Integer.valueOf(1)),

    /**
     * display a image of message transmitted
     */
    IMAGE_ROW_TRANSMIT("C200T" , Integer.valueOf(2)),


    /**
     * display a file of message received
     */
    FILE_ROW_RECEIVED("C1024R" , Integer.valueOf(3)),

    /**
     * display a file of message transmitted
     */
    FILE_ROW_TRANSMIT("C1024T" , Integer.valueOf(4)),

    /**
     * display a voice of message received
     */
    VOICE_ROW_RECEIVED("C60R" , Integer.valueOf(5)),

    /**
     *  display a voice of message transmitted
     */
    VOICE_ROW_TRANSMIT("C60T" , Integer.valueOf(6)),

    /**
     * Display text of message received
     */
    DESCRIPTION_ROW_RECEIVED("C2000R" , Integer.valueOf(7)),

    /**
     * Display text of message transmitted
     */
    DESCRIPTION_ROW_TRANSMIT("C2000T" , Integer.valueOf(8)),

    /**
     * chatting item for system .such as time
     */
    CHATTING_SYSTEM("C18600668603R" , Integer.valueOf(9)),
    
    LOCATION_ROW_RECEIVED("C2200R" , Integer.valueOf(10)),
    
    LOCATION_ROW_TRANSMIT("C2200T" , Integer.valueOf(11)),
    CALL_ROW_RECEIVED("C2400R" , Integer.valueOf(12)),
    CALL_ROW_TO("C2400T" , Integer.valueOf(13)),

 //  CALL_ROW_TRANSMIT("C2400T" , Integer.valueOf(13));


    ADD_ROW("1011" , Integer.valueOf(14)),
    ADD_RESULT_ROW("1012" , Integer.valueOf(15)),


    ADD_HELP_ROW("1015" , Integer.valueOf(16)),
    ADD_HELP_RESULT_ROW("1016" , Integer.valueOf(17)),

    SEND_TCARD_ROW("1019",Integer.valueOf(19)),
    SEND_THELP_ROW("1020",Integer.valueOf(20)),

    SEND_REDBAGS_ROW("2000",Integer.valueOf(21)),//发红包
    SEND_KITE_ROW("2001",Integer.valueOf(22)),//发礼物
    SHARE_SHOW_ROW("2002",Integer.valueOf(23));//发礼物

    private final Integer mId;
    private final Object mDefaultValue;

    /**
     * Constructor of <code>ChattingRowType</code>.
     *
     * @param id The unique identifier of the setting
     * @param defaultValue The default value of the setting
     */
    private ChattingRowType(Object defaultValue , Integer id) {
        this.mId = id;
        this.mDefaultValue = defaultValue;
    }

    /**
     * Method that returns the unique identifier of the setting.
     * @return the mId
     */
    public Integer getId() {
        return this.mId;
    }

    /**
     * Method that returns the default value of the setting.
     *
     * @return Object The default value of the setting
     */
    public Object getDefaultValue() {
        return this.mDefaultValue;
    }


    /**
     *通过value(类型的字段代号)获取对应的类型
     */
    public static ChattingRowType fromValue(String value) {
        ChattingRowType[] values = values();
        int cc = values.length;
        for (int i = 0; i < cc; i++) {
            if (values[i].mDefaultValue.equals(value)) {
                return values[i];
            }
        }
        return null;
    }

}
接下来就是重点了,怎么在适配器adapter中配置不同类型的convertView;
重点看getView 方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
   ECMessage item = getItem(position);
   if (item == null) {
      return null;
   }
   boolean showTimer = false;
   if (position == 0) {
      showTimer = true;
   }
   if (position != 0) {//是否显示时间
      ECMessage previousItem = getItem(position - 1);
      if (mShowTimePosition.contains(item.getMsgId())
            || (item.getMsgTime() - previousItem.getMsgTime() >= 180000L)) {
         showTimer = true;

      }
   }
   BaseChattingRow chattingRow;

   String msgT = "";

   if (item.getType() == ECMessage.Type.TXT
         && !TextUtils.isEmpty(item.getUserData())) {//自己扩展的消息类型
      try {
         JSONObject map = JSONObject.parseObject(item.getUserData());
         msgT = map.getString("msg_type");
         String video_id  = map.getString("video_id");
         String nick  = map.getString("nick");
      } catch (JSONException e) {
      }
      chattingRow = getBaseChattingRow(msgT,
            item.getDirection() == ECMessage.Direction.SEND);//根据消息类型扩展字段获取到对应的消息类型
   } else {//第三方SDK自带的消息类型
      int messageType = ChattingsRowUtils.getChattingMessageType(item
            .getType());//获取第三方SDK自带的消息类型代号
      chattingRow = getBaseChattingRow(messageType,
            item.getDirection() == ECMessage.Direction.SEND);
   }

   View chatView = chattingRow.buildChatView(
         LayoutInflater.from(mContext), convertView);//给对应的消息类型填充布局,并设置了tag
   BaseHolder baseHolder = (BaseHolder) chatView.getTag();//根据tag获取对应的holder

   chattingRow.buildChattingBaseData(mContext, baseHolder, item, position);//给对应的holder填充控件数据
   return chatView;
}
/**
 * 根据消息类型返回相对应的自带消息Item
 * 
 * @param rowType
 * @param isSend
 * @return
 */
public BaseChattingRow getBaseChattingRow(int rowType, boolean isSend) {
   StringBuilder builder = new StringBuilder("C").append(rowType);

   if (isSend) {
      builder.append("T");
   } else {
      builder.append("R");
   }

   LogUtil.d("ChattingListAdapter",
         "builder.toString() = " + builder.toString());
   ChattingRowType fromValue = ChattingRowType.fromValue(builder
         .toString());
   LogUtil.d("ChattingListAdapter", "fromValue = " + fromValue);
   IChattingRow iChattingRow = mRowItems.get(fromValue.getId().intValue());
   return (BaseChattingRow) iChattingRow;
}

/**
 * 获取扩展消息类型
 * @param isSend
 * @return
 */
public BaseChattingRow getBaseChattingRow(String msgT, boolean isSend) {
   ChattingRowType fromValue = ChattingRowType.fromValue(msgT);
   if(fromValue!=null){
      IChattingRow iChattingRow = mRowItems.get(fromValue.getId()
            .intValue());
      return (BaseChattingRow) iChattingRow;
   }

   return null;
}
public class ChattingsRowUtils {

    /**
     *
     * @param type
     * @return
     */
   public static int getChattingMessageType(ECMessage.Type type) {
      if(type == ECMessage.Type.TXT) {
         return 2000;
      } else if (type == ECMessage.Type.VOICE) {
         return 60;
      } else if (type == ECMessage.Type.FILE) {
         return 1024;
      } else if (type == ECMessage.Type.IMAGE) {
         return 200;
      }else if(type==ECMessage.Type.VIDEO){
         return 1024;
      }else if(type==ECMessage.Type.LOCATION){
         return 2200;
      }else if(type== ECMessage.Type.CALL){
         return  2400;
      }
      return 2000;
   }

  嗯,代码有点多,重点记住标注的方法和面向对象思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值