AVOS Cloud是干啥的呢?提供paas(Platform as a Service)服务的云。也就是提供一些接口,像map一样保存数据,但这个map还有个save方法。
AVObject obj=new AVObject("Blogger");
obj.put("name","lzwjava");
obj.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();
在服务器上看到的是数据库一样的表格:
注意这个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);
}
首先,对单词进行了分类,四级、六级、高考的,现在要显示某一类的或者全部类的单词,为了统一,构造了复合查询,查找所有类别的单词的时候,不是去查找所有单词,而是去查找含有这个类别名称、那个类别等所有类别的单词。
这其实很不好,把类别的名称放在某个字段里,该对象是那个类别的话,它的某个字段的就含有类别名称。
不好在于:一来,无法用上索引,索引先排好序,但这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));
}
}
});