Bmob 开发Android程序快速入门--小demo

时间:2024-02-25 21:56:53

注册Bmob帐号

在网址栏输入www.bmob.cn或者在百度输入Bmob进行搜索,打开Bmob官网后,点击右上角的“注册”,在跳转页面填入你的姓名、邮箱、设置密码,确认后到你的邮箱激活Bmob账户,你就可以用Bmob轻松开发应用了。

网站后台创建应用

登录账号进入bmob后台后,点击后台界面左上角“创建应用”,在弹出框输入你应用的名称,然后确认,你就拥有了一个等待开发的应用。

获取应用密钥和下载SDK

选择你要开发的应用,点击该应用下方对应的“应用密钥”

在跳转页面,获取Application ID,此ID将会在初始化SDK中使用到。

获取Application ID后,下载SDK,开发者可以根据自己的需求选择相应的iOS SDK 或Android SDK,点击下载即可。

安装BmobSDK

一、在你的项目根目录下创建"libs"目录,将下载的BmobSDK文件放入该目录下。

二、在你的应用程序中添加相应的权限:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="cn.bmob.example"
        android:versionCode="1"
        android:versionName="1.0">

    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/>

    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_LOGS"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name="cn.bmob.example.MainActivity"
            android:screenOrientation="portrait"
            android:label="@string/app_name">

                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>


        <activity
            android:name=".CreateActivity"
            android:screenOrientation="portrait">
        <activity
            android:name=".DeleteActivity"
            android:screenOrientation="portrait">
        <activity
            android:name=".UpdateActivity"
            android:screenOrientation="portrait">
        <activity
            android:name=".FindActivity"
            android:screenOrientation="portrait">
    </application>
</manifest>

初始化BmobSDK

在你应用程序启动的Activity的onCreate()方法中初始化Bmob功能。代码如下所示:

package com.bmob.example;
import cn.bmob.Bmob;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
         // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
         // 初始化 Bmob SDK
        // 使用时请将第二个参数Application ID替换成你在Bmob服务器端创建的Application ID
        Bmob.initialize(this, "Your Application ID");
    }
}



简介

Bmob平台为您的移动应用提供了一个完整的后端解决方案,我们提供轻量级的SDK开发包,让开发者以最小的配置和最简单的方式使用Bmob平台提供的服务,进而完全消除开发者编写服务器代码以及维护服务器的操作。

开源案例

Bmob致力于为开发者提供快速开发服务,为方便大家更好的理解Bmob SDK能够做的事情,我们特意为大家提供了一些源码,大家可以下载之后,嵌入Bmob的AppKey,再打包运行。

阅读源码是一种良好的习惯!!

即时聊天案例源码:https://github.com/bmob/BmobIMSDK4Android

图文社区案例源码:https://github.com/bmob/Wonderful2 这个案例是猿圈媛圈开发团队提供的。

校园小菜案例源码:https://github.com/bmob/Shop 这个案例是湖工大的朋友提供的。

社交分享案例源码:https://github.com/bmob/bmob-android-social-share 这个是金刚锁开发者提供的

第三方登录案例源码:https://github.com/bmob/bmob-android-demo-thirdpartylogin 包含第三方登录和登录后获取用户信息的源码

应用程序

在Bmob平台注册后,每个账户可创建多个应用程序,创建的每个应用程序都有其独自的应用程序ID,此后所有的应用程序将凭其ID进行Bmob SDK的使用。即使只有一个应用程序,也可以以不同的版本进行测试和生产。

应用安全

请大家在使用Bmob开发应用程序之前,认真阅读我们给大家提供的“数据与安全”的文档,确保你的应用在发布时安全。文档的链接地址是:http://docs.bmob.cn/datasafety/index.html?menukey=otherdoc&key=datasafety

数据类型

目前为止,我们支持的数据类型有String、Integer、Boolean、ArrayList以及BmobObject对象类型。同时Bmob也支持BmobDate、BmobGeoPoint、 BmobFile数据类型。

对象

一个对象对应了数据表中的一条数据,也可以理解为应用程序中的JavaBean.

数据对象

Bmob存储的数据是建立在BmobObject基础上的,所以任何要保存的数据对象必须继承自BmobObject类。BmobObject对象包含objectId、createdAt、updatedAt、ACL四个默认的属性,objectId为对象的唯一标示,可以理解为数据表中的主键,createdAt为对象的创建时间,updatedAt为对象的最后修改时间,ACL为这条数据的操作权限控制。例如,游戏中可能会用到的分数对象GameScore,它可能包含score、playerName、cheatMode等属性,那么这个数据对象创建的示例代码如下:

public class GameScore extends BmobObject{
    private String playerName;
    private Integer score;
    private Boolean cheatMode;
    private BmobFile pic;

    public String getPlayerName() {
        return playerName;
    }
    public void setPlayerName(String playerName) {
        this.playerName = playerName;
    }
    public Integer getScore() {
        return score;
    }
    public void setScore(Integer score) {
        this.score = score;
    }
    public Boolean getCheatMode() {
        return cheatMode;
    }
    public void setCheatMode(Boolean cheatMode) {
        this.cheatMode = cheatMode;
    }
        public BmobFile getPic() {
        return pic;
    }
    public void setPic(BmobFile pic) {
        this.pic = pic;
    }
}

类名和表名的关系

  • 默认情况下,Bmob提供了类名和表名完全一致的简单方式,实现类名和表名的映射。如,上面的GameScore类对应Web后台的表名是GameScore(区分大小写),如果创建一个数据对象名称为T_a_b,那么这个类名对应的Web后台的表名也是T_a_b。
  • 但很多时候,你希望在后台创建的表名和类名并不相同,如表名为T_a_b,而类名还是GameScore,那么你可以使用BmobObject提供的setTableName("表名")的方法,示例代码如下:
//这时候实际操作的表是T_a_b
public class GameScore extends BmobObject{
    private String playerName;
    private Integer score;
    private Boolean cheatMode;
    private BmobFile pic;

    public GameScore() {
        this.setTableName("T_a_b");
    }

    public String getPlayerName() {
        return playerName;
    }

    //其他方法,见上面的代码
}

当然了,你也可以在GameScore实例中动态调用setTableName方法,实现操作可变表(如根据日期建立表来存储信息)的可能。

查询自定义表名的数据

如果您使用了setTableName方法来自定义表名,那么在对该表进行数据查询的时候必须使用以下方法来进行查询。需要注意的是查询的结果是一个JSONArray,您需要自行解析JSONArray中的数据来进行使用。

/**
 * 查询数据
 */
public void queryData(){
    BmobQuery query = new BmobQuery("T_a_b");
    query.findObjects(this, new FindCallback() {

        @Override
        public void onSuccess(JSONArray arg0) {
            // TODO Auto-generated method stub
            showToast("查询成功:"+arg0.length());
        }

        @Override
        public void onFailure(int arg0, String arg1) {
            // TODO Auto-generated method stub
            showToast("查询失败:"+arg1);
        }
    });
}

自定义表名情况下的更新、删除数据和普通的更新、删除数据方式一样,没有变化。尽管如此,我们还是提供了一个关于自定义表名情况下增删改查数据的Demo供开发者朋友参照源码来学习,下载地址是:https://github.com/bmob/bmob-android-demo-dynamic-tablename

特殊对象

为了提供更好的服务,BmobSDK中提供了BmobUser、BmobInstallation两个特殊的BmobObject对象来完成不同的功能,在这里我们统一称为特殊对象。 BmobUser对象主要是针对应用中的用户功能而提供的,它对应着web端的User表,使用BmobUser对象可以很方便的在应用中实现用户的注册、登录、邮箱验证等功能,具体的使用方法可查看文档的用户部分。 BmobInstallation对象主要用于应用的安装设备管理中,它对应着web端的Installation表,任何安装了你应用的设备都会在此表中产生一条数据标示该设备。结合Bmob提供的推送功能,还可以实现将自定义的消息推送给不同的设备终端,具体的使用方法可查看文档的消息推送部分。

添加数据

添加数据非常简单,任何BmobObject对象都具有save方法可以用于将当前对象的内容保存到服务端。 例如,你现在要保存一条游戏分数的记录,可以这样做:

GameScore gameScore = new GameScore();
gameScore.setPlayerName("Barbie");
gameScore.setScore(89);
gameScore.setCheatMode(false);
gameScore.save(mContext, new SaveListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("添加数据成功,返回objectId为:"+gameScore.getObjectId());
    }

    @Override
    public void onFailure(int code, String arg0) {
        // TODO Auto-generated method stub
        // 添加失败
    }
});

运行完以上代码后,数据即可保存到服务器端。为了确认数据是否真的已经保存成功,你可以在Bmob服务器端你应用程序的数据浏览项目中进行查看。你应该看到类似这样的结果:

objectId: "0c6db13c", score: 89, playerName: "Barbie", cheatMode: false,createdAt:"2013-09-27 10:32:54", updatedAt:"2013-09-27 10:32:54"

注:

  1. 在运行以上代码时,如果服务器端你创建的应用程序中已经存在GameScore数据表和相应的score、playerName、cheatMode字段,那么你此时添加的数据和数据类型也应该和服务器端的表结构一致,否则将保存数据失败。

  2. 如果服务器端不存在GameScore数据表,那么Bmob将根据你第一次(也就是运行的以上代码)保存的GameSocre对象在服务器为你创建此数据表并插入相应数据。

  3. 每个BmobObject对象都有几个默认的键(数据列)是不需要开发者指定的,objectId是每个保存成功数据的唯一标识符。createdAtupdatedAt代表每个对象(每条数据)在服务器上创建和最后修改的时间。这些键(数据列)的创建和数据内容是由服务器端自主来完成的。因此,使用save和insert方法时,不需要调用setObjectId方法,否则会出现提示:“It is a reserved field: objectId(105)”--表明objectId为系统保留字段,不允许修改。

查询数据

数据的查询可能是每个应用都会频繁使用到的,BmobSDK中提供了BmobQuery类,它提供了多样的方法来实现不同条件的查询,同时它的使用也是非常的简单和方便的。

查询所有数据

查询某个数据表中的所有数据是非常简单的查询操作,例如:查询所有人员的信息。

BmobQuery<GameScore> query = new BmobQuery<GameScore>();
query.findObjects(this, new FindListener<GameScore>() {
        @Override
        public void onSuccess(List<GameScore> object) {
            // TODO Auto-generated method stub
            toast("查询成功:共"+object.size()+"条数据。");
        }
        @Override
        public void onError(int code, String msg) {
            // TODO Auto-generated method stub
            toast("查询失败:"+msg);
        }
});

怎么样,是不是很简单,而且查询的结果不需要进行任何处理,BmobSDK已经为你封装成相应的JavaBean集合了,你直接使用即可。

这里需要注意一点的是: 默认情况下,系统实际上并不会返回所有的数据,而是默认返回10条数据记录,你可以通过setLimit方法设置返回的记录数量。更多细节可点击查看分页查询一节。

查询单条数据

当我们知道某条数据的objectId时,就可以根据objectId直接获取单条数据对象。例如:查询objectId为a203eba875的人员信息。

BmobQuery<GameScore> query = new BmobQuery<GameScore>();
query.getObject(this, "a203eba875", new GetListener<GameScore>() {

    @Override
    public void onSuccess(GameScore object) {
        // TODO Auto-generated method stub
        toast("查询成功:");
    }

    @Override
    public void onFailure(int code, String arg0) {
        // TODO Auto-generated method stub
        toast("查询失败:"+arg0);
    }

});

条件查询

在查询的使用过程中,基于不同条件的查询是非常常见的,BmobQuery同样也支持不同条件的查询。

例如:如果要过滤掉特定键的值可以使用addWhereNotEqualTo方法。比如需要查询playerName不等于“Barbie”的数据时可以这样写:

query.addWhereNotEqualTo("playerName", "Barbie");

当然,你可以在你的查询操作中添加多个约束条件,来查询符合要求的数据。

query.addWhereNotEqualTo("playerName", "Barbie");     //名字不等于Barbie
query.addWhereGreaterThan("score", 60);      //条件:分数大于60岁

各种不同条件的比较查询:

// 分数 < 50
query.addWhereLessThan("score", 50);
//分数 <= 50
query.addWhereLessThanOrEqualTo("score", 50);
//分数 > 50
query.addWhereGreaterThan("score", 50);
//分数 >= 50
query.addWhereGreaterThanOrEqualTo("score", 50);

如果你想查询匹配几个不同值的数据,如:要查询“Barbie”,“Joe”,“Julia”三个人的成绩时,你可以使用addWhereContainedIn方法来实现。

String[] names = {"Barbie", "Joe", "Julia"};
query.addWhereContainedIn("playerName", Arrays.asList(names));

相反,如果你想查询排除“Barbie”,“Joe”,“Julia”这三个人的其他同学的信息,你可以使用addWhereNotContainedIn方法来实现。

String[] names = {"Barbie", "Joe", "Julia"};
query.addWhereNotContainedIn("playerName", Arrays.asList(names));

时间查询比较特殊,我们需要结合BmobDate这个类来查询某个指定日期时间前后的数据,这里也给出示例供大家参考:

比如,你想查询2015年2月11号之前的Person数据,那么可以使用addWhereLessThan或者addWhereLessThanOrEqualTo(包含当天)来查询。如果想查询之后的数据,则可以使用addWhereGreaterThan或addWhereGreaterThanOrEqualTo(包含当天)来查询。

BmobQuery<Person> query = new BmobQuery<Person>("Person");
String dateString = "2015-02-11";  
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  
Date date  = null;
try {
    date = sdf.parse(dateString);
} catch (ParseException e) {
    e.printStackTrace();
}  
//这是查询2015年2月11之前的Person数据
query.addWhereLessThan("createdAt",new BmobDate(date));
//这是查询2015年2月11之后的Person数据
//query.addWhereGreaterThan("createdAt",new BmobDate(date));

```java

### 模糊查询

如果你想实现类似数据库的模糊查询,比如,你想查询用户表中用户名中含有“a”的用户,那么你可以使用`addWhereContains`方法来实现。
```java
String value = "a";
query.addWhereContains("username", value);

分页查询

有时,在数据比较多的情况下,你希望查询出的符合要求的所有数据能按照多少条为一页来显示,这时可以使用setLimit方法来限制查询结果的数据条数来进行分页。默认情况下,Limit的值为10,最大有效设置值1000(设置的数值超过1000还是视为1000)。

query.setLimit(10); // 限制最多10条数据结果作为一页

在数据较多的情况下,在setLimit的基础上分页显示数据是比较合理的解决办法,setSKip方法可以做到跳过查询的前多少条数据来实现分页查询的功能。默认情况下Skip的值为10。

query.setSkip(10); // 忽略前10条数据(即第一页数据结果)

大家也可以直接下载我们提供的Demo源码(https://github.com/bmob/bmob-android-demo-paging),查看如何使用分页查询,结合ListView开发下拉刷新查看更多内容的应用。

结果排序

对应数据的排序,如数字或字符串,你可以使用升序或降序的方式来控制查询数据的结果顺序:

// 根据score字段升序显示数据
query.order("score");
// 根据score字段降序显示数据
query.order("-score");
// 多个排序字段可以用(,)号分隔
query.order("-score,createdAt");

说明:多个字段排序时,先按第一个字段进行排序,再按第二个字段进行排序,依次进行。

统计对象数量

如果你只是想统计满足查询对象的数量,你并不需要获取所有匹配对象的具体数据信息,可以直接使用count替代findObjects。例如,查询一个特定玩家玩的游戏场数:

BmobQuery<GameSauce> query = new BmobQuery<GameSauce>();
query.addWhereEqualTo("playerName", "Barbie");
query.count(this, GameSauce.class, new CountListener() {
    @Override
    public void onSuccess(int count) {
        // TODO Auto-generated method stub
        toast("Barbie has played" + count + "games");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("count failure:"+msg);
    }
});

复杂查询

复合与查询(and)

有些查询需要使用到复合“与”的查询条件,例如:你想查询出Person表中年龄在6-29岁之间且姓名以"y"或者"e"结尾的人,那么,可以采用and查询,示例代码如下:

//查询年龄6-29岁之间的人,每一个查询条件都需要New一个BmobQuery对象
//--and条件1
BmobQuery<Person> eq1 = new BmobQuery<Person>();
eq1.addWhereLessThanOrEqualTo("age", 29);//年龄<=29
//--and条件2
BmobQuery<Person> eq2 = new BmobQuery<Person>();
eq2.addWhereGreaterThanOrEqualTo("age", 6);//年龄>=6

//查询姓名以"y"或者"e"结尾的人--这个需要使用到复合或查询(or)
//--and条件3
BmobQuery<Person> eq3 = new BmobQuery<Person>();
eq3.addWhereEndsWith("name", "y");
BmobQuery<Person> eq4 = new BmobQuery<Person>();
eq4.addWhereEndsWith("name", "e");
List<BmobQuery<Person>> queries = new ArrayList<BmobQuery<Person>>();
queries.add(eq3);
queries.add(eq4);
BmobQuery<Person> mainQuery = new BmobQuery<Person>();
BmobQuery<Person> or = mainQuery.or(queries);

//最后组装完整的and条件
List<BmobQuery<Person>> andQuerys = new ArrayList<BmobQuery<Person>>();
andQuerys.add(eq1);
andQuerys.add(eq1);
andQuerys.add(or);
//查询符合整个and条件的人
BmobQuery<Person> query = new BmobQuery<Person>();
query.and(andQuerys);
query.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询年龄6-29岁之间,姓名以\'y\'或者\'e\'结尾的人个数:"+object.size());
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("复合与查询失败:"+code+",msg:"+msg);
    }
});

复合或查询(or)

有些情况,在查询的时候需要使用到复合的“或”的查询条件。例如,你想查出 Person 表中 age 等于 29 或者 age 等于 6 的人,可以这样:

BmobQuery<Person> eq1 = new BmobQuery<Person>();
eq1.addWhereEqualTo("age", 29);
BmobQuery<Person> eq2 = new BmobQuery<Person>();
eq2.addWhereEqualTo("age", 6);
List<BmobQuery<Person>> queries = new ArrayList<BmobQuery<Person>>();
queries.add(eq1);
queries.add(eq2);
BmobQuery<Person> mainQuery = new BmobQuery<Person>();
mainQuery.or(queries);
mainQuery.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub

    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub

    }
});

你还可以在此基础上添加更多的约束条件到新创建的 BmobQuery 对象上,表示一个 and 查询操作。

关系查询

如果你要获得某个字段匹配特定BmobObject的对象列表,你可以像查询其他数据类型一样使用addWhereEqualTo来查询。例如:每个Weibo对象都包含一个BmobUser对象在它的author字段上,现在你想查询当前用户发布的所有微博信息,如下:

BmobQuery<Weibo> query = new BmobQuery<Weibo>();
query.order("-updatedAt");
BmobUser user = BmobUser.getCurrentUser(this);
query.addWhereEqualTo("author", user);    // 查询当前用户的所有微博
query.findObjects(this, new FindListener<Weibo>() {
    @Override
    public void onSuccess(List<Weibo> object) {
        // TODO Auto-generated method stub
        toast("查询成功.");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

如果你在查询某个对象列表时,它们的某个字段是BmobObject类型,并且这个BmobObject匹配一个不同的查询,这种情况下可使用addWhereMatchesQuery方法,请注意,默认的 limit 限制 10 也同样作用在内部查询上。因此如果是大规模的数据查询,你可能需要仔细构造你的查询对象来获取想要的行为。例如:要查询带有图片的微博的评论列表:

BmobQuery<Comment> query = new BmobQuery<Comment>();
BmobQuery<Weibo> innerQuery = new BmobQuery<Weibo>();
innerQuery.addWhereExists("image", true);
// 第一个参数为评论表中的weibo字段名
// 第二个参数为weibo字段的表名,也可以直接用"Weibo"字符串的形式
// 第三个参数为内部查询条件
query.addWhereMatchesQuery("weibo", Weibo.class.getSimpleName(), innerQuery);
query.findObjects(this, new FindListener<Comment>() {
    @Override
    public void onSuccess(List<Comment> object) {
        // TODO Auto-generated method stub
        toast("查询成功:");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

反之,不想匹配某个子查询,你可以使用addWhereDoesNotMatchQuery方法。 比如为了查询微博中不带图片的评论列表:

BmobQuery<Comment> query = new BmobQuery<Comment>();
BmobQuery<Weibo> innerQuery = new BmobQuery<Weibo>();
innerQuery.addWhereExists("image", true);
// 第一个参数为评论表中的weibo字段名
// 第二个参数为weibo字段的表名,也可以直接用"Weibo"字符串的形式
// 第三个参数为内部查询条件
query.addWhereDoesNotMatchQuery("weibo", Weibo.class.getSimpleName(), innerQuery);
query.findObjects(this, new FindListener<Comment>() {
    @Override
    public void onSuccess(List<Comment> object) {
        // TODO Auto-generated method stub
        toast("查询成功:");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

在某些情况下,你想在一个查询内获取多种类型的关联对象。你可以使用include方法。例如,你想获取最近的 10 条评论,同时包括它们关联的weibo:

BmobQuery<Comment> query = new BmobQuery<Comment>();
query.setLimit(10); // 限制10条
query.order("createdAt"); //按创建时间排序
query.include("weibo"); //同时将对应的微博信息也查询出来
query.findObjects(this, new FindListener<Comment>() {
    @Override
    public void onSuccess(List<Comment> object) {
        // TODO Auto-generated method stub
        toast("查询成功");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

你可以使用 .号(英语句号)操作符来并列 include 中的内嵌的对象。比如,你同时想 include 一个 Comment 的 weibo 和weibo的 author(发布人)对象,你可以这样做:

query.include("weibo.author");

这里需要注意的是:

1、include的查询对象只能为BmobPointer类型,而不能是BmobRelation类型。

2、如果你想include两个对象,你可以这样做:

query.include("Comment,User");

但不能如下的做法:

query.include("Comment");
query.include("User");

缓存查询

缓存查询通常是将查询结果缓存在磁盘上。当用户的设备处于离线状态时,就可以从缓存中获取数据来显示。或者在应用界面刚刚启动,从网络获取数据还未得到结果时,先使用缓存数据来显示。这样可以让用户不必在按下某个按钮后进行枯燥的等待。 默认的查询操作是没有启用缓存的,开发者可以使用setCachePolicy方法来启用缓存功能。例如:优先从缓存获取数据,如果获取失败再从网络获取数据。

bmobQuery.setCachePolicy(CachePolicy.CACHE_ELSE_NETWORK);    // 先从缓存获取数据,如果没有,再从网络获取。
bmobQuery.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共"+object.size()+"条数据。");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

Bmob SDK提供了几种不同的缓存策略,以适应不同应用场景的需求:

  • IGNORE_CACHE

只从网络获取数据,且不会将数据缓存在本地,这是默认的缓存策略。

  • CACHE_ONLY

只从缓存读取数据,如果缓存没有数据会导致一个BmobException,可以忽略不处理这个BmobException.

  • NETWORK_ONLY

只从网络获取数据,同时会在本地缓存数据。

  • CACHE_ELSE_NETWORK

先从缓存读取数据,如果没有,再从网络获取。

  • CACHE_THEN_NETWORK

先从缓存取数据,无论结果如何都会再次从网络获取数据。也就是说会产生2次调用。通常的用法是先快速取出缓存数据展示view,然后再后台连接网络取得最新数据,取到后用来自网络服务器的最新数据更新view。

如果需要操作缓存内容,可以使用BmobQuery提供的方法做如下操作:

  • 检查是否存在当前查询条件的缓存数据
    booleanisInCache = query.hasCachedResult(this);
  • 清除当前查询的缓存数据
    query.clearCachedResult(this);
  • 清除所有查询结果的缓存数据
    BmobQuery.clearAllCachedResults(this);
  • 设置缓存的最长时间
    query.setMaxCacheAge(100000L);

查询指定列

有的时候,一张表的数据列比较多,而我们只想查询返回某些列的数据时,我们可以使用BmobQuery对象提供的addQueryKeys方法来实现。如下所示:

BmobQuery<Person> bmobQuery = new BmobQuery<Person>();
bmobQuery.addQueryKeys("objectId");
bmobQuery.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共" + object.size() + "条数据。");
         //注意:这里的Person对象中只有指定列的数据。
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:" + msg);
    }
});

指定多列时用,号分隔每列,如:addQueryKeys("objectId,name,add");

修改数据

更新一个对象也是非常简单。例如:将GameScore表中objectId为0c6db13c的游戏分数修改为77.

GameScore gameScore = new GameScore();
gameScore.setScore(77);
gameScore.update(this, "0c6db13c", new UpdateListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("更新成功:");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("更新失败:"+msg);
    }
});

删除数据

从服务器删除对象。例如:将GameScore表中objectId为dd8e6aff28的数据删除。

GameScore gameScore = new GameScore();
gameScore.setObjectId("dd8e6aff28");
gameScore.delete(this, new DeleteListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("删除成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("删除失败:"+msg);
    }
});

删除字段

你可以在一个对象中删除一个字段,通过remove操作:

GameScore gameScore = new GameScore();
gameScore.setObjectId("dd8e6aff28");
gameScore.remove("score");    // 删除GameScore对象中的score字段
gameScore.update(this, new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("删除GameScore对象中的score字段成功");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("删除GameScore对象中的score字段失败:"+msg);
    }
});

数组

对于数组型数据,BmobSDK提供了3种操作来原子性地更改一个数组字段: add、addAll 在一个数组字段的后面添加一些指定的对象(包装在一个数组内) addUnique、addAllUnique 只会在原本数组字段中没有这些对象的情形下才会添加入数组,插入数组的位置不固定的 removeAll 从一个数组字段的值内移除指定的数组中的所有对象

添加数组数据

给一个数据对象中的数组类型字段添加数据可以使用以下方法添加:

Person p = new Person();
p.add("hobby", "唱歌");    // 添加一个值到hobby字段中,hobby为数组类型
//p.addAll("hobby", Arrays.asList("游泳", "看书"));    // 一次添加多个值到hobby字段中
p.save(this, new SaveListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("保存成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("保存失败:"+msg);
    }
});

更新数组数据

举个例子,hobby(爱好)是一个数组类型的字段,那么我们可以在hobby字段中加入一些爱好,只有在hobby字段中不包含这些爱好的情况下才会被加入:

Person p = new Person();
p.setObjectId("d32143db92");
p.addUnique("hobby", "爬山");    // 添加一个值到hobby字段中
//p.addAllUnique("hobby", Arrays.asList("游泳", "羽毛球")); // 一次添加多个值到hobby字段中
p2.update(this, new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("更新爱好成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("更新爱好失败:"+msg);
    }
});

查询数组数据

对于字段类型为数组的情况,可以查找字段中的数组值包含有xxx的对象:

BmobQuery<Person> query = new BmobQuery<Person>();
String [] hobby = {"阅读","唱歌"};
query.addWhereContainsAll("hobby", Arrays.asList(hobby));
query.findObjects(this, new FindListener<Person>() {

    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共" + object.size() + "条数据。");
    }

    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:" + code);
    }

});

删除数组数据

同理我们也可以使用removeAll从数组字段中移除某些值:

Person p = new Person();
p.removeAll("hobby", Arrays.asList("阅读","唱歌","游泳"));
p.update(this, new UpdateListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("从hobby字段中移除阅读、唱歌、游泳成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("从hobby字段中移除阅读、唱歌、游泳失败:"+msg);
    }
});

数据关联

关联关系描述

在程序设计中,不同类型的数据之间可能存在某种关系。比如文章和评论的关系,一篇文章对应有很多条评论,这是一对多的关系,而一条评论只属于某一篇文章,这是一对一的关系。Bmob提供了Pointer(一对一的关系)和Relation(一对多的关系)两种数据类型来解决这种业务需求。

本案例的场景描述

由于关联关系讲解起来比较复杂,以下用一个简单的案例来说明在Bmob中是如何使用关联关系的,最后会提供相应的源码。 这个场景是这样的:我们生活中每个人都可能会办理多张银行卡,而每张银行卡的登记人只有一个。从这个场景可以看出有两个对象,一个是人,一个是银行卡。

Web端创建关联字段

我们接下来需要在Web端创建对应的表,分别是用户表和银行卡表,其中用户表我们直接使用Bmob提供的系统表User表。 在创建数据表的字段的时候,当选择字段类型为Pointer或Relation时,会提示你选择该字段所指向或关联的数据表。如下图所示:

图1 点击添加云端方法名

根据本案例的场景,我们需要在User表中多增加一列为cards,数据类型为Relation,然后创建一个银行卡信息表(BankCard),银行卡表的主要结构如下: bankName String 银行名称 cardNumber String 银行卡号 user Pointer<_User> 银行卡用户

为了更直观的展示数据表的结构,我将两个表的截图贴上,以供参考:

用户表(注意cards字段)

图1 点击添加云端方法名

银行卡表(注意user字段)

图1 点击添加云端方法名

创建数据对象

接下来我们需要创建User表和BankCard表对应的数据对象,User表对应的数据对象的代码如下:

public class MyUser extends BmobUser{
    /**
     * 用户名称
     */
    private String nickname;
    /**
     * 用户的银行卡
     * 一个人可能有多张不同的银行卡,这里选择使用了BmobRelation类型
     */
    private BmobRelation cards;

    public String getNickname() {
        return nickname;
    }
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    public BmobRelation getCards() {
        return cards;
    }
    public void setCards(BmobRelation cards) {
        this.cards = cards;
    }


}

这里注意的是:1、不少开发者在扩展BmobUser的时候,往往还会在属性中加上objectId、username、password、createAt、updateAt等数据表中看到的字段和方法。实际上,BmobUser中已经实现了,如果再次声明的话,会导致编译性的错误。 2、类名可以自定义,这个跟其他表的命名方式有所不同。

BankCard表对应的数据对象的代码如下:

public class BankCard extends BmobObject {
    /**
     * 银行卡号
     */
    private String cardNumber;
    /**
     * 银行名称
     */
    private String bankName;
    /**
     * 户主
     */
    private MyUser user;

    public String getCardNumber() {
        return cardNumber;
    }
    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }
    public String getBankName() {
        return bankName;
    }
    public void setBankName(String bankName) {
        this.bankName = bankName;
    }
    public MyUser getUser() {
        return user;
    }
    public void setUser(MyUser user) {
        this.user = user;
    }
}

这里需要注意的是:1、类名要和表名保持一致。 2、MyUser属性对应为Pointer的指针类型。

添加关联关系

接下来我们就从代码层次上来讲解,怎么样来操作这些关联关系的数据。首先我们来讲添加关联关系。在我们创建一张银行卡信息时,需要指定这张卡的户主(user),这就是添加的一对一的关联关系。代码如下:

/**
 * 创建一条银行卡信息到BankCard表中,并关联到用户的银行卡信息中
 * @param bankName 银行名称
 * @param cardNumber 银行卡号
 */
private void saveBankCardInfo(String bankName, String cardNumber){

    if(TextUtils.isEmpty(user.getObjectId())){
        toast("当前用户的object为空");
        return;
    }

    card = new BankCard();
    card.setBankName(bankName);        // 设置银行名称
    card.setCardNumber(cardNumber);    // 设置银行卡号
    card.setUser(user);                // 设置银行卡户主
    card.save(this, new SaveListener() {
        @Override
        public void onSuccess() {
            // TODO Auto-generated method stub
            toast("成功保存一条银行卡信息到BankCard表中");
            addCardToUser();
        }

        @Override
        public void onFailure(int arg0, String arg1) {
            // TODO Auto-generated method stub
            toast("很遗憾,保存一条银行卡信息到BankCard表中失败了");
        }
    });
}

修改关联关系

当我们的这张银行卡创建成功后,不仅仅只是设置银行卡的户主就可以来,我们还需要更新户主的信息,也就是将当前银行卡关联到用户的cards列中。这就是修改关联关系,代码如下:

/**
 * 添加银行卡到用户的银行卡信息中
 */
private void addCardToUser(){
    if(TextUtils.isEmpty(user.getObjectId()) || 
            TextUtils.isEmpty(card.getObjectId())){
        toast("当前用户或者当前Card对象的object为空");
        return;
    }

    BmobRelation cards = new BmobRelation();
    cards.add(card);
    user.setCards(cards);
    user.update(this, new UpdateListener() {

        @Override
        public void onSuccess() {
            // TODO Auto-generated method stub
            toast("已成功添加到用户的银行卡信息中");
        }

        @Override
        public void onFailure(int arg0, String arg1) {
            // TODO Auto-generated method stub
            toast("很遗憾,用户的银行卡信息添加失败");
        }
    });
}

上面的代码将某银行卡添加到了用户的银行卡信息中,还有一种情况是从用户的银行卡信息中删除掉某银行卡的信息,在现实生活中我叫注销我的银行卡。代码示例如下:

/**
 * 删除用户信息中的某银行卡信息
 */
private void removeCardToUser(){
    if(TextUtils.isEmpty(user.getObjectId()) || 
            TextUtils.isEmpty(card.getObjectId())){
        toast("当前用户或者当前Card对象的object为空");
        return;
    }

    BmobRelation cards = new BmobRelation();
    cards.remove(card);
    user.setCards(cards);
    user.update(this, new UpdateListener() {

        @Override
        public void onSuccess() {
            // TODO Auto-generated method stub
            toast("在用户信息中已成功移除该银行卡信息");
        }

        @Override
        public void onFailure(int arg0, String arg1) {
            // TODO Auto-generated method stub
            toast("很遗憾,移除失败");
        }
    });
}

查询关联关系

需求1:查询我的所有银行卡信息,代码如下:

/**
 * 查询我的所有银行卡信息
 */
private void findMyCards(){
    BmobQuery<BankCard> cards = new BmobQuery<BankCard>();
    /**
     * 注意这里的查询条件
     * 第一个参数:是User表中的cards字段名
     * 第二个参数:是指向User表中的某个用户的BmobPo
     * er对象
     */
    cards.addWhereRelatedTo("cards", new BmobPointer(user));
    cards.findObjects(this, new FindListener<BankCard>() {

        @Override
        public void onSuccess(List<BankCard> arg0) {
            // TODO Auto-generated method stub
            toast("我现在有"+arg0.size()+"张银行卡");
            for (BankCard bankCard : arg0) {
                Log.d("bmob", "objectId:"+bankCard.getObjectId()+",银行名称:"+bankCard.getBankName()+",卡号:"+bankCard.getCardNumber());
            }
        }

        @Override
        public void onError(int arg0, String arg1) {
            // TODO Auto-generated method stub
            toast("查询我银行卡信息失败");
        }
    });
}

需求2:查询银行卡信息时同时获取该卡的户主信息,代码如下:

/**
 * 查询银行卡信息时同时获取该卡的户主信息
 */
private void findCardUser(){
    BmobQuery<BankCard> query = new BmobQuery<BankCard>();
    query.include("user");    // 注意这里的include方法,当在查询过程中想将指针类型的对象信息也查询出来是请使用此方法。
    query.getObject(this, card.getObjectId(), new GetListener<BankCard>() {

        @Override
        public void onSuccess(BankCard arg0) {
            // TODO Auto-generated method stub
            toast("卡号:"+arg0.getCardNumber()+"\n"
                    +"户主:"+arg0.getUser().getUsername());
        }

        @Override
        public void onFailure(int arg0, String arg1) {
            // TODO Auto-generated method stub
            toast("查询银行卡信息失败"+arg1);
        }
    });
}

关联关系的案例源码

以上示例的源代码地址是:https://github.com/bmob/bmob-android-demo-relation。如果您从文档中还不能理解关联关系的使用,可以下载源码进行学习。

批量数据操作

在BmobObject对象中提供了三种用于批量操作的方法,分别是insertBatchupdateBatchdeleteBatch,批量添加、更新、删除。

  • insertBatch的使用方式如下:
List<BmobObject> persons = new ArrayList<BmobObject>();
for (int i = 0; i < 3; i++) {
    Person person = new Person();
    person.setName("张三 "+i);
    person.setAddress("上海朝阳路"+i+"号");
    person.setGpsAdd(new BmobGeoPoint(112.934755, 24.52065));
    person.setUploadTime(new BmobDate(new Date()));
    List<String> hobbys = new ArrayList<String>();
    hobbys.add("阅读");
    hobbys.add("篮球");
    hobbys.add("唱歌");
    person.setHobby(hobbys);
    person.setBankCard(new BankCard("中国银行", "176672673687545097"+i));
    persons.add(person);
}
new BmobObject().insertBatch(this, persons, new SaveListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("批量添加成功");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("批量添加失败:"+msg);
    }
});
  • updateBatch的使用方式如下:
List<BmobObject> persons = new ArrayList<BmobObject>();
Person p1 = new Person();
p1.setObjectId("e51d651c22");
p1.setAge(25);
Person p2 = new Person();
p2.setObjectId("3f70a922c4");
p2.setAge(26);
p2.setGender(false);
Person p3 = new Person();
p3.setObjectId("08fdd55765");
p3.setAge(27);

persons.add(p1);
persons.add(p2);
persons.add(p3);

new BmobObject().updateBatch(this, persons, new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("批量更新成功");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("批量更新失败:"+msg);
    }
});
  • deleteBatch的使用方式如下:
List<BmobObject> persons = new ArrayList<BmobObject>();
Person p1 = new Person();
p1.setObjectId("38ea274d0c");
Person p2 = new Person();
p2.setObjectId("01e29165bc");
Person p3 = new Person();
p3.setObjectId("d8226c4828");

persons.add(p1);
persons.add(p2);
persons.add(p3);

new BmobObject().deleteBatch(this, persons, new DeleteListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("批量删除成功");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("批量删除失败:"+msg);
    }
});

注意:

  1. 任何一种批量操作每次只支持最大50条记录的操作。
  2. 批量操作不支持对User表的操作。

原子计数器

很多应用可能会有计数器功能的需求(并发请求会出现这个问题),比如某条信息被点赞多少次,如果多人同时操作,如果用普通的更新方法的话,可能会导致数据不一致的情况。为此,Bmob提供了原子计数器来保证原子性的修改某一数值字段的值。注意:原子计数器只能对应用于Web后台的Number字段,和实体类实现中的Integer对象类型(类中请不要用int类型)。

gameScore.increment("score"); // 分数递增1
gameScore.update(this, updateListener);

您还可以通过increment(key, amount)方法来递增或递减任意幅度的数字

gameScore.increment("score", 5); // 分数递增5
//gameScore.increment("score", -5); // 分数递减5
gameScore.update(this, updateListener);

文件管理

BmobFile可以让你的应用程序将文件存储到服务器中,常见的文件类型都可以实现存储:比如图像文件、影像文件、音乐文件和任何其他二进制数据。 【注】以下均为SDK对文件进行操作的方法,如果你想在Web端对文件进行操作,请查看我们的帮助文档:http://docs.bmob.cn/helps/index.html?menukey=otherdoc&key=helps#index_如何在Web后台上传文件(如图片)

创建文件对象

创建文件对象方式如下:

String picPath = "sdcard/temp.jpg";
BmobFile bmobFile = new BmobFile(new File(picPath));

上传单一文件

文件分片上传的方法非常简单,示例代码如下:

String picPath = "sdcard/temp.jpg";
BmobFile bmobFile = new BmobFile(new File(picPath));
bmobFile.uploadblock(this, new UploadFileListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        //bmobFile.getUrl()---返回的上传文件的地址(不带域名)
        //bmobFile.getFileUrl(context)--返回的上传文件的完整地址(带域名)
        toast("上传文件成功:" + bmobFile.getFileUrl(context));
    }

    @Override
    public void onProgress(Integer value) {
        // TODO Auto-generated method stub
        // 返回的上传进度(百分比)
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("上传文件失败:" + msg);
    }
});

批量上传文件

BmobSDK_V3.2.7新增批量上传文件的方法,使用起来也很简单,示例代码如下:

//详细示例可查看BmobExample工程中BmobFileActivity类

String filePath_mp3 = "/mnt/sdcard/testbmob/test1.png";
String filePath_lrc = "/mnt/sdcard/testbmob/test2.png";
String[] filePaths = new String[2];
filePaths[0] = filePath_mp3;
filePaths[1] = filePath_lrc;
Bmob.uploadBatch(this, filePaths, new UploadBatchListener() {

    @Override
    public void onSuccess(List<BmobFile> files,List<String> urls) {
        // TODO Auto-generated method stub
        //1、files-上传完成后的BmobFile集合,是为了方便大家对其上传后的数据进行操作,例如你可以将该文件保存到表中
        //2、urls-上传文件的服务器地址
    }

    @Override
    public void onError(int statuscode, String errormsg) {
        // TODO Auto-generated method stub
        ShowToast("错误码"+statuscode +",错误描述:"+errormsg);
    }

    @Override
    public void onProgress(int curIndex, int curPercent, int total,int totalPercent) {
        // TODO Auto-generated method stub
        //1、curIndex--表示当前第几个文件正在上传
        //2、curPercent--表示当前上传文件的进度值(百分比)
        //3、total--表示总的上传文件数
        //4、totalPercent--表示总的上传进度(百分比)
    }
});

下载文件

查询数据时获取文件对象的示例代码如下(文件下载的具体代码实现需要大家自行实现):

bmobQuery.findObjects(this, new FindListener<GameSauce>() {
    @Override
    public void onSuccess(List<GameSauce> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共"+object.size()+"条数据。");
        for (Person person : object) {
               if(person.getPic() != null){
                                  //文件名称
                                person.getPic().getFilename();
                                //文件下载地址
                person.getPic().getFileUrl();
            }
        }
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:"+msg);
    }
});

删除文件

BmobSDKV3.3.0提供了删除文件的接口,方便开发者对文件进行管理,示例代码如下:

BmobFile file = new BmobFile();
//此url是上传文件成功之后通过bmobFile.getUrl()方法获取的。
file.setUrl(url);
file.delete(this, new DeleteListener() {

    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        showToast("文件删除成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        showToast("文件删除失败:"+code+",msg = "+msg);
    }
});

为方便大家理解文件服务的使用,Bmob提供了一个文件上传的案例和源码,大家可以到示例和教程中查看和下载

注:

1、单个文件上传大小不可超过200M;

2、文件分片上传的大小不可超过200M;

3、有时候使用upload方式上传不超过10M的文件的时候会出现OOM异常,故,建议开发者使用uploadblock(分片上传)方法来上传文件。

4、文件的批量上传是BmobSDK_v3.2.7版本才提供的功能,如需使用,请更新版本。

缩略图

1、 获取缩略图

如果你的BmobFile对象是保存的图片类型的文件,那么当你需要使用缩略图功能的时候,可以使用loadImageThumbnail方法来获取改图片的缩略图。

bmobFile.loadImageThumbnail(this, imageView, 300, 300);

你还可以指定获取缩略图的图片质量

bmobFile.loadImageThumbnail(this, imageView, 300, 300, 100);

2、获取图片

很多时候您可能只是想直接加载图片来显示,那么你可以使用loadImage方法来加载原图。

bmobFile.loadImage(this, imageView);

同样您也可以指定加载原图显示的大小

bmobFile.loadImage(this, imageView, 300, 300);

3、 缩略图的案例源码

我们为大家提供了缩略图的一个简单案例源码,大家可以下载查看:https://github.com/bmob/bmob-android-demo-thumbnail

新版文件管理

新版文件管理是通过BmobProFile类(自BmobSDKv3.2.9开始)完成的,其提供了文件的单一上传、批量上传、文件下载、生成缩略图等功能,

BmobProFile和BmobFile两者之间是不兼容的,也就是说不能用BmobFile类上传的成功后得到的文件名再用BmobProFile类提供的下载方法来下载。

单一上传

单一文件上传只需要调用BmobProFile类提供的静态方法:upload,示例代码如下:

BTPFileResponse response = BmobProFile.getInstance(MainActivity.this).upload(filePath, new UploadListener() {

            @Override
            public void onSuccess(String fileName,String url) {
                // TODO Auto-generated method stub
                dialog.dismiss();
                showToast("文件已上传成功:"+fileName);
            }

            @Override
            public void onProgress(int ratio) {
                // TODO Auto-generated method stub
                BmobLog.i("MainActivity -onProgress :"+ratio);
            }

            @Override
            public void onError(int statuscode, String errormsg) {
                // TODO Auto-generated method stub
                showToast("上传出错:"+errormsg);
            }
        });

onSuccess方法参数:

1、fileName:文件名(带后缀),这个文件名是唯一的,开发者需要记录下该文件名,方便后续下载该文件。

2、url:文件服务器地址(如果你上传的是图片类型的文件,此url地址并不能直接在浏览器查看(会出现404错误),需要经过URL签名得到真正的可访问的URL地址)。

URL签名

1、使用场景:

开发者上传的如果是图片且希望能够访问完整的URL地址用来客户端直接显示图片,那么就需要用到URL签名。

2、签名认证步骤:

1)、开启签名认证:

开发者需要在web后台开启文件管理的URL签名认证:

文件管理-->基本配置-->设置SecretKey-->开启-->保存

注:此处的secretKey可任意填写,它是专门针对文件服务的,和"应用密钥"中的数据服务使用到的SecretKey是不一样的。

此部分为配置了URL的签名认证安全的开发者使用,若没配置,则按照正常处理。

2)、URL签名说明:

URL签名,需要携带签名后的参数,用于验证当前的来源的数据是否遭到破坏等。

开启签名认证的URL地址格式:

URL=url(文件上传成功之后返回的url地址)?t=(客户端类型)&a=(应用密钥中的AccessKey)&e=(时间)&token=(token签名)

未开启签名认证的URL地址格式:

URL=url(文件上传成功之后返回的url地址)?t=(客户端类型)&a=(应用密钥中的AccessKey)

注:

1、t:客户端类型(1~19代表SDK客户端,1:IOS,2:Android,3:wp,…,20:官网后台;21:其他网站)

2、AccessKey:在web后台的应用密钥中查看

3、e:当前服务器的时间戳+有效时长,以秒为单位。

4、Token:Token签名使用了web后台的文件管理中设置的SecretKey,开发者要注意此值的安全不被泄漏.

3)、URL签名步骤:

请求的文件名称fileName: dfwsdweqe0012.jpg;

请求的文件服务器地址url:http://testAPi.bmob.cn/dfwsdweqe0012.jpg

假如请求参数为:

假设当前的时间戳为:1415697063 有效时间时长为:300秒,则e=1415697063+300,

当前时间戳:e= 1415697363 // unix time时间,单位为秒

当前客户端类型: t=1 //注释:Android

App的AccessKey:a=b63737a2825821fc3208b8a80a524da

当前的密钥SecretKey:abcdefg

组装请求URI:

Uri = /dfwsdweqe0012.jpg?t=1&a=b63737a2825821fc3208b8a80a524da&e=1415697363

得到Token:

1、针对Uri进行HMAC-SHA1算法签名;

2、对签名后的字符串进行URL安全Base64编码;

3、编码后即为要要发送的token。

伪代码如下:

Token=urlbase64_encode(hmacsha1(Uri, secretKey));

得到token= vMs1nom-Pf-WQRgNs8EA2aiQQpo=

得到最终的发送请求的URL为:

http://testAPi.bmob.cn/dfwsdweqe0012.jpg?t=1&a=b63737a2825821fc3208b8a80a524da & e=1415697363&token=vMs1nom-Pf-WQRgNs8EA2aiQQpo=

注:1、以上所有的参数名(t,a,e,token)均为小写,参数顺序为t,a,e,token,uri、secretkey等编码格式都为utf-8。

2、URL安全的Base64编码方式的基本过程是先将内容以Base64格式编码为字符串,然后检查该编码后的字符串,将字符串中的加号+换成中划线-,斜杠/换成下划线_,得到最终的字符串;

4)、URL签名方法:

鉴于URL签名比较复杂,BmobSDKV3.3.0的BmobProFile类为开发者提供了获取URL签名的方法:signURL(V3.3.2已修改为BmobProFile类的内部方法)


/**
 * @param fileName:文件名
 * @param fileUrl :文件url地址
 * @param accessKey:web应用密钥中的AccessKey
 * @param effectTime:有效时长(秒)
 * @param secretKey:密钥
 * @return 可访问的URL地址
 */
String URL = BmobProFile.getInstance(MainActivity.this).signURL(String fileName,String fileUrl,String accessKey,long effectTime,String secretKey)

未开启URL签名认证的示例代码如下:

String URL =BmobProFile.getInstance(MainActivity.this).signURL("dfwsdweqe0012.jpg","http://testAPi.bmob.cn/dfwsdweqe0012.jpg","b63737a2825821fc3208b8a80a524da",0,null);

已开启URL签名认证的示例代码如下:

String URL = BmobProFile.getInstance(MainActivity.this).signURL("dfwsdweqe0012.jpg","http://testAPi.bmob.cn/dfwsdweqe0012.jpg","b63737a2825821fc3208b8a80a524da",100,"abcdefg");

注:

1、fileName/fileUrl:表示上传(批量上传)成功后得到的文件名/文件服务器地址。

2、effectTime:表示这个URL请求的有效时长,单位为秒,一旦超过有效时长,则该URL请求失效。

3、若开发者未开启URL签名认证,则前三个参数必填,后面的effectTime传0,secretKey传null即可。

4、若文件类型为图片类型,客户端需要直接显示的话,则不建议开启URL签名认证

批量上传

BmobProFile同样提供了批量上传文件的静态方法:uploadBatch:示例代码如下:

BmobProFile.getInstance(MainActivity.this).uploadBatch(files, new UploadBatchListener() {

            @Override
            public void onSuccess(boolean isFinish,String[] fileNames,String[] urls) {
                // TODO Auto-generated method stub
                if(isFinish){
                    dialog.dismiss();
                }
                showToast(""+isFinish+"-----"+Arrays.asList(fileNames)+"----"+Arrays.asList(urls));
            }

            @Override
            public void onProgress(int curIndex, int curPercent, int total,int totalPercent) {
                // TODO Auto-generated method stub
                dialog.setProgress(curIndex);
                BmobLog.i("MainActivity -onProgress :"+curIndex+"---"+curPercent+"---"+total+"----"+totalPercent);
            }

            @Override
            public void onError(int statuscode, String errormsg) {
                // TODO Auto-generated method stub
                dialog.dismiss();
                showToast("批量上传出错:"+statuscode+"--"+errormsg);
            }
        });
    }

onProgress方法参数:

1、curIndex :表示当前第几个文件正在上传

2、curPercent :表示当前上传文件的进度值(百分比)

3、total :表示总的上传文件数

4、totalPercent:表示总的上传进度(百分比)

文件下载

BmobProFile同样提供了文件下载的静态方法:download,只需要将上传文件后记录下来的文件名fileName(必须是通过BmobProFile类的upload方法得到的)作为参数即可,示例代码如下:


BmobProFile.getInstance(MainActivity.this).download(fileName, new DownloadListener() {

            @Override
            public void onSuccess(String fullPath) {
                // TODO Auto-generated method stub
                showToast("下载成功:"+fullPath);
            }

            @Override
            public void onProgress(String localPath, int percent) {
                // TODO Auto-generated method stub
                BmobLog.i("MainActivity -download-->onProgress :"+percent);
                dialog.setProgress(percent);
            }

            @Override
            public void onError(int statuscode, String errormsg) {
                // TODO Auto-generated method stub
                dialog.dismiss();
                showToast("下载出错:"+statuscode +"--"+errormsg);
            }
        });

注:

1、onProgress参数localPath:表示当前下载文件的地址,当下载进度不为100的时候,这个地址下面的文件是不完整的,只有一部分。

2、onSuccess参数fullPath :表示下载成功后文件的存储完整地址,和localpath的路径是一样的。

3、允许开发者自定义保存下载文件的目录名,可在Apllication中对其进行初始化配置。示例如下:

BmobConfiguration config = new BmobConfiguration.Builder(context).customExternalCacheDir("目录名").build();
BmobPro.getInstance(context).initConfig(config);

缩略图处理

对图片进行缩略图处理,BmobProFile类提供了两种方式:

一种将生成缩略图的任务提交给服务器,由服务器来处理并同步返回生成后的服务器缩略图地址(submitThumnailTask);另一种是SDK提供的本地处理缩略图的方法(getLocalThumbnail)。

一、submitThumnailTask

示例代码如下:


BmobProFile.getInstance(MainActivity.this).submitThumnailTask(fileName, modelId, new ThumbnailListener() {

            @Override
            public void onSuccess(String thumbnailName,String thumbnailUrl) {
                // TODO Auto-generated method stub
                //此处得到的缩略图地址(thumbnailUrl)不一定能够请求的到,此方法为异步方法
                BmobLog.i("MainActivity -onSuccess :"+thumbnailName+"-->"+thumbnailUrl);
            }

            @Override
            public void onError(int statuscode, String errormsg) {
                // TODO Auto-generated method stub
                BmobLog.i("MainActivity -onError :"+statuscode+"---"+errormsg);
            }
        });

注:

A、请求参数:fileName:文件名,modelId :缩略图的规格类型ID

B、thumbnailName的格式:

fileName+"_"+modelId

如果fileName=f24af10cbc15476e9789afaf168c3b8e.jpg,modelId=1,那么thumbnailName=f24af10cbc15476e9789afaf168c3b8e.jpg_1。

C、目前Bmob提供的规格类型ID(modelId)有六种:

1--指定宽,高自适应,等比例缩放;

2--指定高,宽自适应,等比例缩放;

3--指定最长边,短边自适应,等比例缩放;

4--指定最短边,长边自适应,等比例缩放;

5--指定最大宽高,等比例缩放;

6--固定宽高,居中裁剪;

二、getLocalThumbnail

SDK提供了三种处理本地缩略图的方式:

一、指定规格ID

示例代码如下:

BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath, modelId, new LocalThumbnailListener() {

                    @Override
                    public void onError(int statuscode, String errormsg) {
                        // TODO Auto-generated method stub
                        BmobLog.i("MainActivity -localThumbnail-->生成缩略图失败 :"+statuscode+","+errormsg);
                    }

                    @Override
                    public void onSuccess(String thumbnailPath) {
                        // TODO Auto-generated method stub
                        BmobLog.i("MainActivity -localThumbnail-->生成后的缩略图路径 :"+thumbnailPath);
                    }
                });

二、指定规格ID、宽、高

示例代码如下:

BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath, modeId, width, height, new LocalThumbnailListener() {

                    @Override
                    public void onError(int statuscode, String errormsg) {
                        // TODO Auto-generated method stub
                        showToast("本地缩略图创建失败 :"+statuscode+","+errormsg);
                    }

                    @Override
                    public void onSuccess(String thumbnailPath) {
                        // TODO Auto-generated method stub
                        showToast("本地缩略图创建成功  :"+thumbnailPath);
                    }
                });

三、指定规格ID、宽、高、图片压缩质量

为了方便开发者对图片进行压缩处理,V3.3.3版本在获取本地缩略图的方法中新增了图片压缩质量(quality)参数,取值范围:0-100。示例代码如下:

BmobProFile.getInstance(LocalThumbnailActivity.this).getLocalThumbnail(localPath, modeId, width, height, quality,new LocalThumbnailListener() {

                    @Override
                    public void onError(int statuscode, String errormsg) {
                        // TODO Auto-generated method stub
                        showToast("本地缩略图创建失败 :"+statuscode+","+errormsg);
                    }

                    @Override
                    public void onSuccess(String thumbnailPath) {
                        // TODO Auto-generated method stub
                        showToast("本地缩略图创建成功  :"+thumbnailPath);
                    }
                });

注:

1、localPath:图片的本地路径,需要带后缀名

2、modelId:开发者应事先在应用管理后台(文件管理-->自定义版本-->缩略图配置版本)完成基本的生成缩略图的规格配置:

数据实时同步

数据实时同步是一个超酷的功能!

SDK可以实现对数据表或行的监听,当这个表或者行的数据发生变化时,Bmob会立即将变化的信息告知SDK。 这种服务非常适合做游戏开发(如,开发斗地主游戏,三个人同时监听一行数据的变化,任何一个人出牌都会将数据写入到这行数据中,其他人也就立即知道了)、群聊(一群人监听某个表的变化,任何人发言都会将数据写入到这个表中,其他人也可以立即知道了)等实时性要求很高的场景中。

为方便大家快速了解数据的实时同步服务,我们提供了一个简单的应用实例( https://github.com/bmob/bmob-android-demo-realtime-data )供大家参考。

开始连接

使用数据实时功能,首先需要创建BmobRealTimeData对象,然后调用start方法连接服务器。

BmobRealTimeData rtd = new BmobRealTimeData();
rtd.start(this, new ValueEventListener() {
    @Override
    public void onDataChange(JSONObject data) {
        // TODO Auto-generated method stub
        Log.d("bmob", "("+data.optString("action")+")"+"数据:"+data);
    }

    @Override
    public void onConnectCompleted() {
        // TODO Auto-generated method stub
        Log.d("bmob", "连接成功:"+rtd.isConnected());
    }
});

start方法中的ValueEventListener参数用于监听连接成功和数据变化的回调。当有数据变化时会通过onDataChange回调方法反馈到客户端。开发者只需要处理得到的data就可以了。

注:

1、监听器不支持UI线程,在监听回调中请不要直接操作UI;

2、如果你要监听User、Installation等系统表的话,表名前需要加上“_”,例如:_User

监听数据

在BmobRealTimeData对象连接成功后,就可以进行数据的监听了。BmobSDK提供了监听表和行的方法如下:

// 监听表更新
rtd.subTableUpdate(tableName);
// 监听表删除
rtd.subTableDelete(tableName);
// 监听行更新
rtd.subRowUpdate(tableName, objectId);
// 监听行删除
rtd.subRowDelete(tableName, objectId);

其中tableName为要监听的数据表名,objectId为要监听的数据行Id, 通常比较保险的做法是在BmobRealTimeData对象的连接状态为true的情况下进行监听,代码如下:

if(rtd.isConnected()){
    // 监听表更新
    rtd.subTableUpdate(tableName);
}

取消监听

当开发者想取消监听某个行为是,可使用下面的方法:

// 取消监听表更新
rtd.unsubTableUpdate(testTableName);
// 取消监听表删除
rtd.unsubTableDelete(testTableName);
// 取消监听行更新
rtd.unsubRowUpdate(testTableName, objectId);
// 取消监听行删除
rtd.unsubRowDelete(testTableName, objectId);

用户管理

用户是一个应用程序的核心。对于个人开发者来说,自己的应用程序积累到越多的用户,就会给自己带来越强的创作动力。因此Bmob提供了一个专门的用户类——BmobUser来自动处理用户账户管理所需的功能。

有了这个类,你就可以在你的应用程序中添加用户账户功能。

BmobUser是BmobObject的一个子类,它继承了BmobObject所有的方法,具有BmobObject相同的功能。不同的是,BmobUser增加了一些特定的关于用户账户管理相关的功能。

属性

BmobUser除了从BmobObject继承的属性外,还有几个特定的属性: username: 用户的用户名(必需)。 password: 用户的密码(必需)。 email: 用户的电子邮件地址(可选)

扩展用户类

很多时候,你的用户表还会有很多其他字段,如性别、年龄、头像等。那么,你需要对BmobUser类进行扩展,添加一些新的属性。示例代码如下所示:

public class SpecialUser extends BmobUser {

    private boolean sex;
    private String nick;

    public boolean getSex() {
        return this.sex;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public String getNick() {
        return this.sex;
    }

    public void setNick(String nick) {
        this.nick = nick;
    }
}

更多代码实现大家可以下载SDK,在里面的BmobExample中查找MyUser类,参考它的用法。

创建用户对象

创建用户对象如下:

BmobUser user = new BmobUser();

注册用户

你的应用程序可能会要求用户注册。下面的代码是一个典型的注册过程:

BmobUser bu = new BmobUser();
bu.setUsername("sendi");
bu.setPassword("123456");
bu.setEmail("sendi@163.com");
bu.signUp(this, new SaveListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("注册成功:");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("注册失败:"+msg);
    }
});

在注册过程中,服务器会对注册用户信息进行检查,以确保注册的用户名和电子邮件地址是独一无二的。此外,对于用户的密码,你可以在应用程序中进行相应的加密处理后提交。

如果注册不成功,你可以查看返回的错误对象。最有可能的情况是,用户名或电子邮件已经被另一个用户注册。这种情况你可以提示用户,要求他们尝试使用不同的用户名进行注册。

你也可以要求用户使用Email做为用户名注册,这样做的好处是,你在提交信息的时候可以将输入的“用户名“默认设置为用户的Email地址,以后在用户忘记密码的情况下可以使用Bmob提供重置密码功能。

这里有两点需要注意的:

  • 有些时候你可能需要在用户注册时发送一封验证邮件,以确认用户邮箱的真实性。这时,你只需要登录自己的应用管理后台,在应用设置->邮件设置(下图)中把“邮箱验证”功能打开,Bmob云后端就会在注册时自动发动一封验证给用户。

  • username字段是大小写敏感的字段,如果你希望应用的用户名不区分大小写,请在注册和登录时进行大小写的统一转换。

登录用户

当用户注册成功后,您需要让他们以后能够用注册的用户名登录到他们的账户使用应用。要做到这一点,你可以使用BmobUser类的login方法。

BmobUser bu2 = new BmobUser();
bu2.setUsername("lucky");
bu2.setPassword("123456");
bu2.login(this, new SaveListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("登录成功:");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("登录失败:"+msg);
    }
});

获取当前用户

如果用户在每次打开你的应用程序时都要登录,这将会直接影响到你应用的用户体验。为了避免这种情况,你可以使用缓存的CurrentUser对象。

每当你应用的用户注册成功或是第一次登录成功,都会在本地磁盘中有一个缓存的用户对象,这样,你可以通过获取这个缓存的用户对象来进行登录:

BmobUser bmobUser = BmobUser.getCurrentUser(this);
if(bmobUser != null){
    // 允许用户使用应用
}else{
    //缓存用户对象为空时, 可打开用户注册界面…
}

在扩展了用户类的情况下获取当前登录用户,可以使用如下的示例代码(SpecialUser类可参看上面):

SpecialUser userInfo = BmobUser.getCurrentUser(this,SpecialUser.class);

退出登录

退出登录非常简单,可以使用如下的代码:

BmobUser.logOut(this);   //清除缓存用户对象
BmobUser currentUser = BmobUser.getCurrentUser(this); // 现在的currentUser是null了

更新用户

很多情况下你可能需要修改用户信息,比如你的应用具备修改个人资料的功能,Bmob提供的用户更新方式有两种写法:

第一种:新建一个用户对象,并调用update(context,objectId,updateListener)方法来更新(推荐使用),示例:

BmobUser newUser = new BmobUser();
newUser.setEmail("xxx@163.com");
BmobUser bmobUser = BmobUser.getCurrentUser(this);
newUser.update(this,bmobUser.getObjectId(),new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("更新用户信息成功:");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("更新用户信息失败:" + msg);
    }
});

第二种:获取本地的用户对象,并调用update(context,updateListener)方法来更新(不推荐使用),示例:

BmobUser bmobUser = BmobUser.getCurrentUser(this);
// 修改用户的邮箱为xxx@163.com
bmobUser.setEmail("xxx@163.com");
bmobUser.update(this,new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("更新用户信息成功:");
    }
    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("更新用户信息失败:" + msg);
    }
});

1、开发者在进行用户更新操作的时候,推荐使用第一种方式来进行用户的更新操作,因为此方法只会更新你提交的用户信息(比如只会向服务器提交当前用户的email值),而不会将本地存储的用户信息也提交到后台更新。

2、在更新用户信息时,如果用户邮箱有变更并且在管理后台打开了邮箱验证选项的话,Bmob云后端同样会自动发一封邮件验证信息给用户。

查询用户

查询用户和查询普通对象一样,只需指定BmobUser类即可,如下:

BmobQuery<BmobUser> query = new BmobQuery<BmobUser>();
query.addWhereEqualTo("username", "lucky");
query.findObjects(this, new FindListener<BmobUser>() {
    @Override
    public void onSuccess(List<BmobUser> object) {
        // TODO Auto-generated method stub
        toast("查询用户成功:"+object.size());
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询用户失败:"+msg);
    }
});

浏览器中查看用户表

User表是一个特殊的表,专门存储BmobUser对象。在浏览器端,你会看到一个User表旁边有一个小人的图标。

密码重置

一旦你引入了一个密码系统,那么肯定会有用户忘记密码的情况。对于这种情况,我们提供了一种方法,让用户安全地重置起密码。

重置密码的流程很简单,开发者只需要求用户输入注册的电子邮件地址即可:

final String email = "xxx@163.com";
BmobUser.resetPassword(this, email, new ResetPasswordListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("重置密码请求成功,请到" + email + "邮箱进行密码重置操作");
    }
    @Override
    public void onFailure(int code, String e) {
        // TODO Auto-generated method stub
        toast("重置密码失败:" + e);
    }
});

密码重置流程如下:

  1. 用户输入他们的电子邮件,请求重置自己的密码。
  2. Bmob向他们的邮箱发送一封包含特殊的密码重置连接的电子邮件。
  3. 用户根据向导点击重置密码连接,打开一个特殊的Bmob页面,根据提示他们可以输入一个新的密码。
  4. 用户的密码已被重置为新输入的密码。

找回密码

为方便大家了解如何用Bmob开发找回密码的功能,我们为大家准备了另外一份文档,详细见我们在Github中的文档:

https://github.com/bmob/bmob-cloudcode-demo/blob/master/HOW-TO-FIND-PASSWORD.md

邮箱验证

设置邮件验证是一个可选的应用设置, 这样可以对已经确认过邮件的用户提供一部分保留的体验,邮件验证功能会在用户(User)对象中加入emailVerified字段, 当一个用户的邮件被新添加或者修改过的话,emailVerified会被默认设为false,如果应用设置中开启了邮箱认证功能,Bmob会对用户填写的邮箱发送一个链接, 这个链接可以把emailVerified设置为 true.

emailVerified 字段有 3 种状态可以考虑:

  • true : 用户可以点击邮件中的链接通过Bmob来验证地址,一个用户永远不会在新创建这个值的时候显示emailVerified为true。
  • false : 用户(User)对象最后一次被刷新的时候, 用户并没有确认过他的邮箱地址, 如果你看到emailVerified为false的话,你可以考虑刷新用户(User)对象。
  • missing : 用户(User)对象已经被创建,但应用设置并没有开启邮件验证功能; 或者用户(User)对象没有email邮箱。

请求验证Email

发送给用户的邮箱验证邮件会在一周内失效,可以通过调用 requestEmailVerify 来强制重新发送:

final String email = "xxx@qq.com";
BmobUser.requestEmailVerify(this, email, new EmailVerifyListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("请求验证邮件成功,请到" + email + "邮箱中进行激活。");
    }
    @Override
    public void onFailure(int code, String e) {
        // TODO Auto-generated method stub
        toast("请求验证邮件失败:" + e);
    }
});

第三方账号登陆

Bmob提供了非常简单的方法来实现使用第三方账号登陆的功能,目前支持新浪微博、QQ账号的登陆。

新浪微博账号登陆

使用新浪微博账号登陆,需要先在新浪微博开放平台中创建应用并得到appkey和redirectUrl,在新浪微博开放平台创建应用的步骤可以参考新浪微博提供的开发文档。然后将新浪微博提供的SDK和BmobSDK一样放入自己项目的libs目录中。接下来就是在程序中调用BmobSDK提供的方法了。示例代码如下:

BmobUser.weiboLogin(this, "appkey", "redirectUrl", new OtherLoginListener() {
    @Override
    public void onSuccess(JSONObject userAuth) {
        // TODO Auto-generated method stub
        toast("第三方登陆成功:"+userAuth);
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("第三方登陆失败:"+msg);
    }
});

QQ账号登陆

使用QQ账号登陆,同样也需要在腾讯开放平台中创建应用并得到appid,在腾讯开放平台创建应用的步骤可以参考腾讯开放平台提供的开发文档。然后将腾讯提供的SDK和BmobSDK一样放入自己项目的libs目录中。使用腾讯SDK还需要在AndroidManifest.xml文件中添加相应的配置如下:

<!-- qq回调需要注册该activity -->
<activity
    android:name="com.tencent.connect.common.AssistActivity"
    android:configChanges="orientation|keyboardHidden"
    android:screenOrientation="portrait"
    android:theme="@android:style/Theme.Translucent.NoTitleBar" />

<!-- qq授权需要注册该activity -->
<activity
    android:name="com.tencent.tauth.AuthActivity"
    android:launchMode="singleTask"
    android:noHistory="true" >
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />

        <data android:scheme="tencent你的AppId" />
    </intent-filter>
</activity>

最后是在程序中调用BmobSDK提供的方法了,示例代码如下:

BmobUser.qqLogin(this, "appid", new OtherLoginListener() {
    @Override
    public void onSuccess(JSONObject userAuth) {
        // TODO Auto-generated method stub
        toast("第三方登陆成功:"+userAuth.toString());
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("第三方登陆失败:"+msg);
    }
});

第三方账号与BmobUser绑定

如果你的应用中有其他功能已经使用到了相关第三方平台的功能,比如社交分享功能,那么你可以将已经得到的用户授权信息传递给BmobSDK来便捷地与BmobUser进行绑定。以下代码展示了将第三方账号和已经存在的BmobUser对象进行绑定:

BmobUser.associateWithAuthDate(this, BmobUser.getCurrentUser(this), userAuth, new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub

    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub

    }
});

以上代码中的参数userAuth是由开发者构造的JSONObject格式的第三方平台授权信息,相关平台的授权信息格式如下所示: 新浪微博的userAuth内容:

{"weibo": {
      "uid": "145785469",
            "access_token": "2.00vs9yFCI8FrHCba4951pdq5vn1slZ",
            "expiration_in": "78000"
    }
}

QQ的userAuth内容:

{"qq": {
      "openid": "AAC61872C459FB196AECFA9D6FEBA334",
      "access_token": "19A1E9FB3E440B4D15DBB44a39946FD4",
      "expires_in": 7776000
    }
}

解除绑定

解除第三方账号与BmobUser的绑定关系如下代码所示:

BmobUser.dissociateAuthData(this, BmobUser.getCurrentUser(this), new UpdateListener() {
    @Override
    public void onSuccess() {
        // TODO Auto-generated method stub
        toast("解除绑定成功");
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("解除绑定失败:"+msg);
    }
});

第三方登录的案例源码

大家可以下载我们提供的案例源码:https://github.com/bmob/bmob-android-demo-thirdpartylogin 这个源码包含了第三方登录的源码和登录之后如何获取用户基本信息的部分。

ACL和角色

数据安全是软件系统中最重要的组成部分,为了更好的保护应用数据的安全,Bmob在软件架构层面提供了应用层次、表层次、ACL(Access Control List:访问控制列表)、角色管理(Role)四种不同粒度的权限控制的方式,确保用户数据的安全(详细请查看Bmob数据与安全页面,了解Bmob如何保护数据安全)。

其中,最灵活的方法是通过ACL和角色,它的思路是每一条数据有一个用户和角色的列表,以及这些用户和角色拥有什么样的许可权限。

大多数应用程序需要对不同的数据进行灵活的访问和控制,这就可以使用Bmob提供的ACL模式来实现。例如:

  • 对于私有数据,读写权限可以只局限于数据的所有者。
  • 对于一个论坛,会员和版主有写的权限,一般的游客只有读的权限。
  • 对于日志数据只有开发者才能够访问,ACL可以拒绝所有的访问权限。
  • 属于一个被授权的用户或者开发者所创建的数据,可以有公共的读的权限,但是写入权限仅限于管理者角色。
  • 一个用户发送给另外一个用户的消息,可以只给这些用户赋予读写的权限。

用Bmob SDK,你可以对这些数据设置一个默认的ACL,这样,即使黑客反编译了你的应用,获取到Application Key,也仍然无法操作和破坏你的用户数据,确保了用户数据的安全可靠。而作为开发者,当你需要对这些数据进行管理时,可以通过超级权限Key(Master Key)进行。

默认访问权限

在没有显示指定的情况下,每一个BmobObject(表)中的ACL(列)属性的默认值是所有人可读可写的。在客户端想要修改这个权限设置,只需要简单调用BmobACL的setPublicReadAccess方法和setPublicWriteAccess方法,即:

BmobACL aCL = new BmobACL();

aCL.setPublicReadAccess(true);

aCL.setPublicWriteAccess(true);

注意:可读可写是默认的权限,不需要写额外的代码。

指定用户的访问权限

假如你想实现一个分享日志类的应用时,这可能会需要针对不同的日志设定不同的访问权限。比如,公开的日志,发布者有更改和修改的权限,其他用户只有读的权限,那么可用如下代码实现:

Blog blog = new Blog();
blog.setTitle("论电影的七个元素");
blog.setContent("这是blog的具体内容");

BmobACL acl = new BmobACL();    //创建一个ACL对象
acl.setPublicReadAccess(true);    // 设置所有人可读的权限
acl.setWriteAccess(BmobUser.getCurrentUser(this), true);   // 设置当前用户可写的权限

blog.setACL(acl);    //设置这条数据的ACL信息
blog.save(this, new SaveListener() {
    @Override
    public void onSuccess() {
        //添加成功
    }

    @Override
    public void onFailure(int code, String msg) {
        //添加失败
    }
});

有时,用户想发表一篇不公开的日志,这种情况只有发布者才对这篇日志拥有读写权限,相应的代码如下:

Blog blog = new Blog();
blog.setTitle("一个人的秘密");
blog.setContent("这是blog的具体内容");

BmobACL acl = new BmobACL();  //创建ACL对象
acl.setReadAccess(BmobUser.getCurrentUser(this), true); // 设置当前用户可写的权限
acl.setWriteAccess(BmobUser.getCurrentUser(this), true); // 设置当前用户可写的权限

blog.setACL(acl);    //设置这条数据的ACL信息
blog.save(this, new SaveListener() {
    @Override
    public void onSuccess() {
        //添加成功
    }

    @Override
    public void onFailure(int code, String msg) {
        //添加失败
    }
});

角色管理

上面的指定用户访问权限虽然很方便,但是对于有些应用可能会有一定的局限性。比如一家公司的工资系统,员工和公司的出纳们只拥有工资的读权限,而公司的人事和老板才拥有全部的读写权限。要实现这种功能,你也可以通过设置每个用户的ACL权限来实现,如下:


//创建公司某用户的工资对象
WageInfo wageinfo = new WageInfo();
wageinfo.setWage(100000);   

//这里创建四个用户对象,分别为老板、人事小张、出纳小谢和自己
BmobUser boss;
BmobUser hr_zhang;
BmobUser cashier_xie;
BmobUser me;

//创建ACL对象
BmobACL acl = new BmobACL();

//设置四个用户读的权限
acl.setReadAccess(boos, true);    
acl.setReadAccess(hr_zhang, true);
acl.setReadAccess(cashier_xie, true);
acl.setReadAccess(me, true);

//设置老板和人事小张对这个工资的写权限
acl.setWriteAccess(boss, true);
acl.setWriteAccess(hr_zhang, true);

//设置工资对象的ACL
wageinfo.setACL(acl);
wageinfo.save(this, new SaveListener() {
    @Override
    public void onSuccess() {
        //保存成功
    }

    @Override
    public void onFailure(int code, String msg) {
        //保存失败
    }
});

但是,一个公司的人事、出纳和员工不仅仅只有一个人,同时还会有离职、调换岗位以及新员工加入等问题存在。如果用上面的代码对公司的每个人进行一一设置的话是不现实的,既麻烦也很难维护。针对这个问题,我们可以利用BmobRole来解决。我们只需要对用户进行分类,每个分类赋予不同的权限。如下代码实现:

//创建公司某用户的工资对象
WageInfo wageinfo = new WageInfo();
wageinfo.setWage(100000);

//这里创建四个用户对象,分别为老板、人事小张、出纳小谢和自己
BmobUser boss;
BmobUser hr_zhang;
BmobUser hr_luo;
BmobUser cashier_xie;
BmobUser me;

//创建HR和Cashier两个用户角色(这里为了举例BmobRole的使用,将这段代码写在这里,正常情况下放在员工管理界面会更合适)
BmobRole hr = new BmobRole("HR");
BmobRole cashier = new BmobRole("Cashier");

//将hr_zhang和hr_luo归属到hr角色中
hr.getUsers().add(hr_zhang);
hr.getUsers().add(hr_luo);
//保存到云端角色表中(web端可以查看Role表)
hr.save(this);  

//将cashier_xie归属到cashier角色中
cashier.getUsers().add(cashier_xie);
//保存到云端角色表中(web端可以查看Role表)
cashier.save(this);

//创建ACL对象
BmobACL acl = new BmobACL();
acl.setReadAccess(boos, true); // 假设老板只有一个, 设置读权限
acl.setReadAccess(me, true); // 给自己设置读权限
acl.setRoleReadAccess(hr, true); // 给hr角色设置读权限
acl.setRoleReadAccess(cashier, true); // 给cashier角色设置读权限

acl.setWriteAccess(boss, true); // 设置老板拥有写权限
acl.setRoleWriteAccess(hr, true); // 设置ht角色拥有写权限

//设置工资对象的ACL
wageinfo.setACL(acl);
wageinfo.save(this);

需要说明一点的是,Web端的Role表也具有ACL的列,你可以将角色管理的权限赋予某些用户。

角色之间的从属关系

下面我们来说一下角色与角色之间的从属关系。用一个例子来说明下:一个互联网企业有移动部门,部门中有不同的小组,如Android开发组和IOS开发组。每个小组只拥有自己小组的代码读写权限,但这两个小组同时拥有核心库代码的读权限。

//创建MobileDep(移动研发部)、AndroidTeam(android开发组)和iOSTeam(ios开发组)三个角色
BmobRole mobileDep = new BmobRole("MobileDep");
BmobRole androidTeam = new BmobRole("AndroidTeam");
BmobRole iosTeam = new BmobRole("iOSTeam");

//保存AndroidTeam和iosTeam角色到云端
androidTeam.save(this);
iosTeam.save(this);

//将androidTeam和iosTeam两种角色添加到移动部门角色中
mobileDep.getRoles().add(androidTeam);
mobileDep.getRoles().add(iosTeam);
mobileDep.save(this);

// 假设创建三个代码数据对象
Code coreCode = new Code();
Code androidCode = new Code();
Code iosCode = new Code();

//......此处省略一些具体的属性设定

coreCode.save(this);
androidCode.save(this);
iosCode.save(this);

//设置androidTeam角色对androidCode对象的读和写的权限
androidCode.setRoleReadAccess(androidTeam, true);
androidCode.setRoleWriteAccess(androidTeam, true);

//设置iosTeam角色对iosCode对象的读和写的权限
iosCode.setRoleReadAccess(iosTeam, true);
iosCode.setRoleWriteAccess(iosTeam, true);

//设置mobileDep角色可以对coreCode对象进行读操作
coreCode.setRoleReadAccess(mobileDep);

ACL案例源码

我们为大家提供一个ACL相关的案例源码,大家可以点击下载:https://github.com/bmob/bmob-android-demo-acl

地理位置

Bmob允许用户根据地球的经度和纬度坐标进行基于地理位置的信息查询。通过在BmobObject的查询中添加一个BmobGeoPoint的对象查询,你就可以实现轻松查找出离当前用户最接近的信息或地点的功能。

创建地理位置对象

首先需要创建一个BmobGeoPoint对象。例如,创建一个东经116.39727786183357度,北纬39.913768382429105度的BmobGeoPoint对象:

BmobGeoPoint point = new BmobGeoPoint(116.39727786183357, 39.913768382429105);

查询地理位置信息

现在,你的数据表中有了一定的地理坐标对象的数据,这样可以测试找出最接近某个点的信息了。你可以使用BmobQuery对象的addWhereNear方法来这样做:

BmobQuery<Person> bmobQuery = new BmobQuery<Person>();
bmobQuery.addWhereNear("gpsAdd", new BmobGeoPoint(112.934755, 24.52065));
bmobQuery.setLimit(10);    //获取最接近用户地点的10条数据
bmobQuery.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共" + object.size() + "条数据。");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:" + msg);
    }
});

要限制查询指定距离范围的数据可以使用addWhereWithinKilometersaddWhereWithinMilesaddWhereWithinRadians方法。

要查询一个矩形范围内的信息可以使用addWhereWithinGeoBox来实现:

BmobGeoPoint southwestOfSF = new BmobGeoPoint(116.10675, 39.711669);
BmobGeoPoint northeastOfSF = new BmobGeoPoint(116.627623, 40.143687);
BmobQuery<Person> query = new BmobQuery<Person>();
query.addWhereWithinGeoBox("gpsAdd", southwestOfSF, northeastOfSF);
query.findObjects(this, new FindListener<Person>() {
    @Override
    public void onSuccess(List<Person> object) {
        // TODO Auto-generated method stub
        toast("查询成功:共" + object.size() + "条数据。");
    }
    @Override
    public void onError(int code, String msg) {
        // TODO Auto-generated method stub
        toast("查询失败:" + msg);
    }
});

注意事项 目前有几个需要注意的地方:

  1. 每个BmobObject数据对象中只能有一个BmobGeoPoint对象。

  2. 地理位置的点不能超过规定的范围。纬度的范围应该是在-90.0到90.0之间。经度的范围应该是在-180.0到180.0之间。如果您添加的经纬度超出了以上范围,将导致程序错误。

云端代码的调用

很多时候,单纯的前端代码是不能完成全部事情的,一些重要和复杂的业务逻辑还是希望能够在服务端中执行。比如:对比较大量的比赛数据进行排序,对某个网站进行资料采集和处理,获取用户的IP信息,等等。Bmob不仅提供了云端存储,还开放了云端的业务逻辑代码功能,也就是云端代码。

相关云端代码的使用,大家可以参考开发文档: http://docs.bmob.cn/cloudcode/developdoc/index.html?menukey=develop_doc&key=develop_cloudcode

云端代码的执行有多种方法:

其中,在SDK中调用云端代码的方法如下:

AsyncCustomEndpoints ace = new AsyncCustomEndpoints();
//第一个参数是上下文对象,第二个参数是云端代码的方法名称,第三个参数是上传到云端代码的参数列表(JSONObject cloudCodeParams),第四个参数是回调类
ace.callEndpoint.callEndpoint(MainActivity.this, cloudCodeName, params, 
    new CloudCodeListener() {
            @Override
            public void onSuccess(Object object) {
                // TODO Auto-generated method stub
                toast("云端usertest方法返回:" + object.toString());
            }
            @Override
            public void onFailure(int code, String msg) {
                // TODO Auto-generated method stub
                toast("访问云端usertest方法失败:" + msg);
            }
        });

消息推送

消息推送简介

推送通知是让用户及时被通知、和你的应用保持联系的一种非常棒的方式,你可以快速而有效地通知到所有的用户,下面这个教程将会教你如何使用Bmob来推送消息。

消息推送快速入门

一、在Bmob官方网站的下载界面中,选择下载AndroidSDK,将下载的zip压缩包进行解压,得到bmobPush_(版本号).jar,然后将它放在你项目根目录下的"libs"目录中。

二、在您的应用程序AndroidManifest.xml文件中添加相应的权限:

<!-- BmobPush SDK权限 -->
    <permission android:protectionLevel="normal" android:name="cn.bmob.permission.push"></permission>
    <uses-permission android:name="cn.bmob.permission.push"/><!-- 添加自定义的权限-->
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />    
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_USER_PRESENT" />

三、在您的应用程序AndroidManifest.xml文件中注册BmobPush SDK运行所需的推送服务和消息接收器:

    <service
               android:label="PushService"
            android:name="cn.bmob.push.lib.service.PushService"
            android:process="cn.bmob.push"
            android:permission="cn.bmob.permission.push"
            android:exported="true">
             <intent-filter>
                 <action android:name="cn.bmob.push.lib.service.PushService"/>
             </intent-filter>
        </service>

        <receiver android:name="cn.bmob.push.PushReceiver" >
            <intent-filter android:priority="2147483647" ><!--优先级加最高-->
                <!-- 系统启动完成后会调用 -->
                <action android:name="android.intent.action.BOOT_COMPLETED" />               
                <!-- 解锁完成后会调用 -->
                <action android:name="android.intent.action.USER_PRESENT" />
                <!-- 监听网络连通性 -->
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />               
            </intent-filter>
        </receiver>

四、在你的应用程序中创建一个消息接收器。

Push消息通过action=cn.bmob.push.action.MESSAGE的Intent把数据发送给客户端your.package.MyPushMessageReceiver,消息格式由应用自己决定,PushService只负责把服务器下发的消息以字符串格式透传给客户端。 your.package.MyPushMessageReceiver代码示例如下:

public class MyPushMessageReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        if(intent.getAction().equals(PushConstants.ACTION_MESSAGE)){
            Log.d("bmob", "客户端收到推送内容:"+intent.getStringExtra(PushConstants.EXTRA_PUSH_MESSAGE_STRING));
        }
    }

}

五、启动推送服务

在你的应用程序主Activity中调用如下方法:

    // 使用推送服务时的初始化操作
    BmobInstallation.getCurrentInstallation(this).save();
    // 启动推送服务
    BmobPush.startWork(this, "你的AppKey");

代码中的"你的AppKey"就是你在Bmob后台中创建的应用程序的AppKey,如果你不知道这是什么,可以参考快速入门文档中的注册Bmob账号部分。

六、在web端进行推送设置

在应用面板-->消息推送-->推送设置界面中填写包名进行保存。 

七、在web端推送消息

完成以上步骤后,你可以运行应用程序,从web推送一条消息给客户端。 

在后台推送消息给Android和iOS两个平台的时候,有一些需要注意的: 1、由于Android和iOS的提送机制不同,iOS要经过APNS,Android的推送完全是走Bmob的长连接服务,为兼容这个问题,如果你选择发送格式为“json”格式时,需要添加APNS兼容头部(见下面json的aps部分),推送内容格式如下:

{
    "aps": {
    "sound": "cheering.caf", 
    "alert": "这个是通知栏上显示的内容", 
    "badge": 0 
    }, 
    "xx" : "json的key-value对,你可以根据情况添加更多的,客户端进行解析获取", 
}

其中,sound是iOS接收时的声音,badge是iOS通知栏的累计消息数。

2、如果你选择发送格式为“text”时,推送内容为“推送消息测试。。。。”,Bmob会自动添加aps部分发送给APNS,,相当于自动生成如下的json格式的推送内容:

{
    "aps": {
        "alert": "推送消息测试。。。。", 
    }
}

同时,也会发送给Android端,相当于自动生成如下的json格式的推送内容:

{
    "alert" : "推送消息测试。。。。", 
}

3、如果只是发送给Android端,大家可以自定义json格式的数据。

4、由于iOS的APNS的推送的大小是有限制的,默认最多256bytes,因此,如果你需要跨平台互通的话,需注意推送的内容不要太长。

5、想要更多了解Bmob的推送格式的朋友,如即时聊天,可以查看我们在问答社区中的回答:http://wenda.codenow.cn//?/question/204

八、源码下载

为了更好的让开发者朋友正确的集成和使用Bmob推送功能,我们还提供了一个关于Bmob推送功能的简单Demo以供大家参考,有需要的朋友可以到如下地址进行源码的下载。https://github.com/bmob/bmob-android-demo-push

消息推送的视频教程和Demo

Bmob官方为大家准备了消息推送的视频教程,有需要的朋友可以移步浏览视频教程:

客户端推送消息:http://v.youku.com/v_show/id_XNzQ4ODczOTc2.html

集成BmobPushSDK:http://v.youku.com/v_show/id_XNzQ4ODczOTc2.html

其他相关说明

以上文档仅仅介绍了如何实现消息的一次性推送,如果你还需要用到其他的推送方法,如组播、广播等,还需要详细阅读下面的相关知识。

安装消息推送服务

每一个Bmob的App被安装在用户的设备上后,如果要使用消息推送功能,Bmob SDK会自动生成一个Installation对象。Installation对象包含了推送所需要的所有信息。举例:一个棒球的App,你可以让用户订阅感兴趣的棒球队,然后及时将这个球队的消息推送给用户 。 您可以使用 BmobSDK,通过 BmobInstallation 对象进行一系列操作,就像你存储和获取其他的普通对象一样,比如BmobObject对象。

BmobInstallation对象有几个系统默认的特殊字段来帮助你进行设备定位等管理:

  • channels : 当前这个设备订阅的渠道名称数组
  • timeZone : 设备所在位置的时区, 如Asia/Shanghai,这个会在每个BmobInstallation对象更新时同步(只读)
  • deviceType : 设备的的类型, 值为:"ios" 或 "android" (只读)
  • installationId : Bmob使用的设备唯一号 (只读)
保存 installation

使用消息推送前,首先需要保存设备信息。

BmobInstallation.getCurrentInstallation(this).save();

你还可以通过定义继承自BmobInstallation的JavaBean来为BmobInstallation对象添加更多的属性,用来定制更通用的推送。

public class MyBmobInstallation extends BmobInstallation {
    private int score;

    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
}

订阅频道和退订

订阅频道

订阅频道可使用 subscribe 方法

BmobInstallation installation = BmobInstallation.getCurrentInstallation(this);
installation.subscribe("Giants");
installation.subscribe("Mets");
installation.save();
退订频道

退订频道可使用 unsubscribe 方法

BmobInstallation installation = BmobInstallation.getCurrentInstallation(this);
installation.unsubscribe("Giants");
installation.save();

广播推送消息

在客户端实现推送消息的功能,通过 BmobPushManager 对象来完成,比如给所有设备推送一条消息,如下:

BmobPushManager bmobPush = new BmobPushManager(this);
bmobPush.pushMessageAll("Hello Bmob.");

组播推送消息

发送消息给订阅了Giants频道的用户

BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
List<String> channels = new ArrayList<String>();
channels.add("Giants");

query.addWhereEqualTo("channels", channels);
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

同时发送消息给多个频道时,可以将其他频道添加在channels中。

多播推送消息

推送给不活跃的用户
BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereLessThan("updatedAt", new BmobDate(new Date()));
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");
根据查询条件做推送
BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereEqualTo("score", 80);
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

请注意,where 条件查询的都是 installations 表。这里是假设 installations 表存储了 score 的Number属性,你可以像查询普通对象一样构造where查询

根据平台做推送

给Android平台的终端推送

BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereEqualTo("deviceType", "android");
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

给IOS平台的终端推送

BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereEqualTo("deviceType", "ios");
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");
根据地理位置信息做推送
BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereWithinRadians("location", new BmobGeoPoint(112.934755, 24.52065), 1.0);
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

上面的例子假设 installation 表中有个 location 属性是 GeoPoint 类型,我们就可以根据地理信息位置做推送。

点播推送消息

发送给Android单个客户端

String installationId = "客户端installationId";
BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereEqualTo("installationId", installationId);
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

发送给iOS单个客户端

String deviceToken = "客户端deviceToken";
BmobPushManager bmobPush = new BmobPushManager(this);
BmobQuery<BmobInstallation> query = BmobInstallation.getQuery();
query.addWhereEqualTo("deviceToken", deviceToken);
bmobPush.setQuery(query);
bmobPush.pushMessage("消息内容");

短信服务

由于Bmob官方对外提供的服务都是免费的,而短信服务产生的费用我们无法把控,因此短信服务的功能我们没有直接对外提供,而主要针对有需要的合作客户。如果你有这方面的需要,可以联系我们的技术客服琪琪(QQ:2395453054)。

短信服务的功能包括:

  • 短信验证码服务(注册和找回密码等);
  • 短信模板服务(需要你先设定短信模板,方便运营商审核,不支持法律禁止或者与政策相违背的短信服务);
  • 可自定义短信后缀,如“尊敬的*,你购买的商品已经在快递中,请注意查收。【Bmob快递】”,其中Bmob快递就是短信后缀,可以替换为你的公司名称。

其他功能

获取服务器时间

在Bmob对象中提供了一个静态方法,用于获取服务器时间。

Bmob.getServerTime(MainActivity.this, new GetServerTimeListener() {
    @Override
    public void onSuccess(long time) {
        // TODO Auto-generated method stub
        SimpleDateFormat formatter = new SimpleDateFormat(
                "yyyy-MM-dd HH:mm");
        String times = formatter.format(new Date(time * 1000L));
        toast("当前服务器时间为:" + times);
    }

    @Override
    public void onFailure(int code, String msg) {
        // TODO Auto-generated method stub
        toast("获取服务器时间失败:" + msg);
    }
});

自动更新组件

Bmob为大家提供了应用的自动更新组件,使用这个组件可以快速方便实现应用的自动升级功能。 详细的使用操作可以参考文档:http://docs.bmob.cn/android/autoupdate/index.html?menukey=otherdoc&key=autoupdate

错误码列表

由于Android SDK是基于RestApi接口实现的,因此,以下只提供与Android相关的错误码,如果你在开发过程中发现有其他的错误码,请点击查看我们的RestFul开发文档中提供的错误码文档:http://docs.bmob.cn/errorcode/index.html?menukey=otherdoc&key=errorcode

9001

内容:AppKey is Null, Please initialize BmobSDK.

含义:AppKey为空,请初始化。

9002

内容:Parse data error

含义:解析返回数据出错

9003

内容:upload file error

含义:上传文件出错

9004

内容:upload file failure

含义:文件上传失败

9005

内容:A batch operation can not be more than 50

含义:批量操作只支持最多50条

9006

内容:objectId is null

含义:objectId为空

9007

内容:BmobFile File size must be less than 10M.

含义:文件大小超过10M

9008

内容:BmobFile File does not exist.

含义:上传文件不存在

9009

内容:No cache data.

含义:没有缓存数据

9010

内容:The network is not normal.(Time out)

含义:网络超时

9011

内容:BmobUser does not support batch operations.

含义:BmobUser类不支持批量操作

9012

内容:context is null.

含义:上下文为空

9013

内容: BmobObject Object names(database table name) format is not correct.

含义:BmobObject(数据表名称)格式不正确

9014

含义:第三方账号授权失败

9015

含义:其他错误均返回此code

9016

内容:The network is not available,please check your network!

含义:无网络连接,请检查您的手机网络。

混淆打包的相关问题

由于Bmob Android SDK本身进行了代码混淆,因此,你在给应用打包编译混淆时,请不要混淆BmobSDK的代码,另外,任何继承自BmobObject、BmobUser的JavaBean请不要混淆。具体可参考BmobExample中proguard-project.txt的代码:

-ignorewarnings
# 这里根据具体的SDK版本修改
-libraryjars libs/bmob_v3.0.9beta.jar

-keepattributes Signature
-keep class cn.bmob.v3.** {*;}

# 保证继承自BmobObject、BmobUser类的JavaBean不被混淆
-keep class com.example.bmobexample.Person{*;}
-keep class com.example.bmobexample.MyUser{*;}
-keep class com.example.bmobexample.relationaldata.Weibo{*;}
-keep class com.example.bmobexample.relationaldata.Comment{*;}



代码不复制来。、
我仿写到该代码:代码

可以参考视频教程:http://www.imooc.com/learn/254