logo
- 简介
- 运行效果
- 设计思路
- 代码
- 参考
一、简介
该应用主要利用bmob提供的数据实时同步功能来让客户端对云端指定表的监听完成了群聊的基本功能,同时在消息类型上区分了文本消息和图片消息。应用可以判断消息类型并根据对应的消息类型来显示文本/图片。笔者接触Android不久,在性能的优化及程序的设计上如有不足还望指出~ 谢谢~
二、运行效果
--- 群聊消息截图三、设计思路
即时通讯的实现最大的难点在于双方数据的实时同步,现在Bmob已经帮我们解决了,所以我们只需要将云端的数据加载到ListView中进行显示即可。
我们要实现两种消息:文本消息 和 图片消息。两种消息在云端存放的本质是相同的,只不过一个存放的内容为发送的消息文本一个存放的是云端图片的URL。两种消息的区分可以另外定义一个变量viewtype(准确来说应该命名msgtype,命名viewtype是因为对应了不同的viewholder,不过这都不重要,不要在意这些细节)来实现,当viewtype为0时,以文本的形式展示,当viewtype为1时,以图片的形式展示。
我设计了如下结构:
类型 | 变量名 |
---|---|
String | name |
String | content |
int | viewtype |
其中name可省,也可以根据自己的需要添加其它值
之后调用bmob提供的save方法即可完成数据的保存,在BmobRealTimeData类的回调函数中就可以拿到新增的数据了。
本地数据的加载方法主要参考了文章结尾的参考
,在原基础上做了一些调整。
四、代码
除了以下代码使用前还要进行Bmob的初始化
以及在清单中添加相应的权限
和build.gradle中的部分依赖
Chat.class
public class Chat extends BmobObject{
public final static int TEXT_TYPE = 0;
public final static int IMAGE_TYPE = 1;
private int viewtype;
private String name;
private String content;
public Chat(String name, String content, int type) {
this.name = name;
this.content = content;
this.viewtype = type;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setViewtype(int viewtype) {
this.viewtype = viewtype;
}
public int getViewtype() {
return viewtype;
}
}
MainActivity.class
public class MainActivity extends Activity implements View.OnClickListener {
ListView mListView;
String name;
Button btn_send, btn_pic_send;
EditText et_content;
PlayAdapter mPlayAdapter;
List<Chat> messages = new ArrayList<Chat>();
BmobRealTimeData data = new BmobRealTimeData();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
name = telephonyManager.getDeviceId().toString();
initview();
initdata();
}
private void initdata() {
BmobQuery<Chat> query = new BmobQuery<Chat>();
query.order("createdAt");
query.setLimit(500);
query.findObjects(new FindListener<Chat>() {
@Override
public void done(List<Chat> list, BmobException e) {
if (e == null) {
for (Chat chat : list) {
messages.add(chat);
}
} else {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
});
data.start(new ValueEventListener() {
@Override
public void onConnectCompleted(Exception e) {
if (data.isConnected()) {
data.subTableUpdate("Chat");
}
}
@Override
public void onDataChange(JSONObject jsonObject) {
if (BmobRealTimeData.ACTION_UPDATETABLE.equals(jsonObject.optString("action"))) {
JSONObject data = jsonObject.optJSONObject("data");
Chat chat = new Chat(data.optString("name"), data.optString("content"), Integer.parseInt(data.optString("viewtype")));
messages.add(chat);
mPlayAdapter.notifyDataSetChanged();
}
}
});
}
private void initview() {
mListView = (ListView) findViewById(R.id.lv_data);
mPlayAdapter = new PlayAdapter(MainActivity.this, messages, name);
mListView.setAdapter(mPlayAdapter);
mListView.setDivider(null);
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
btn_pic_send = (Button) findViewById(R.id.btn_send_pic);
btn_send = (Button) findViewById(R.id.btn_send);
btn_pic_send.setOnClickListener(this);
btn_send.setOnClickListener(this);
et_content = (EditText) findViewById(R.id.et_msg);
}
private void sendMsg(String name, String msg, int msgType){
Chat chat = new Chat(name, msg, msgType);
chat.save(new SaveListener<String>() {
@Override
public void done(String s, BmobException e) {
if (e == null) {
et_content.setText("");
}
}
});
}
@Override
public void onClick(View view) {
if (view == btn_send) {
String content = et_content.getText().toString();
if (TextUtils.isEmpty(name) || TextUtils.isEmpty(content)) {
Toast.makeText(MainActivity.this, "消息不能为空", Toast.LENGTH_SHORT).show();
return;
} else {
sendMsg(name, content, Chat.TEXT_TYPE);
}
} else if (view == btn_pic_send) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, 42);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 42) {
try {
Uri uri = data.getData();
String path = getPath(this, uri);
final BmobFile pic = new BmobFile(new File(path));
pic.uploadblock(new UploadFileListener() {
@Override
public void done(BmobException e) {
if (e == null) {
sendMsg(name, pic.getFileUrl(), Chat.IMAGE_TYPE);
}
}
});
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
public static String getPath(Context context, Uri uri) throws URISyntaxException {
if ("content".equalsIgnoreCase(uri.getScheme())) {
String[] projection = { "_data" };
Cursor cursor = null;
try {
cursor = context.getContentResolver().query(uri, projection, null, null, null);
int column_index = cursor.getColumnIndexOrThrow("_data");
if (cursor.moveToFirst()) {
return cursor.getString(column_index);
}
} catch (Exception e) {
// Eat it Or Log it.
}
} else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
}
MsgAdapter.class
public class MsgAdapter extends BaseAdapter {
public static final int ITEM_TEXT = 0;
public static final int ITEM_PIC = 1;
private List<Chat> mList;
private Context context;
private String MyName;
private LayoutInflater inflater;
class Hodler1 {
LinearLayout leftLayout;
LinearLayout rightLayout;
TextView leftMsg;
TextView rightMsg;
Hodler1(View view) {
leftLayout = view.findViewById(R.id.left_layout);
rightLayout = view.findViewById(R.id.right_layout);
leftMsg = view.findViewById(R.id.left_msg);
rightMsg = view.findViewById(R.id.right_msg);
}
}
class Hodler2 {
LinearLayout left_pic_layout;
LinearLayout right_pic_layout;
ImageView leftPic;
ImageView rightPic;
Hodler2(View view) {
left_pic_layout = view.findViewById(R.id.pic_left_layout);
right_pic_layout = view.findViewById(R.id.pic_right_layout);
leftPic = view.findViewById(R.id.iv_picture_left);
rightPic = view.findViewById(R.id.iv_picture_right);
}
}
public PlayAdapter(Context context, List<Chat> mList, String name) {
this.context = context;
this.mList = mList;
inflater = LayoutInflater.from(context);
this.MyName = name;
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int i) {
return mList.get(i);
}
@Override
public int getItemViewType(int position) {
return mList.get(position).getViewtype();
}
//图片与文本对应两种不同的viewholder
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
int type = getItemViewType(i);
Hodler1 hodler1 = null;
Hodler2 hodler2 = null;
if (view == null) {
switch (type) {
case ITEM_TEXT:
view = inflater.inflate(R.layout.msg_item, null);
hodler1 = new Hodler1(view);
if (mList.get(i).getName().equals(MyName)) {
hodler1.leftLayout.setVisibility(View.GONE);
hodler1.rightLayout.setVisibility(View.VISIBLE);
hodler1.rightMsg.setText(mList.get(i).getContent());
} else {
hodler1.leftLayout.setVisibility(View.VISIBLE);
hodler1.leftMsg.setText(mList.get(i).getContent());
hodler1.rightLayout.setVisibility(View.GONE);
}
view.setTag(hodler1);
break;
case ITEM_PIC:
view = inflater.inflate(R.layout.msg_item_pic, null);
hodler2 = new Hodler2(view);
if (mList.get(i).getName().equals(MyName)) {
hodler2.left_pic_layout.setVisibility(View.GONE);
hodler2.right_pic_layout.setVisibility(View.VISIBLE);
Picasso.with(context).load(mList.get(i).getContent()).into(hodler2.rightPic);
} else {
hodler2.left_pic_layout.setVisibility(View.VISIBLE);
hodler2.right_pic_layout.setVisibility(View.GONE);
Picasso.with(context).load(mList.get(i).getContent()).into(hodler2.leftPic);
}
view.setTag(hodler2);
break;
default:
break;
}
} else {
switch (type) {
case ITEM_TEXT:
hodler1 = (Hodler1) view.getTag();
if (mList.get(i).getName().equals(MyName)) {
hodler1.leftLayout.setVisibility(View.GONE);
hodler1.rightLayout.setVisibility(View.VISIBLE);
hodler1.rightMsg.setText(mList.get(i).getContent());
} else {
hodler1.leftLayout.setVisibility(View.VISIBLE);
hodler1.leftMsg.setText(mList.get(i).getContent());
hodler1.rightLayout.setVisibility(View.GONE);
}
break;
case ITEM_PIC:
hodler2 = (Hodler2) view.getTag();
if (mList.get(i).getName().equals(MyName)) {
hodler2.left_pic_layout.setVisibility(View.GONE);
hodler2.right_pic_layout.setVisibility(View.VISIBLE);
Picasso.with(context).load(mList.get(i).getContent()).into(hodler2.rightPic);
} else {
hodler2.left_pic_layout.setVisibility(View.VISIBLE);
hodler2.right_pic_layout.setVisibility(View.GONE);
Picasso.with(context).load(mList.get(i).getContent()).into(hodler2.leftPic);
}
break;
default:
break;
}
}
return view;
}
}
网友评论