什么是MVP呢,简单来说就是将view层和逻辑完全独立出来,让逻辑和显示完全独立。本例中就是采用了这种模式,让activity作为view层,activity中涉及了适配器,所以这里尝试让适配器作为P层来进行逻辑处理。以后可能要考虑用多个p来做逻辑处理。总之,我们先来分析下如何用MVP得思路来分析这个工程吧~
一、界面
界面这个环节有很多细节需要扣,之前我写过一篇文章就是讲这个界面实现的,推荐先去看看:http://www.cnblogs.com/tianzhijiexian/p/4295195.html
二、根据界面来思考逻辑
一般情况下我们从设计那里得到了一张图后就需要进行分析了,分析这个界面需要什么逻辑。所以我们再来看看界面是什么样的:
我们从上到下进行分析,分析时就需要写出接口了,等于把自然语言程序化。
1.顶部有退出按钮——finish()
2.顶部有刷新按钮——refresh();刷新成功后需要有回调——onRefreshSuccess()
3.界面有信息,需要适配器——setAdapter()
4.下方有+号,是发送图片的按钮——sendPhoto();因为是实时聊天界面,即使信息没发送成功,也需要添加到适配器中,显示一个没法送成功的标记就好。所以不需要做回调。只需要在适配器的getView()中根据list得item的标志来判断是否发送成功了,根据是否发送成功来显示没法送成功的感叹号。
5.有发送按钮,发送文字——addNewReply(String str);因为是实时聊天界面,即使信息没发送成功,也需要添加到适配器中,显示一个没法送成功的标记就好。需要在适配器的getView()中进行状态的回调,回调方式同上。
6.既然需要在getView中进行回调,那么activity中就要能有这个getView()的方法——onGetViewFromAdapter()
三、Activity需要实现的接口
这样我们大概的接口就已经写好了,下面来看看最终的接口文档:
接口 IUMengFeedbackView(实现友盟反馈的activity需要实现这个接口)
四、调用P层进行逻辑操作
我们假设我们的activity已经实现了这个接口,也已经做好了界面,那么是不是该调用p层来处理逻辑了呢?现在p层在哪里呢?别着急,p我已经写好了,而且对外提供了很多的方法让view可以随意调用。
UMengFeedbackPresenter的源码:
package com.kale.umenglib; import com.umeng.fb.FeedbackAgent; import com.umeng.fb.SyncListener; import com.umeng.fb.model.Conversation; import com.umeng.fb.model.Reply; import android.content.Context; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.List; import java.util.UUID; /** * @author:Jack Tony * 定义回话界面的adapter * @date :2015年2月9日 */ public class UMengFeedbackPresenter extends BaseAdapter { private final String TAG = getClass().getSimpleName(); /** * 表示是一对一聊天,有两个类型的信息 */ private static final int VIEW_TYPE_COUNT = 2; /** * 用户的标识 */ private static final int VIEW_TYPE_USER = 0; /** * 开发者的标识 */ private static final int VIEW_TYPE_DEV = 1; /** * 一次性加载多少条数据,默认10条 */ private int mLoadDataNum = 10; // default /** * 当前显示的数据条数 */ private int mCurrentMsgCount = 10; private Context mContext; /** * 负责显示umeng反馈界面信息的activity */ private IUMengFeedbackView mFeedbackView; /** * 反馈系统的回话对象 */ private Conversation mConversation; private static UMengFeedbackPresenter instance; private UMengFeedbackPresenter(IUMengFeedbackView view) { mContext = (Context) view; mFeedbackView = view; mConversation = new FeedbackAgent(mContext).getDefaultConversation(); mConversation.setOnChangeListener(new Conversation.OnChangeListener() { @Override public void onChange() { // 发送消息后会自动调用此方法,在这里更新下发送状态 notifyDataSetChanged(); } }); } public static UMengFeedbackPresenter getInstance(IUMengFeedbackView view) { if (instance == null) { instance = new UMengFeedbackPresenter(view); } return instance; } /** * 得到当前adapt中的数据条数 * * @return 当前adapt中的数据条数 */ @Override public int getCount() { // 如果开始时的数目小于一次性显示的数目,就按照当前的数目显示,否则会数组越界 int totalCount = mConversation.getReplyList().size(); if (totalCount < mCurrentMsgCount) { mCurrentMsgCount = totalCount; } return mCurrentMsgCount; } /** * @return 当前的position * 重要方法,计算出当前的position */ private int getCurrentPosition(int position) { int totalCount = mConversation.getReplyList().size(); if (totalCount < mCurrentMsgCount) { mCurrentMsgCount = totalCount; } return totalCount - mCurrentMsgCount + position; } @Override public Object getItem(int position) { position = getCurrentPosition(position); return mConversation.getReplyList().get(position); } @Override public long getItemId(int position) { return getCurrentPosition(position); } @Override public int getViewTypeCount() { // 这里是一对一聊天,所以是两种类型 return VIEW_TYPE_COUNT; } @Override public int getItemViewType(int position) { position = getCurrentPosition(position); // 获取单条回复 Reply reply = mConversation.getReplyList().get(position); if (reply.type.equals(Reply.TYPE_DEV_REPLY)) { // 开发者回复Item布局 return VIEW_TYPE_DEV; } else if (reply.type.equals(Reply.TYPE_USER_REPLY)) { // 用户反馈、回复Item布局 return VIEW_TYPE_USER; } else { return 0; } } @Override public View getView(int position, View convertView, ViewGroup parent) { position = getCurrentPosition(position); // 得到当前位置的reply对象 Reply reply = mConversation.getReplyList().get(position); //Log.d(TAG, "reply type = " + reply.type); if (convertView == null) { LayoutInflater inflater = LayoutInflater.from(mContext); // 根据Type的类型来加载不同的Item布局 switch (reply.type) { case Reply.TYPE_DEV_REPLY: // 如果是开发者回复的,那么就加载开发者回复的布局 convertView = inflater.inflate(mFeedbackView.getDevReplyLayoutId(), null); break; case Reply.TYPE_NEW_FEEDBACK: //break; case Reply.TYPE_USER_REPLY: convertView = inflater.inflate(mFeedbackView.getUserReplyLayoutId(), null); break; default: } } if (reply.type.equals(Reply.TYPE_USER_REPLY) || reply.type.equals(Reply.TYPE_NEW_FEEDBACK)) { mFeedbackView.setUserReplyView(convertView, reply); } else if (reply.type.equals(Reply.TYPE_DEV_REPLY)) { mFeedbackView.setDevReplyView(convertView, reply); } Reply nextReply = null; if ((position + 1) < mConversation.getReplyList().size()) { nextReply = mConversation.getReplyList().get(position + 1); } mFeedbackView.onGetViewFromAdapter(convertView, reply, nextReply); return convertView; } /** * 加载之前的聊天信息 */ public void loadOldData() { int loadDataNum = mLoadDataNum; int totalCount = mConversation.getReplyList().size(); if (loadDataNum + mCurrentMsgCount >= totalCount) { // 如果要加载的数据超过了数据的总量,算出实际加载的数据条数 loadDataNum = totalCount - mCurrentMsgCount; } mCurrentMsgCount += loadDataNum; notifyDataSetChanged(); mFeedbackView.onLoadOldDataSuccess(loadDataNum); } /** * 发送图片给开发者 */ public void sendPhotoToDev() { Intent intent = new Intent(); intent.putExtra(UMengFeedbackPhotoActivity.KEY_UMENG_GET_PHOTO, UMengFeedbackPhotoActivity.VALUE_UMENG_GET_PHOTO); intent.setClass(mContext, UMengFeedbackPhotoActivity.class); mContext.startActivity(intent); } /** * 当用户发送图片信息时,在Activity的onActivityResult中调用此方法来处理上传图片等后续操作 */ protected void getPhotoFromAlbum(Intent data) { //Log.e(TAG, "data.getDataString -- " + data.getDataString()); if (UMengB.a(mContext, data.getData())) { UMengB.a(mContext, data.getData(), "R" + UUID.randomUUID().toString(), new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); sendMsgToDev((String) msg.obj, Reply.CONTENT_TYPE_IMAGE_REPLY); } }); } } /** * 用户发送了一条新的信息后调用此方法 * * @param replyMsg 信息的内容 * @param type Reply.CONTENT_TYPE_TEXT_REPLY或者Reply.CONTENT_TYPE_IMAGE_REPLY */ public void sendMsgToDev(String replyMsg, String type) { if (type.equals(Reply.CONTENT_TYPE_TEXT_REPLY)) { mConversation.addUserReply(replyMsg); } else if (type.equals(Reply.CONTENT_TYPE_IMAGE_REPLY)) { mConversation.addUserReply("", replyMsg, "image_reply", -1.0F); } else if (type.equals(Reply.CONTENT_TYPE_AUDIO_REPLY)) { } mCurrentMsgCount++; syncToUmeng(); } /** * 将数据和服务器同步 * TODO:这里有两种写法,可以考虑换个实现方式。 */ public void syncToUmeng() { //new FeedbackAgent(mContext).sync();// 第一种写法 // 第二种写法↓ mConversation.sync(new SyncListener() { @Override public void onSendUserReply(List<Reply> replyList) { Log.d(TAG, "onSendUserReply"); if (replyList == null || replyList.size() < 1) { Log.d(TAG, "user 用户没有发送新的消息"); } else { notifyDataSetChanged(); } } @Override public void onReceiveDevReply(List<Reply> replyList) { Log.d(TAG, "onReceiveDevReply"); if (replyList == null || replyList.size() < 1) { // 没有开发者新的回复 Log.d(TAG, "dev 开发者没有新的回复"); } else { notifyDataSetChanged(); } } }); } /** * 设置界面一开始显示多少条数据,默认显示最近的十条信息 */ public void setReplyMsgCount(int count) { mCurrentMsgCount = count; } /** * 设置调用loadOldData()时,一次性加载多少条数据,默认10条 */ public void setLoadDataNum(int number) { mLoadDataNum = number; } /** * 得到适配器对象 */ public BaseAdapter getAdapter() { return this; } }