使用Bmob实现失物招领app

Judy ·
更新时间:2024-09-21
· 517 次阅读

失物招领app,这个app是非常适合初学者在学习数据库或bmob云数据库开发时练习的项目。在我完成这个app的开发后,确实收获很多,那么。这篇文章我来整理一下思路和开发时遇到的坎坷和解决方法。 首先常规的按流程来,先编写页面,这次的失物招领app,我所实现的功能很简单,所涉及的数据库的操作也是增、删、改、查。

一、页面设计

页面分类

登录页面(login.xml)
注册页面(register.xml)
发布页面(add_lost_information.xml)
浏览列表页面(lost_and_found.xml)
欢迎(启动)页面(welcome.xml)
浏览列表的内容页面(item.xml)
长按显示的编辑和删除的控件(pop_window_view.xml) (布局页面代码,看文章后面的代码链接)
二、设计与数据库中对应的实体数据类

这个根据在bmob里面的表来设计 举个例子 Person表,里面有String name 和 String password,那User.java就这样写。

package com.example.tone.bean;

import android.widget.Toast;

import java.lang.ref.SoftReference;

import cn.bmob.v3.BmobObject;
import cn.bmob.v3.exception.BmobException;
import cn.bmob.v3.listener.SaveListener;

import static cn.bmob.v3.Bmob.getApplicationContext;

public class Person extends BmobObject {
public String getName() {
return name;
}

public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } String name; String password;

}

编写属性的Get和Set方法,AndroidStdio的快捷操作是,选中String name;String password;右键单击选择Greater,选择创建get和set方法。

三、与页面对应的功能类设计

这里主要编写这些页面的逻辑。

Welcome.java

主要的逻辑操作就是,显示开屏图片然后停留2秒,跳转到登录页面

//Bmob默认初始化
Bmob.initialize(this,“你自己的ID”);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//进入登录页面
Intent intent = new Intent(WelcomeActivity.this,LoginActivity.class);
startActivity(intent);
finish();
}
},2000);
login.java

获取用户输入的用户名和密码 使用bmob的login方法实现登录 单击“还没注册”跳转注册页面 登录代码代码如下

private void bmobUserAccotuntLogin(){
final String accountName = accountLoginName.getText().toString().trim(); //从控件中获取账号
final String accountPassword = accountLoginPassword.getText().toString().trim();//从控件中获取密码

if(TextUtils.isEmpty(accountName)){ showToast("账号不能为空"); return; } if (TextUtils.isEmpty(accountPassword)){ showToast("密码不能为空"); return; } //登录过程

// 展示加载中的圈圈
showProgressBar();

new Handler().postDelayed(new Runnable() { @Override public void run() { //BmobUSer类为Bmob后端云提供的类 BmobUser bmobUser = new BmobUser(); bmobUser.setUsername(accountName); bmobUser.setPassword(accountPassword); bmobUser.login(new SaveListener() { @Override public void done(BmobUser bmobUser, BmobException e){ if (e==null){ //登录成功后进入主页面 Intent intent =new Intent(LoginActivity.this,LostAndFoundActivity.class); startActivity(intent); finish(); }else { showToast(""+e.getMessage()); hiddenProgressBar(); //隐藏进度条 } } }); } },3000); }

Register.java

主要逻辑 填写数据 点击注册 关键代码

private void bmobRegisterAccount(){
final String registerName = accountRegisterName.getText().toString().trim(); //从控件中获取账号
final String registerPasswor = accountRegisterPassword.getText().toString().trim(); //从控件中获取密码

if (TextUtils.isEmpty(registerName)||TextUtils.isEmpty(registerPasswor)){ showToast("注册账号或密码为空"); return; } BmobUser bmobUser = new BmobUser(); //实例化对象 bmobUser.setUsername(registerName); //添加账号到数据库 bmobUser.setPassword(registerPasswor); //添加密码到数据库 bmobUser.signUp(new SaveListener() { @Override public void done(BmobUser bmobUser, BmobException e){ if (e==null){ showToast("注册账号成功"); finish(); }else { showToast("register fail:" + e.getMessage()); } } }); }

当然有查重代码

private void registerAccount(){
final String registerName = accountRegisterName.getText().toString().trim(); //获取账号
final String registerPassword = accountRegisterPassword.getText().toString().trim(); //获取密码

//为空判断 if (TextUtils.isEmpty(registerName) || TextUtils.isEmpty(registerPassword)) { showToast("注册账号或密码为空"); return; } //账号查询 防止重复注册 BmobQuery registerUserBmobQuery = new BmobQuery(); registerUserBmobQuery.order("-createdAt"); //数据库操作 按时间排序 registerUserBmobQuery.findObjects(new FindListener() { @Override public void done(List lists, BmobException e) { for (RegisterUser list : lists){ if (registerName.equals(list.getRegisterName())){ showToast("账号已被注册,请重新注册"); }else{ registerAccount(registerName, registerPassword); } } } }); }

浏览页面LostAndFound.java

这个页面是展示别的用户或自己发布的失物招领帖子 主要操作:

加载页面将内(条目)放在Recycleview的适配器里

private void initData(){
BmobQuerylostInfomationReqBmobQuery = new BmobQuery();
lostInfomationReqBmobQuery.order("-updateAt"); //排序
lostInfomationReqBmobQuery.findObjects(new FindListener() {
@Override
public void done(List list, BmobException e) {
if (e== null){
lostInfomationReqList = list;
lostAndFoundAdapter.setData(list);
recyclerView.setAdapter(lostAndFoundAdapter);
}else {
showToast(“查询数据失败”);
}
}
});
}
刷新页面

//监测页面刷新
@Override
protected void onActivityResult(int requestCode,int resultCode,Intent data){
switch (requestCode){
case REQUEST_CODE:
if (resultCode == RESULT_OK){
refreshData(); //数据刷新
}
break;
default:
break;
}
}

/* * 查询数据库中的最新数据 * * */ private void refreshData(){ BmobQuery lostInfomationReqBmobQuery = new BmobQuery(); lostInfomationReqBmobQuery.order("-updatedAt");//按更新时间排序 lostInfomationReqBmobQuery.findObjects(new FindListener() { @Override public void done(List list, BmobException e) { if (e == null) { lostInfomationReqList = list; lostAndFoundAdapter.setData(list); lostAndFoundAdapter.notifyDataSetChanged(); } } }); }

长按内容(条目)可以选择和删除或编辑

@Override
public void onEditOrDeleteClick(int position, int code){
if (code == LostAndFoundAdapter.EDIT_CODE){
/带参页面跳转/
Intent intent = new Intent(LostAndFoundActivity.this, AddLostInformationActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable(“editData”, lostInfomationReqList.get(position));
intent.putExtras(bundle);
startActivityForResult(intent, REQUEST_CODE);
} else if (code == LostAndFoundAdapter.DELETE_CODE) {
deleteItemData(position);
}
}

private void deleteItemData(final int position){ if (lostInfomationReqList.size()!=0){ LostInfomationReq lostInfomationReq =new LostInfomationReq(); lostInfomationReq.setObjectId(lostInfomationReqList.get(position).getObjectId()); lostInfomationReq.delete(new UpdateListener() { @Override public void done(BmobException e) { if (e==null){ lostInfomationReqList.remove(position); lostAndFoundAdapter.setData(lostInfomationReqList); lostAndFoundAdapter.notifyDataSetChanged(); }else { showToast("数据删除失败"); } } }); } }

点击右上角的加号图片跳转到发布(AddLostAndFound)页面

public void onClick(View v){
switch (v.getId()){
case R.id.iv_add:
Intent intent =new Intent(LostAndFoundActivity.this,AddLostInformationActivity.class);
startActivityForResult(intent,REQUEST_CODE);
break;
default:
break;
}
}
点击返回弹出“再按一次退出应用”

@Override
public boolean onKeyDown(int keyCode, KeyEvent event){
if(keyCode == KeyEvent.KEYCODE_BACK){
if (System.currentTimeMillis() - exitTime>2000){
showToast(“再按一次退出程序”);
exitTime = System.currentTimeMillis();
}else {
android.os.Process.killProcess(android.os.Process.myPid());
}
}
return false;
}
AddLostAndFound.java

由于长按也会跳转到此,所以需要判断是编辑(更新)还是新发布(添加) 更新

private void updataInfo(String titleName,String num,String descidle){
LostInfomationReq lostInfomationReq = new LostInfomationReq();
lostInfomationReq.setTitle(titleName); //titleName 为用户输入的标题
lostInfomationReq.setPhoneNum(num);
lostInfomationReq.setDesc(descidle);
lostInfomationReq.update(infomationReq.getObjectId(), new UpdateListener() {
@Override
public void done(BmobException e) {
if (e== null){
showToast(“更新信息成功”);
//更新数据后提示主界面进行数据刷新
Intent intent = new Intent();
setResult(RESULT_OK,intent);
finish();
}
}
});
}
添加数据

private void publishLostInfo(String titleName,String num,String descridle){
LostInfomationReq lostInfomationReq = new LostInfomationReq();
lostInfomationReq.setTitle(titleName);//titleName为用户输入的标题
lostInfomationReq.setPhoneNum(num);//num为用户输入的号码
lostInfomationReq.setDesc(descridle);//descridle为信息描述
lostInfomationReq.save(new SaveListener() {
@Override
public void done(String s, BmobException e) {
if (e==null){
showToast(“招领信息发布成功”);
//成功后提示主界面刷新数据
Intent intent =new Intent();
setResult(RESULT_OK,intent);
//成功后将页面销毁
finish();
}else {
showToast(“信息发布失败”);
}
}
});
}
四、编写适配器(Adapter)

适配器就好像是这个布局里的容器,它需要适配多种可能的item(条目),而这个条目是可以图文混合的,排列方式也是多种多样,所以需要Adapter去适配(封装)。 代码如下 有时间可以去好好研究,很有趣

public class LostAndFoundAdapter extends RecyclerView.Adapter {
private Context mContext;
private ListlostInfosData;
private ItemClickListener mItemClickListener;
public final static int EDIT_CODE = 998;
public final static int DELETE_CODE = 997;

public LostAndFoundAdapter(Context context){ this.mContext=context; } public void setData(List data){ this.lostInfosData=data; } /*创建recycleview*/ @Override public LostAndFoundHolder onCreateViewHolder( ViewGroup parent, int viewType) { /*传入内容页面 itme.xml*/ View view = LayoutInflater.from(mContext).inflate(R.layout.lost_itme,parent,false); LostAndFoundHolder lostAndFoundHolder = new LostAndFoundHolder(view); return lostAndFoundHolder; } /*传入数据*/ @Override public void onBindViewHolder(@NonNull final LostAndFoundAdapter.LostAndFoundHolder holder, final int position) {

// 绑定数据
if (lostInfosData!=null){
LostInfomationReq lostInfomationReq = lostInfosData.get(position);
holder.title.setText(lostInfomationReq.getTitle());
holder.desc.setText(lostInfomationReq.getDesc());
holder.phoneNum.setText(lostInfomationReq.getPhoneNum());
holder.time.setText(lostInfomationReq.getCreatedAt());

holder.IIitem.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) {

// mLongClickListener.onLongClick(position);
showWindow(holder,position);
return false;
}
});
}
}

//长按后方法 显示 private void showWindow(LostAndFoundHolder holder,final int pos){ //加载布局文件 View contenview = LayoutInflater.from(mContext).inflate(R.layout.pop_window_view,null); final PopupWindow popupWindow = new PopupWindow(contenview,LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT); //设置焦点 popupWindow.setFocusable(true); //触摸框外 popupWindow.setOutsideTouchable(true); //点击空白处的时候让PopupWindow消失 popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000)); //设置出现时候的偏移量 popupWindow.showAsDropDown(holder.time,300,-100); //showAsDropDown(View anchor):相对某个控件的位置(正左下方),无偏移 // showAsDropDown(View anchor, int xoff, int yoff):相对某个控件的位置,有偏移 //showAtLocation(View parent, int gravity, int x, int y):相对于父控件的位置(例如正中央Gravity.CENTER,下方Gravity.BOTTOM等),可以设置偏移或无偏移 //点击编辑按钮 contenview.findViewById(R.id.edit_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //回调给主界面,进行数据操作 mItemClickListener.onEditOrDeleteClick(pos,EDIT_CODE); //销毁弹出框 popupWindow.dismiss(); } }); //点击删除按钮 contenview.findViewById(R.id.delete_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //回调给主界面,进行数据操作 mItemClickListener.onEditOrDeleteClick(pos,DELETE_CODE); //销毁弹出框 popupWindow.dismiss(); } }); } /*计数 看看创建了几个 item*/ @Override public int getItemCount() { return lostInfosData.size()==0?0:lostInfosData.size(); } /*绑定条目页面的控件 (子控件)*/ public class LostAndFoundHolder extends RecyclerView.ViewHolder{ private TextView title; private TextView desc; private TextView time; private TextView phoneNum; private LinearLayout IIitem; public LostAndFoundHolder(View itemView){ super(itemView); title =(TextView)itemView.findViewById(R.id.tv_title); desc = (TextView) itemView.findViewById(R.id.tv_desc); time = (TextView) itemView.findViewById(R.id.tv_time); phoneNum = (TextView) itemView.findViewById(R.id.tv_num); IIitem = (LinearLayout) itemView.findViewById(R.id.II_item); } } /* * 设置长按事件 * */ public void setLongClickListener(ItemClickListener clickListener){ this.mItemClickListener = clickListener; } public interface ItemClickListener{ void onEditOrDeleteClick(int position,int code); }

}
完整代码在这 链接:https://pan.baidu.com/s/1gh8c4JAGvNezaTBS3jsh1A 提取码:9odr 复制这段内容后打开百度网盘手机App,操作更方便哦


作者:泳江



app bmob

需要 登录 后方可回复, 如果你还没有账号请 注册新账号