手把手带你撸一个校园APP(六):失物招领&二手交易模块

代码经过简单的整理,已经放到Github上了。https://github.com/zhengweichao/Hevttc
回首来看,代码质量一般,里面也有各种逻辑问题,还望各位看官海涵。接下来有时间的话,会逐步进行优化。如果对你有帮助,还望可以给个star,不胜感激。

前言

在校园生活中,存在着各种各样的信息差。也正因为这些信息差的存在,经常让校园同学们面临各种各样的问题。比如丢东西的找不到东西,捡到东西的找不到失主等等。其中最为突出的莫过于 【失物招领】及【二手交易】了。
校园作为一个比较特殊的地点,大家的素质以及诚信度普遍高于其它地方。“科师有约” 校园APP致力于减少校园信息差的存在,让校园生活更简单。

科师有约 只是一个美好的想法,并将部分功能从技术上进行简单实现。在实际生活中并未推广开来使用,在此权当抛砖引玉之用。还是希望学弟学妹们可以做出真正的产品,并在校园生活中得以应用。

本项目基于Bmob进行开发,很多地方需要Bmob相关知识。大家如果没了解过的话,可先自行查看 Bmob开发文档

系列文章:

Github地址: 科师有约校园APP

  1. 手把手带你撸一个校园APP(一):项目简介
  2. 手把手带你撸一个校园APP(二):应用启动和欢迎页面
  3. 手把手带你撸一个校园APP(三):用户模块(登录注册等)
  4. 手把手带你撸一个校园APP(四):APP框架及功能设计
  5. 手把手带你撸一个校园APP(五):新闻页面中心模块
  6. 手把手带你撸一个校园APP(六):失物招领&二手交易模块
  7. 手把手带你撸一个校园APP(七):图说校园模块
  8. 手把手带你撸一个校园APP(八):校园通讯录模块
  9. 手把手带你撸一个校园APP(九):课程表模块(模拟登陆爬取教务处课程信息)
  10. 手把手带你撸一个校园APP(十):APP通用模块(更新,意见反馈等)

实现效果

【失物招领】:
分为 寻物启事(找东西的)+ 失物招领(找失主的)
【二手交易】:
分为 淘点宝贝(想买东西的)+ 换点银子(想卖东西的)。效果图与失物招领类似

在这里插入图片描述

分析

失物招领与二手交易,两个模块从整体逻辑上来说基本一致。因为我们只做简易实现,所以就两个模块就不再区分讲解(下简称 “需求” )。
(当然,这里还可以做很多很多优化,本文后面【未来可做的优化】部分会进一步讲解)
需要实现功能如下:

  1. 发布需求(含 图片压缩及上传)
  2. 需求列表展示
  3. 需求详情展示
  4. 沟通联系(简化为 拨打电话)

其中需求列表的展示页面,与 新闻中心模块 使用的技术代码基本相同。想了解的可以再退回去看 上篇文章

数据库设计

(因两模块基本逻辑相似,仅就失物招领模块开讲)
为了使数据区分的更清楚,设计数据库时,将 “失物招领” 与 “寻物启事” 分别设置为两个表。其中的字段名称设计等均相同。字段如下:

字段名 描述 类型 是否主键
objectId 事件id号 String
title 事件标题 String -
tel 联系方式 Number -
author 发布人 String -
content 事件详细描述 String -
isOver 事件处理状态 Boolean -
createdAt 事件发布时间 Date -

(大家也可以设置为一个表,其中另外加一个字段进行区分)

安卓实现

发布需求

此处应用的技术都比较简单。发布需求 其实就是简单的数据库的增加操作。带图片的需求需要再做一下进一步的处理(图片压缩以及上传)

发布无图片的需求

LoseItem bean = new LoseItem();
MyUser user = BmobUser.getCurrentUser(MyUser.class);
bean.setAuthor(user.getUsername());
bean.setContent(loseDesc);
bean.setTel(loseTel);
bean.setTitle(loseTitle);
bean.save(new SaveListener<String>() {
    @Override
    public void done(String objectId, BmobException e) {
        if (e == null) {
            ToastUtil.show(LoseAddActivity.this, "发布成功", Toast.LENGTH_SHORT);
            LoadDialog.dismiss(LoseAddActivity.this);
            startActivity(new Intent(LoseAddActivity.this, LoseActivity.class));
            finish();
        } else {
            ToastUtil.show(LoseAddActivity.this, "发布失败,请稍后再试", Toast.LENGTH_SHORT);
            LoadDialog.dismiss(LoseAddActivity.this);
        }
    }
});

发布有图片的需求

现在手机像素一般都很高,所以一个图片好几MB 的情况也很常见。直接上传的话,会极大浪费用户流量以及文件存储空间。所以需要对图片进行压缩处理后再上传。
所以发布有图片的需求需要拆分为以下 4 步来进行。

1. 选择图片
选择图片部分使用了 廖子尧 大神的 imagepicker 库。完全仿微信UI,实现了拍照、图片选择(单选/多选)、 裁剪 、旋转 等功能。

Github : imagepicker
作者:廖子尧 jeasonlzy

大神的文档写的十分详尽,集成方法我就不再赘述了。核心代码如下:

// 设置 图片选择器 相应参数
ImagePicker imagePicker = ImagePicker.getInstance();
imagePicker.setImageLoader(new GlideImageLoader());   //设置图片加载器
imagePicker.setShowCamera(true);                      //显示拍照按钮
imagePicker.setCrop(true);                           //允许裁剪(单选才有效)
imagePicker.setSaveRectangle(true);                   //是否按矩形区域保存
imagePicker.setSelectLimit(maxImgCount);              //选中数量限制
imagePicker.setStyle(CropImageView.Style.RECTANGLE);  //裁剪框的形状
imagePicker.setFocusWidth(800);                       //裁剪框的宽度。单位像素(圆形自动取宽高最小值)
imagePicker.setFocusHeight(800);                      //裁剪框的高度。单位像素(圆形自动取宽高最小值)
imagePicker.setOutPutX(1000);                         //保存文件的宽度。单位像素
imagePicker.setOutPutY(1000);                         //保存文件的高度。单位像素

// ...省略其它代码

// 开始选择图片
List<String> names = new ArrayList<>();
names.add("拍照");
names.add("相册");
showDialog(new SelectDialog.SelectDialogListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        switch (position) {
            case 0:
                // 直接调起相机
                ImagePicker.getInstance().setSelectLimit(maxImgCount - selImageList.size());
                Intent intent = new Intent(LoseAddActivity.this, ImageGridActivity.class);
                intent.putExtra(ImageGridActivity.EXTRAS_TAKE_PICKERS, true); // 是否是直接打开相机
                startActivityForResult(intent, REQUEST_CODE_SELECT);
                break;
            case 1:
                //打开选择,本次允许选择的数量
                ImagePicker.getInstance().setSelectLimit(maxImgCount - selImageList.size());
                Intent intent1 = new Intent(LoseAddActivity.this, ImageGridActivity.class);
                intent1.putExtra(ImageGridActivity.EXTRAS_IMAGES, images);
                startActivityForResult(intent1, REQUEST_CODE_SELECT);
                break;
        }
    }
}, names);

2. 图片压缩
图片压缩部分采用了 Luban(鲁班) —— Android图片压缩工具,仿微信朋友圈压缩策略。
作者采用逆向推算,效果已经很接近微信朋友圈压缩后的效果。
(再次踩在了巨人的肩膀上……)

Github : Luban(鲁班)
作者: Curzibn

核心代码如下:

Luban.with(LoseAddActivity.this)
     .load(paths)                                   // 传入要压缩的图片列表
     .ignoreBy(100)                                  // 忽略不压缩图片的大小
     .setTargetDir(getPath())                        // 设置压缩后文件存储位置
     .setCompressListener(new OnCompressListener() { //设置回调
         @Override
         public void onStart() {
             // 开始压缩 ...
         }
         @Override
         public void onSuccess(File file) {
             // 压缩成功 ...
         }
         @Override
         public void onError(Throwable e) {
             // 当压缩过程出现问题时调用
         }
      }).launch();    //启动压缩

3. 图片上传
这里是按照Bmob官方代码来写的。详情可见 Bmob文件管理

BmobFile.uploadBatch(filePaths, new UploadBatchListener() {
    @Override
    public void onSuccess(List<BmobFile> files, List<String> urls) {
        // 上传图片成功
        //1、files-上传完成后的BmobFile集合,是为了方便大家对其上传后的数据进行操作,例如你可以将该文件保存到表中
        //2、urls-上传文件的完整url地址
    }

    @Override
    public void onError(int statuscode, String errormsg) {
        // 上传图片失败
        LoadDialog.dismiss(LoseAddActivity.this);
    }

    @Override
    public void onProgress(int curIndex, int curPercent, int total, int totalPercent) {
    }
});

需要注意的是 上传多张图片,onSuccess 会多次调用 。别忘了做相应处理。

4. 发布需求
和发布无图片需求代码基本一致,只不过多了一句设置图片的代码。

LoseItem bean = new LoseItem();
// ... 省略其它代码
bean.setPic(files.get(0));

bean.save(new SaveListener<String>() {
    @Override
    public void done(String objectId, BmobException e) {
        // ... 省略其它代码
    }
});

至此,失物招领 & 二手交易模块基本完成。

然而整个流程中还有很多可以优化的地方,作者大概率没有时间和精力去做这部分了。
特将这部分内容整理如下,若他人有类似需求,以望能有所启迪或帮助。

未来可做的优化

简而言之,就是 提升平台能力

因两个模块逻辑相似性较高,故此处以【失物招领】为例:
在一个完整的过程中,总共存在3方:丢东西的,捡东西的,平台。

本文上面已经讲解了最基础简易的沟通流程:

  1. 丢东西的 在平台发布 寻物启事;捡东西的看见 --> 私下联系;
  2. 捡东西的 在平台发布 失物招领;丢东西的看见 --> 私下联系;

这种方式固然简单粗暴,但是显得不太灵活。
身为平台,应该发挥出平台更大的能力。那么应该从哪里开始入手呢?

校园是一个很特殊的地方,这里的失物招领有许多特殊之处,总结一下不难发现:

  1. 用户群体(学生,教职工,家属楼住户)绝大多数都接受过高等教育,文化素质较高,认知较为统一; ==> 【其它用户捡到后,有较大概率归还】
  2. 用户活动范围较为一致,活动区域较为封闭; ==>【用户丢失物品,较大概率被其它校园用户捡到】
  3. 用户捡到或丢失的物品有较高重复性(校园卡,身份证,课本); ==> 【物品上一般带有 失主信息,可以通过实名信息直接锁定失主】
  4. 根据院系,专业,班级等,很容易找到相关实名用户。 ==> 【根据附属信息,很容易找到某人或其朋友同学】
  5. 有很多人捡到东西后,会交给专门的组织或个人(失物招领协会,门卫,校园卡服务中心等)。 ==> 【可以集中起来这些地方的信息,统一处理】

综上所述,未来如果有学弟学妹想做这部分,按个人看法,可做的优化如下:

  1. 加强用户实名认证操作,仅限实名认证用户使用APP。
  2. 定期收集整理线下失物招领信息,录入线上系统。
  3. 线上系统运用实名信息匹配失主并通过推送私信等方式进行联系(保证用户隐私的前提下进行)。
  4. 对线上信息进行匹配以及相似内容匹配操作,以优化处理双方都发布了信息的情况。

至此,本文内容全部完毕,项目中大量依赖或采用了第三方项目的代码。在此向各位有分享精神的大佬们致敬!

如果本文对你有所帮助,还望可以随手赏一个点赞哈 ~ ~

发布了71 篇原创文章 · 获赞 197 · 访问量 32万+

猜你喜欢

转载自blog.csdn.net/zheng_weichao/article/details/104245390