天盾app项目总结


经过几个星期的努力,天盾app2.0版正式发布。再次记录下自己在开发中遇到的问题:

  1. 拍照图片oom
  2. listview 图片错位
  3. xutils 数据库的使用与升级

1. 拍照显示图片oom

由于该app中有快递单的采集,用RecyclerView 展示,并且每条可能需要拍照录入三张图片,这些图片需要显示并保存到文件便于上传。
目前,各个各个手机拍照后生成的图片比较大,分辨率也很高,直接显示很容易出现oom,使用BitmapFactory创建bitmap显示图片,每次使用都会分配内存,通过设置它的采样率,以避免。通过使用下面的工具类来加载图片:

public class BitmapUtil {
private static final boolean DEBUG = false;
private static final String TAG = BitmapUtil.class.getSimpleName();

private BitmapUtil() {
    throw new Error("Do not need instantiate!");
}

/**
 * 图片压缩处理(使用Options的方法)
 * <p/>
 * @param reqWidth  目标宽度
 * @param reqHeight 目标高度
 */
public static BitmapFactory.Options calculateInSampleSize(
        final BitmapFactory.Options options, final int reqWidth,
        final int reqHeight) {
    // 源图片的高度和宽度
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > 400 || width > 450) {
        if (height > reqHeight || width > reqWidth) {
            // 计算出实际宽高和目标宽高的比率
            final int heightRatio = Math.round((float) height
                    / (float) reqHeight);
            final int widthRatio = Math.round((float) width
                    / (float) reqWidth);
            // 选择宽和高中最小的比率作为inSampleSize的值,这样可以保证最终图片的宽和高
            // 一定都会大于等于目标的宽和高。
            inSampleSize = heightRatio < widthRatio ? heightRatio
                    : widthRatio;
        }
    }
    // 设置压缩比例
    options.inSampleSize = inSampleSize;
    options.inJustDecodeBounds = false;
    return options;
}



/**
 * 获取一个指定大小的bitmap
 *
 * @param reqWidth  目标宽度
 * @param reqHeight 目标高度
 */
public static Bitmap getBitmapFromFile(String pathName, int reqWidth,
                                       int reqHeight) {
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(pathName, options);
    options = calculateInSampleSize(options, reqWidth, reqHeight);
    return BitmapFactory.decodeFile(pathName, options);
}
}

这里只列出了计算采样率和从文件中加载显示的方法,如需了解更多该工具,请点击此处查看
具体使用如下:

int width = mImageView.getWidth();
int height = mImageView.getHeight();
//picPath 为图片存储路径
mImageView.setImageBitmap(BitmapUtil.getBitmapFromFile(picPath, width, height));

进过测试,连续拍照10多张并显示,内存的消耗物明显变化,大约有2M的多动,测试手机为Nexus 6,至此,oom完美解决,性能也十分好。

2. Listview 加载网络图片错位

在app登陆前,需要选择相应的快递和分部,而快递列表的设计是显示快递图片和快递公司名称,该部分数据是由网络获取的,展示在listView中。当图片地址为空时,无图片的item就会显示其他的图片,而且随着屏幕的滚动而变化,出现错位的现象。这种情况主要是由于ListView适配器 中getView的convertView复用导致的,解决办法是为imageview设置tag标记,这里以图片的url作为标记。如下,getView的代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    if (convertView == null) {
        convertView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item_express, parent, false);
        holder = new ViewHolder(convertView);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    String imgUrl = mDatas.get(position).getExpressIco();
    holder.imgExpressIcon.setTag(imgUrl);

    //这里注意图片地址的判断,被 "" 坑了好久
    if (holder.imgExpressIcon.getTag() == null || holder.imgExpressIcon.getTag().equals("")) {
        //若无网络图片,显示错误图片
        holder.imgExpressIcon.setImageResource(R.drawable.express_error);
    } else if (holder.imgExpressIcon.getTag().equals(imgUrl)) {
        x.image().bind(holder.imgExpressIcon, Constants.BASE_URL + imgUrl);
    }
    holder.tvExpressName.setText(mDatas.get(position).getExpressName());

    return convertView;
}

3. xutils3 数据库的使用与升级

为了节省流量,将采集的数据保存在本地,便于在wifi情况下同一上传,只有该功能需要数据库,加上项目中使用的有xutils,带有数据库模块,便没有自己写或者使用 GreenDao,Ralem等其他的数据库框架。
此处简单的记录下改数据库框架的使用。

  • 在Application中配置
    在自己的application类(或者使用的activity)中添加配置信息,这里为了方便,在Application类中添加,并通过单利类访问使用。
    如下部分代码:

    public class SNApplication extends Application {
    
      private static DbManager.DaoConfig mDaoConfig = null;
    
      /**
       * 获取数据库配置对象
       *
       * @return
       */
      public static DbManager.DaoConfig getDaoConfig() {
          if (mDaoConfig == null) {
              mDaoConfig = new DbManager.DaoConfig()
                      .setDbName("ygjexpress.db")
                      .setDbVersion(2)
                      .setDbOpenListener(new DbManager.DbOpenListener() {
                          @Override
                          public void onDbOpened(DbManager db) {
                              // 开启WAL, 提升写入速度
                              db.getDatabase().enableWriteAheadLogging();
                          }
                      })
                      .setDbUpgradeListener(new DbManager.DbUpgradeListener() {
                          @Override
                          public void onUpgrade(DbManager db, int oldVersion, int newVersion) {
                              //升级数据库
                              try {
                                  //添加 user_id ,避免同一手机登陆多个账号出现数据混乱
                                  db.addColumn(PickupDbItem.class,"user_id");
                              } catch (DbException e) {
                                  e.printStackTrace();
                              }
                          }
                      });
    
          }
          return mDaoConfig;
      }
    }
    
  • 创建数据表对应的实体类
    通过注解,来指定数据表名(Table)和字段名(Column),isId 指定是否为id,property设置是否唯一。

    @Table(name = "pickup_item")
    public class PickupDbItem {
      @Column(name = "id", isId = true)
      private int id;
      @Column(name = "sender_idcrad_id")
      private String senderIdcradID;//身份证id
      @Column(name = "express_no")
      private String expressNo;//快递编号
      @Column(name = "pic_bale_before")
      private String picBaleBefore;//打包前
      @Column(name = "pic_bale_after")
      private String picBaleAfter;//打包后图片
      @Column(name = "pic_bale_complete")
      private String picBaleComplete;//贴快递单后图片
    
      @Column(name = "user_id")
      private String userId; //当前登录的用户id
    
     //此处省略构造方法和getter和setter方法
    
  • 具体的使用

    //获取数据库配置
    private static DbManager mDbManager = x.getDb(SNApplication.getDaoConfig());
    //插入一条
    mDbManager.save(pickupDbItem);
    //查找-条
    pickupDbItem = mDbManager.selector(PickupDbItem.class)
                          .where("express_no", "=", expressNo)
                          .findFirst();
    //查找所有
    mDbManager.selector(PickupDbItem.class).findAll();
    //更新三个字段
    mDbManager.update(pickupDbItem, "sender_idcrad_id", "pic_bale_before", "pic_bale_after", "pic_bale_complete");
    //删除
    mDbManager.delete(pickupDbItem);
    

    用法很简单,负责的查询条件可以使用WhereBuilder类来构造。更多的请参见此处

  • 数据库的升级

在配置文件中增加版本号,在 setDbUpgradeListener 中的 onUpgrade 方法中添加或删除列,最后在实体中添加相应的字段即可

项目比较小,遇到的问题也就这些,需要查看该app的,请访问内测平台


文章作者: imtianx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 imtianx !
评论
 上一篇
【转】国内一线互联网公司内部面试题库(一)——java篇 【转】国内一线互联网公司内部面试题库(一)——java篇
本文转自:国内一线互联网公司内部面试题库国内一线互联网公司内部面试题库,以下面试题来自于百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐内部题库 熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。下面是java 部分 1.接口
2016-11-05
下一篇 
android studio 生成aar和jar android studio 生成aar和jar
1. aar包aar包是android studio 下打包android 工程中的src、res、lib后生成的aar文件,以便导入到其他的as工程中使用。在as中它的生成方式较为简单,主要步骤如下: 1.新建model,选择 andr
  目录