用AVOS Cloud加速移动开发,地图.save()即可把键值对保存到服务器上

用AVOS Cloud加速移动开发,map.save()即可把键值对保存到服务器上

AVOS Cloud是干啥的呢?提供paas(Platform as a Service)服务的云。也就是提供一些接口,像map一样保存数据,但这个map还有个save方法。

AVObject obj=new AVObject("Blogger");

obj.put("name","lzwjava");

obj.save();

于是在服务端可以看见:

用AVOS Cloud加速移动开发,地图.save()即可把键值对保存到服务器上


当然还有其它增删改查操作,推送,数据分析,社交登录,事件流系统(微博,好友关系)。

工具是相当方便迅捷的,我唯一担心的就是用多了这么方便的工具,不利于自己的技术积累……


如何定义AVObject子类呢?这样做的好处是用上IDE的智能提示、类型检查。

1)定义一个类,extends AVObject,加上注释,且保证有一个空构造器方法。

@AVClassName("FilmItem")
public class FilmItem extends AVObject{
  public static final String NAME = "name";
  public FilmItem(){
  }
  public String getName(){
    return getString(NAME);
  }
  public void setName(String name){
    put(NAME,name);
  }
}


2)在Application类中,注册一下。

AVObject.registerSubclass(FilmItem.class);

如何方便简单地用呢?

建议查找、判断存在等操作的时候返回一个子类对象,

  public static VideoItem avGetVideoItem(int id) throws AVException {
    AVQuery<VideoItem> q=AVObject.getQuery(VideoItem.class);
    q.whereEqualTo(VideoItem.VIDEO_ID,id);
    q.setLimit(1);
    VideoItem item=null;
    List<VideoItem> items = q.find();
    if(items!=null && items.isEmpty()==false){
      item=items.get(0);
    }
    return item;
  }

像这个,根据id来找到一个VideoItem,之后便用子类中定义的方法来使用即可,

判断是否为空:

    item=avGetVideoItem(id);

    if(item!=null){

    }else{

    }

得到某个字段值

   item.getName();

也可以,

   item.getString("name");


就是一些键值对,像map,只不过还有save,delete等等方法,save一下保存到服务器上。

item.putName("suck");

item.save();

在服务器上看到的是数据库一样的表格:

用AVOS Cloud加速移动开发,地图.save()即可把键值对保存到服务器上

注意这个save方法是要网络连接的,阻塞线程的。得另开一个线程。

可用

item.saveInBackgroud();

让其在后台线程,有相应的一个回调接口,可以处理save完之后的事情。


特别注意的是不建议请求某一个对象的时候,只用到一个字段值,就把其丢弃掉,

  public static String avGetGetVideoName(String word) throws AVException {
    AVQuery<VideoItem> query = getQuery(VideoItem.class);
    query.whereEqualTo(WORD, word);
    query.setLimit(1);
    List<VideoItem> items = query.find();
    VideoItem item = items.get(0);
    return item.getVideoName();
  }
像这个,一个单词对应一个短视频,根据单词来找某个VideoItem,找到后,

返回item.getVideoName();

这样返回的一大串键值对只用了其中一个。

可以用数据库把相应的值保存起来:

db.execSQL("insert into video_item (id,film_id,word,video_url," +
        "film_en_name,word_type,like_count,showAt,videoName) " +
        "values(?,?,?,?,?,?,?,?,?) ", new String[]{"" + item.getVideoId(), ""
        + item.getFilmId(),item.getWord(), videoUrl,
        item.getFilmEnName(), item.getWordType(),item.getLikeCount() + "",
        dateStr,videoName});

或者在前面的query中加上缓存策略,

query.setCachePolicy(AVQuery.CachePolicy.CACHE_ELSE_NETWORK);


加载部分数据:

  public List<Integer> getTypedWordIdIn(int startIndex,
                                        int endIndex, String orderBy, String[] types) {
    AVQuery<VideoItem> query = getQueryOfTypes(types);
    int n = endIndex - startIndex + 1;
    query.whereLessThanOrEqualTo(VideoItem.SHOW_AT, new Date());
    query.setLimit(n);
    query.setSkip(startIndex);
    query.orderByDescending(orderBy);
    SQLiteDatabase db = getWritableDatabase();
    List<Integer> ids = new ArrayList<Integer>();
    try {
      List<VideoItem> items = query.find();
      for(VideoItem item:items){
        ids.add(item.getVideoId());
      }
      int succN=insertVideos(db, items);
    } catch (AVException e) {
      e.printStackTrace();
    }
    return ids;
  }

  private static AVQuery<VideoItem> getQueryOfTypes(String... types) {
    List<AVQuery<VideoItem>> qs = new ArrayList<AVQuery<VideoItem>>();
    for (int i = 0; i < types.length; i++) {
      AVQuery<VideoItem> q = AVQuery.getQuery(VideoItem.class);
      q.whereContains("wordType", types[i]);
      qs.add(q);
    }
    return AVQuery.or(qs);
  }

用AVOS Cloud加速移动开发,地图.save()即可把键值对保存到服务器上

首先,对单词进行了分类,四级、六级、高考的,现在要显示某一类的或者全部类的单词,为了统一,构造了复合查询,查找所有类别的单词的时候,不是去查找所有单词,而是去查找含有这个类别名称、那个类别等所有类别的单词。

这其实很不好,把类别的名称放在某个字段里,该对象是那个类别的话,它的某个字段的就含有类别名称。

不好在于:一来,无法用上索引,索引先排好序,但这contains用不上排好的顺序,无法用二分来快速定位。contains用来判断字符串包含关系。是要判断很多次的。

像这个"cet4,cet6,gaokao,gre,ielts",判断是否contains "ielts",从前面往后面的要判断10来20次。

而如果保存为数组的话,即[cet4,cet6,gaokao,gre,ielts],只用判断5次。

AVOS支持数组。是我刚出茅庐,糗大了。


分页展示的核心主要是:

    query.setLimit(n);
    query.setSkip(startIndex);
    query.orderByDescending(orderBy);
首先要有某种排序,AVOS的默认排序是数据的更新时间的逆序,即最近更新在前面,所以要定制我们自己的分页排序。这样调用

        int startIndex = page * pageSize;
        int endIndex = startIndex + pageSize - 1;
        int askSize = endIndex - startIndex + 1;
        String type=getWordType();
        List<Integer> ids;
        ids=DBHelper.sqlGetTypedWordIdIn(dbHelper,startIndex,endIndex,
            DBHelper.ID,new String[]{type});
        if(size<askSize){
        }

最后一句,if(size<askSize)表明返回的条数少于请求的条数,于是可以显示“没有更多”的消息了。


一些例子:

点赞的统计功能:

  public static void incrementLikeCount(List<Integer> ids, int delta) throws AVException {
    if(ids.size()==0){
      return;
    }
    List<AVObject> items = avGetVideoItems(ids);
    for(AVObject item :items){
      item.increment(LIKE_COUNT,delta);
    }
    AVObject.saveAll(items);
  }

increment是AVOS已提供的方法。这样就可以为ids所代表的视频的LikeCount增加delta。


批量保存喜欢关系,两个字段,一个是用户名,另外一个是喜欢的视频id,

  public static void avInsertUserLike(List<Integer> ids) throws AVException {
    String username= AVUser.getCurrentUser().getUsername();
    List<AVObject> userLikes=new ArrayList<AVObject>();
    for(int id :ids){
      AVObject like=new AVObject(USER_LIKE);
      like.put(VIDEO_ID, id);
      like.put(USER_NAME, username);
      userLikes.add(like);
    }
    AVObject.saveAll(userLikes);
    VideoItem.incrementLikeCount(ids, 1);
  }

用户取消收藏了,删除喜欢关系:

  public static void  avDelUserLike(List<Integer> ids) throws AVException {
    List<AVObject> items = avGetUserLikes(ids);
    for(AVObject item :items){
      item.delete();
    }
    VideoItem.incrementLikeCount(ids, -1);
  }

AVOS的图片保存在七牛上,于是可以用七牛的接口获取缩略图或其它图片处理

 String logoUrl=item.getLogo().getUrl()+"?imageView2/2/w/"+ App.imgWidth;

 private void setImageWidth() {
    DisplayMetrics metrics=new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    App.imgWidth=metrics.widthPixels/3;
  }

在我的app中,分三栏展示图片,于是需要宽度为屏幕1/3的照片,

这样在图片的url后面加上 "?imageView2/2/w/"+ App.imgWidth

还可以旋转,各种截取操作的,见七牛文档。

音视频处理也可以,各种转换,截取帧。


登录:

    AVUser.logInInBackground(userNameStr, passwordStr, new LogInCallback() {
      public void done(AVUser user, AVException e) {
        dialog.dismiss();
        if (e == null) {
          // 登录成功
          loginSucceed();
        } else {
          // 登录失败
          toast(getString(R.string.fail_login_tips));
        }
      }
    });

注册:

    user.signUpInBackground(new SignUpCallback() {
      public void done(AVException e) {
        dialog.dismiss();
        if (e == null) {
          // successfully
          loginSucceed();
          finish();
        } else {
          toast(getString(R.string.have_been_registered));
        }
      }
    });