这部分是社区功能的开发,类似于贴吧,登录后才可以发贴和评论。
由于关联关系讲解起来比较复杂,以下用一个简单的案例来说明在Bmob中是如何使用关联关系的。
场景:用户发表帖子,同时又可对帖子进行评论留言。
在这个场景中涉及到三个表:用户表(_User
)、帖子表(Post
)、评论表(Comment
),以下是各个表的字段:
_User
字段如下:
字段 | 类型 | 含义 |
---|---|---|
objectId | String | 用户ID |
username | String | 用户名(可以既发帖子又发评论) |
age | Integer | 年龄 |
Post
字段如下:
字段 | 含义 | 类型 |
---|---|---|
objectId | String | 帖子ID |
title | String | 帖子标题 |
content | String | 帖子内容 |
author | Pointer | 帖子作者 |
likes | Relation | 喜欢帖子的读者 |
Comment
字段如下:
字段 | 含义 | 类型 |
---|---|---|
objectId | String | 评论ID |
content | String | 评论内容 |
post | Pointer | 评论对应的帖子 |
author | Pointer | 评论该帖子的人 |
5.RecyclerViewAdapter.java RecyclerView适配器
package com.example.wjy329.ufo;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import cn.bmob.v3.Bmob;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
private Context mContext;
private TextView head_title;
private TextView head_describe;
public RecyclerViewAdapter(Context mContext) {
this.mContext = mContext;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view =
LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_card_main, parent, false);
head_title = (TextView) view.findViewById(R.id.head_title);
head_describe = (TextView) view.findViewById(R.id.head_describe);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final View view = holder.mView;
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
@Override
public int getItemCount() {
return 10;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public final View mView;
public ViewHolder(View view) {
super(view);
mView = view;
}
}
}
6.BbsAdapter.java bbs适配器
package com.example.wjy329.ufo.Adapter;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.wjy329.ufo.Bean.Post;
import com.example.wjy329.ufo.Bean.bbs;
import com.example.wjy329.ufo.R;
import java.util.List;
/**
* Created by wjy329 on 2017/4/6.
*/
public class BbsAdapter extends RecyclerView.Adapter{
private LayoutInflater mInflater;
private Context mContext;
private List mDatas;
private OnItemClickListener mOnItemClickListener;
public BbsAdapter(Context context , Listdatas){
this.mContext = context;
this.mDatas = datas;
mInflater = LayoutInflater.from(context);
}
//创建一个ViewHolder
@Override
public BbsViewHolder onCreateViewHolder(ViewGroup arg0, int arg1) {
View view = mInflater.inflate(R.layout.item_single_textview,arg0,false);
BbsViewHolder viewHolder = new BbsViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(final BbsViewHolder holder, int pos) {
holder.id_tv.setText(mDatas.get(pos).getAuthor().getUsername());
holder.title_tv.setText(mDatas.get(pos).getTitle());
holder.content_tv.setText(mDatas.get(pos).getContent());
if(mOnItemClickListener != null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int pos = holder.getLayoutPosition();
mOnItemClickListener.onItemClick(holder.itemView,pos);
}
});
}
}
@Override
public int getItemCount() {
return mDatas.size();
}
public Object getItem(int position) {
return mDatas.get(position);
}
public interface OnItemClickListener{
void onItemClick(View view,int position);
}
public void setOnItemClickLitener(OnItemClickListener mOnItemClickListener)
{
this.mOnItemClickListener = mOnItemClickListener;
}
}
class BbsViewHolder extends ViewHolder{
public TextView id_tv;
public TextView title_tv;
public TextView content_tv;
public BbsViewHolder(View arg0) {
super(arg0);
id_tv = (TextView) arg0.findViewById(R.id.id_tv);
title_tv = (TextView) arg0.findViewById(R.id.title_tv);
content_tv = (TextView) arg0.findViewById(R.id.content_tv);
}
}
package com.example.wjy329.ufo.Bean;
import cn.bmob.v3.BmobObject;
/**
* Created by wjy329 on 2017/4/11..
*/
public class bbs extends BmobObject {
private String id; //用户名
private String title; //标题
private String content; //内容
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
8.Post.java 帖子实体类
package com.example.wjy329.ufo.Bean;
import cn.bmob.v3.BmobObject;
import cn.bmob.v3.datatype.BmobRelation;
/**
* Created by wjy329 on 2017/4/13.
*/
public class Post extends BmobObject {
private String title;//帖子标题
private String content;// 帖子内容
private MyUser author;//帖子的发布者,这里体现的是一对一的关系,该帖子属于某个用户
private BmobRelation likes;//多对多关系:用于存储喜欢该帖子的所有用户
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public MyUser getAuthor() {
return author;
}
public void setAuthor(MyUser author) {
this.author = author;
}
public BmobRelation getLikes() {
return likes;
}
public void setLikes(BmobRelation likes) {
this.likes = likes;
}
}
package com.example.wjy329.ufo.Bean;
import cn.bmob.v3.BmobObject;
/**
* Created by wjy329 on 2017/4/13.
*/
public class Comment extends BmobObject {
private String content;//评论内容
private MyUser user;//评论的用户,Pointer类型,一对一关系
private Post post; //所评论的帖子,这里体现的是一对多的关系,一个评论只能属于一个微博
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public MyUser getUser() {
return user;
}
public void setUser(MyUser user) {
this.user = user;
}
public Post getPost() {
return post;
}
public void setPost(Post post) {
this.post = post;
}
}
10.BbsFragment.java 社区主fragment类
package com.example.wjy329.ufo.fragment;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import com.example.wjy329.ufo.Activity.MainBBS;
import com.example.wjy329.ufo.Activity.NewCardActivity;
import com.example.wjy329.ufo.Adapter.BbsAdapter;
import com.example.wjy329.ufo.Bean.Post;
import com.example.wjy329.ufo.R;
import com.example.wjy329.ufo.Tools.DividerItemDecoration;
import java.util.List;
import cn.bmob.v3.Bmob;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.BmobUser;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
/**
* Created by wjy329 on 2017/2/25.
*/
public class BbsFragment extends Fragment {
private RecyclerView mRecyclerView;
private BbsAdapter mAdapter;
private FloatingActionButton mFloat;
private SwipeRefreshLayout mSwipe;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_bbs, container, false);
Bmob.initialize(this.getActivity(),"618f5d7ccf1b0dc170e0effbfd5dabae");
mRecyclerView = (RecyclerView) view.findViewById(R.id.id_recyclerView);
mFloat = (FloatingActionButton) view.findViewById(R.id.add_bt);
mSwipe = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh);
BmobQuery query =new BmobQuery();
query.order("-createdAt");
query.include("author");//在查询帖子信息的同时也把发布人的信息查询出来
query.findObjects(new FindListener() {
@Override
public void done(List list, BmobException e) {
if(e ==null) {
//布局管理
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
mRecyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new BbsAdapter(getActivity(), list);
mAdapter.setOnItemClickLitener(new BbsAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
//利用intent传值到bbs详情信息页面,MainBBS.java
Post data = (Post) mAdapter.getItem(position);
Bundle bundle =new Bundle();
bundle.putString("title",data.getTitle());
bundle.putString("id",data.getAuthor().getUsername());
bundle.putString("content",data.getContent());
bundle.putString("postid",data.getObjectId());
Intent intent = new Intent(getActivity(), MainBBS.class);
intent.putExtras(bundle);
startActivity(intent);
}
});
mRecyclerView.setAdapter(mAdapter);
//添加分隔线
mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(),DividerItemDecoration.VERTICAL_LIST));
}else{
Log.i("bmob","失败:"+e.getMessage()+","+e.getErrorCode());
Toast.makeText(getActivity(), "网络连接失败,请检查网络",
Toast.LENGTH_SHORT).show();
}
}
});
//下拉刷新
mSwipe.setColorSchemeColors(R.color.blue,R.color.green,R.color.red,R.color.yellow);
mSwipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
BmobQuery query =new BmobQuery();
query.order("-createdAt");
//在查询帖子信息的同时也把发布人的信息查询出来
query.include("author");
query.findObjects(new FindListener() {
@Override
public void done(List list, BmobException e) {
if(e ==null) {
//布局管理
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
mRecyclerView.setLayoutManager(linearLayoutManager);
mAdapter = new BbsAdapter(getActivity(), list);
mAdapter.setOnItemClickLitener(new BbsAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
Post data = (Post) mAdapter.getItem(position);
Bundle bundle =new Bundle();
bundle.putString("title",data.getTitle());
bundle.putString("id",data.getAuthor().getUsername());
bundle.putString("content",data.getContent());
Intent intent = new Intent(getActivity(), MainBBS.class);
intent.putExtras(bundle);
startActivity(intent);
}
});
mRecyclerView.setAdapter(mAdapter);
}else{
Log.i("bmob","失败:"+e.getMessage()+","+e.getErrorCode());
Toast.makeText(getActivity(), "网络连接失败,请检查网络",
Toast.LENGTH_SHORT).show();
}
}
});
mSwipe.setRefreshing(false);
}
},1000);
}
});
//发表新帖
mFloat.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BmobUser bmobUser = BmobUser.getCurrentUser();
if(bmobUser != null){
Intent newintent = new Intent(getActivity(), NewCardActivity.class);
startActivity(newintent);
}else{
Toast.makeText(getActivity(),"请登录后再发表!",Toast.LENGTH_LONG).show();
}
}
});
return view;
}
}
11.MainBBS.java 帖子详细页面
package com.example.wjy329.ufo.Activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.example.wjy329.ufo.Adapter.CommentAdapter;
import com.example.wjy329.ufo.Bean.Comment;
import com.example.wjy329.ufo.Bean.MyUser;
import com.example.wjy329.ufo.Bean.Post;
import com.example.wjy329.ufo.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import cn.bmob.v3.Bmob;
import cn.bmob.v3.BmobQuery;
import cn.bmob.v3.BmobUser;
import cn.bmob.v3.datatype.BmobPointer;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.FindListener;
import cn.bmob.v3.listener.SaveListener;
/**
* Created by wjy329 on 2017/4/11.
*/
public class MainBBS extends Activity {
private TextView bbs_title;
private TextView bbs_id;
private TextView bbs_content;
private ListView bbs_listview;
private ScrollView mScrollView;
private EditText comment_say;
private Button comment_send;
private CommentAdapter adapter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainbbs);
bbs_title = (TextView) findViewById(R.id.BBS_title);
bbs_id = (TextView) findViewById(R.id.BBS_id);
bbs_content = (TextView) findViewById(R.id.BBS_content);
bbs_listview = (ListView) findViewById(R.id.bbs_Recycler);
mScrollView = (ScrollView) findViewById(R.id.scrollView);
comment_say = (EditText) findViewById(R.id.bbs_et);
comment_send = (Button) findViewById(R.id.bbs_bt);
Bundle b = getIntent().getExtras();
String BBS_title = b.getString("title");
String BBS_id = b.getString("id");
String BBS_content = b.getString("content");
final String Post_id = b.getString("postid");
//文本框输入不能为空
isEditTextNull();
//发表评论
comment_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MyUser user = BmobUser.getCurrentUser(MyUser.class);
if(user != null){
Post post = new Post();
post.setObjectId(Post_id);
final Comment comment = new Comment();
comment.setContent(comment_say.getText().toString());
comment.setPost(post);
comment.setUser(user);
comment.save(new SaveListener() {
@Override
public void done(String s, BmobException e) {
if(e==null){
Toast.makeText(getApplication(), "评论发表成功",
Toast.LENGTH_SHORT).show();
refresh();
Log.i("bmob","评论发表成功");
}else{
Log.i("bmob","失败:"+e.getMessage());
}
}
});
}else{
Toast.makeText(getApplication(),"请登录后再发表!",Toast.LENGTH_LONG).show();
}
}
});
BmobQuery query = new BmobQuery();
Post post = new Post();
post.setObjectId(Post_id);
query.order("-createdAt");
query.addWhereEqualTo("post",new BmobPointer(post));
query.include("user,post.author");
query.findObjects(new FindListener() {
@Override
public void done(List list, BmobException e) {
if(e == null){
adapter = new CommentAdapter(getApplication(),list);
bbs_listview.setAdapter(adapter);
//scrollview嵌套listview,listview全部显示。
setListViewHeightBasedOnChildren(bbs_listview);
}
}
});
//防止从中间显示
mScrollView.smoothScrollTo(0,20);
bbs_title.setText(BBS_title);
bbs_id.setText(BBS_id);
bbs_content.setText(BBS_content);
}
private void isEditTextNull() {
comment_say.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(comment_say.length() != 0){
comment_send.setEnabled(true);
}else{
comment_send.setEnabled(false);
}
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(comment_say.length() != 0){
comment_send.setEnabled(true);
}else{
comment_send.setEnabled(false);
}
}
@Override
public void afterTextChanged(Editable editable) {
if(comment_say.length() != 0){
comment_send.setEnabled(true);
}else{
comment_send.setEnabled(false);
}
}
});
}
private void refresh() {
onCreate(null);
}
private void setListViewHeightBasedOnChildren(ListView bbs_listview) {
// 获取ListView对应的Adapter
ListAdapter listAdapter = bbs_listview.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0, len = listAdapter.getCount(); i < len; i++) {
// listAdapter.getCount()返回数据项的数目
View listItem = listAdapter.getView(i, null, bbs_listview);
// 计算子项View 的宽高
listItem.measure(0, 0);
// 统计所有子项的总高度
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = bbs_listview.getLayoutParams();
params.height = totalHeight+ (bbs_listview.getDividerHeight() * (listAdapter.getCount() - 1));
// listView.getDividerHeight()获取子项间分隔符占用的高度
// params.height最后得到整个ListView完整显示需要的高度
bbs_listview.setLayoutParams(params);
}
}
12.mainbbs.xml 详细帖子布局文件
13.CommentAdapter.java 评论的适配器
package com.example.wjy329.ufo.Adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.example.wjy329.ufo.Bean.Comment;
import com.example.wjy329.ufo.R;
import java.util.List;
/**
* Created by wjy329 on 2017/4/13.
*/
public class CommentAdapter extends BaseAdapter {
List h1;
LayoutInflater inflater;
public CommentAdapter(Context context, List comments){
this.h1 = comments;
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return h1.size();
}
@Override
public Object getItem(int position) {
return h1.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.list_item_bbs,null);
holder.commentContent = (TextView) convertView.findViewById(R.id.Comment_content);
holder.commentUser = (TextView) convertView.findViewById(R.id.Comment_user);
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
final Comment comment = h1.get(position);
holder.commentUser.setText(comment.getUser().getUsername());
holder.commentContent.setText(comment.getContent());
return convertView;
}
static class ViewHolder{
TextView commentContent;
TextView commentUser;
}
}
14.NewCardActivity.java 新帖子的主类
package com.example.wjy329.ufo.Activity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.example.wjy329.ufo.Bean.MyUser;
import com.example.wjy329.ufo.Bean.Post;
import com.example.wjy329.ufo.R;
import com.example.wjy329.ufo.fragment.BbsFragment;
import cn.bmob.v3.Bmob;
import cn.bmob.v3.BmobUser;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.SaveListener;
/**
* Created by wjy329 on 2017/4/13.
*/
public class NewCardActivity extends Activity{
private EditText bbsTitle;
private EditText bbsContent;
private Button bbsSent;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newbbs);
Bmob.initialize(getApplication(),"618f5d7ccf1b0dc170e0effbfd5dabae");
bbsTitle = (EditText) findViewById(R.id.new_bbsTitle);
bbsContent = (EditText) findViewById(R.id.new_bbsContent);
bbsSent = (Button) findViewById(R.id.new_bbsSent);
//文本框输入不能为空
isEditTextNull();
bbsSent.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MyUser user = BmobUser.getCurrentUser(MyUser.class);
//创建帖子信息
Post post = new Post();
post.setTitle(bbsTitle.getText().toString());
post.setContent(bbsContent.getText().toString());
post.setAuthor(user);
post.save(new SaveListener() {
@Override
public void done(String s, BmobException e) {
if(e == null){
Toast.makeText(getApplication(),"发布成功!",Toast.LENGTH_LONG).show();
finish();
Log.i("bmob","保存成功");
}else{
Log.i("bmob","保存失败:"+e.getMessage());
}
}
});
}
});
}
private void isEditTextNull() {
bbsTitle.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(bbsTitle.length() != 0){
bbsSent.setEnabled(true);
}else{
bbsSent.setEnabled(false);
}
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(bbsTitle.length() != 0){
bbsSent.setEnabled(true);
}else{
bbsSent.setEnabled(false);
}
}
@Override
public void afterTextChanged(Editable editable) {
if(bbsTitle.getText().toString().startsWith(" ")){
bbsTitle.setText("");
}
if ((bbsTitle.getText().toString().equals(""))||(bbsContent.getText().toString().equals(""))){
bbsSent.setEnabled(false);
}else{
bbsSent.setEnabled(true);
}
}
});
bbsContent.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(bbsContent.length() != 0){
bbsSent.setEnabled(true);
}else{
bbsSent.setEnabled(false);
}
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
if(bbsContent.length() != 0){
bbsSent.setEnabled(true);
}else{
bbsSent.setEnabled(false);
}
}
@Override
public void afterTextChanged(Editable editable) {
if ((bbsTitle.getText().toString().equals(""))||(bbsContent.getText().toString().equals(""))){
bbsSent.setEnabled(false);
}else{
bbsSent.setEnabled(true);
}
}
});
}
}
到这里,我们已经实现了社区功能,关于登录注册我将会专门记录一篇。