失物招领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,操作更方便哦