【Android】Firebase配置与使用(上)

来源:互联网 发布:大型体育赛事数据服务 编辑:程序博客网 时间:2024/04/27 10:21

Firebase是一个支持实时数据库管理、云端存储、推送分发、事件统计、身份验证等功能的强大的后台,常用于各个平台的开发中。

在Android开发中,使用Firebase作为自己的app的后台主要可以分为以下几步:

  1. 为你的app配置Firebase服务
  2. 根据需要设计数据库的结构
  3. 对实时数据库进行增删改查以及持久化操作
  4. 文件上传/下载
  5. #如有需要可以使用Firebase进行事件统计#

接下来对每一步进行介绍:

1.配置Firebase服务

首先,我们需要在Firebase console上添加我们的工程,表示我们的控制台上有这样一个项目需要Firebase提供服务,未来查看数据库结构时也可以从console进入。(以下均在Firebase的官方网站进行操作)

  1. 如果还没有 Firebase 项目,可以在Firebase console 中创建一个。 如果已经有一个与Firebase项目,点击 Import Google Project。
  2. 点击 Add Firebase to your Android app 并按设置步骤进行操作。如果在导入现有 Google 项目,这可能是自动进行的,只需下载配置文件即可。
  3. 出现提示时,输入您的应用的包名称。输入应用使用的包名称十分重要。只有将一个应用添加至 Firebase 项目时才能进行此设置。
  4. 最后,下载一个 google-services.json 文件。我们可以随时重新下载此文件。

注:如果您有多个构建变体含有已定义的不同包名称,则必须在 Firebase console 中将每个应用添加到您的项目。
配置的过程在官方文档中有较为详细的描述,这里仅简单记录一下。

在服务器的控制台添加完我们的工程,接下来需要在我们的工程中导入firebase服务:
在根目录下的build.gradle中添加如下规则,从而导入google服务的插件:

buildscript {    // ...    dependencies {        // ...        classpath 'com.google.gms:google-services:3.0.0'    }}

然后再在module的build.gradle中添加如下代码来启用Gradle插件:

apply plugin: 'com.android.application'android {  // ...}dependencies {  // ...  compile 'com.google.firebase:firebase-core:9.6.1'}// ADD THIS AT THE BOTTOMapply plugin: 'com.google.gms.google-services'

注意:dependencies中编译的库根据需求而变化,官方网站给出了如下的可用库以及其对应的功能的列表:
这里写图片描述
以上Firebase的配置工作就完成了。

2.根据需要设计数据库的结构

Firebase提倡使用JSON文件来代替传统数据库,即把所有的Firebase Realtime Database数据都存储为JSON格式。数据之间的层次通过JSON的嵌套来体现,而不存在传统的表、行、列等。这里可以理解成用JSON格式构建一颗树,每条记录就是树中的一个节点。
值得一提的是,Firebase在设计数据库的时候,不提倡使用多层的嵌套,而提倡使用扁平化的数据结构。例如我们在设计一个聊天应用的数据库时,有两种方式:

{  // 这是一个构建数据库的错误示例,因为在获取“chats”的标题时,我们不得不遍历“chat”下的所有节点   // 这无形中增加了冗余的下载量和作业时间  "chats": {    "one": {      "title": "聊天1",      "messages": {        "m1": { "sender": "张三", "message": "哈哈哈" },        "m2": { ... },        // 一系列的message…      }    },    "two": { ... }  }}

这个结构中,我们可以看到“chats”节点下有许多聊天,各自有title、message等信息。其中“title”嵌套在“one”节点下,如果我们要得到“one”的聊天标题,我们则需要便利完“one”这个节点,包括“message”节点下的所有内容,所以这个工作量是大而不必要的。
正确的做法应该是将数据库展开:

{  "chats": {    "one": {      "title": "聊天1",      "lastMessage": "张三: 哈哈哈",      "timestamp": 1459361875666    },    "two": { ... },    "three": { ... }  },//这个节点记录聊天成员是否被包括在该聊天内  "members": {    "one": {      "张三": true,      "李四": true,      "王五": true    },    "two": { ... },    "three": { ... }  },  "messages": {    "one": {      "m1": {        "name": "张三",        "message": "哈哈哈",        "timestamp": 1459361875337      },      "m2": { ... },      "m3": { ... }    },    "two": { ... },    "three": { ... }  }}

可以看到,这个结构中我们把聊天的每一项属性展开到同一层树,这样获取chats的相关信息的时候就会更为简单,而不进行多余的下载和访问。
以上是设计数据库的一些注意事项。

3.对实时数据库进行增删改查以及持久化操作

为了对实时数据库进行增删改查,Firebase为我们封装好了setValue()、push()、updateChildren()、runTransaction()四种方法,接下来逐一介绍:

setValue()

主要用于一些基本的写入操作。参数可以是JSON可用的数据类型(String,Int,Long,Double,Boolean,Map

private void writeNewUser(String userId, String name, String email) {    User user = new User(name, email);    mDatabase.child("users").child(userId).setValue(user);}

这里的child(var1)表示取节点名为“var1”的节点,由此看来,setValue方法在修改子节点的数据时可以不用重写修改内容无关的节点数据。setValue方法在对既有数据的节点进行操作的时候会覆盖原有的数据,从而修改数据,对没有数据的节点进行操作的时候则会添加数据。

push()

主要用于将数据追加到Json树。如我们在设计一款图片存储app的时候,需要有不同的相册(album)对图片进行分类。新建一个相册的时候,我们可以直接在我们要的节点处push()一个新节点,再对新节点使用setValue设置值。

DatabaseReference ref = getAlbumsHeaderNode().push();//…ref.setValue(album)

其中album代表存放相册属性的Java对象,DatabaseReference为节点类,getAlbumsHeaderNode()得到的是节点“Header”,上述代码在Header节点下面追加了一个子节点,并把album数据放入该节点中。
值得一提的是,push()方法追加节点时会产生一个唯一的ID,这个ID基于时间给出,这也使得多个终端可以对同一个节点进行追加子节点操作。这个ID可以通过getKey()方法获得。

updateChildren()

用于同时更新多个子节点。如果要同时向多个节点的特定子节点写入数据,而不覆盖其他子节点,可以使用该方法。比如:

//先在“post”下创建一个节点,并获取他的IDString key = mDatabase.child("posts").push().getKey();    Post post = new Post(userId, username, title, body);    //将Post对象返回成一个map    Map<String, Object> postValues = post.toMap();    Map<String, Object> childUpdates = new HashMap<>();    childUpdates.put("/node01/" + key, postValues);    childUpdates.put("/node02/" + userId + "/" + key, postValues);    mDatabase.updateChildren(childUpdates);    ...

代码中childUpdates这个map的键是节点名称,值为节点数据。使用updateChildren()同时更新两个节点下的子节点的值。

注意:通过这种方式同步更新具有原子性:要么所有更新全部成功,要么全部失败。
setValue()方法和updateChildren()方法都可以设置回调,来监听更新是否成功,直接在函数后面加.addOnCompleteListener即可。

runTransaction()

这个方法可以防止多个终端对同意数据进行操作的时候产生数据混乱。他的原理是:如果更新操作由于写数据冲突被拒绝,则将当前值返回给客户端,客户端更新数据后重新进行写操作。
例如,在社交博客中,我们可以允许用户对博文加星和取消加星,并跟踪博文获得的加星数,如下所示:

private void onStarClicked(DatabaseReference postRef) {    postRef.runTransaction(new Transaction.Handler() {        @Override        public Transaction.Result doTransaction(MutableData mutableData) {            Post p = mutableData.getValue(Post.class);            if (p == null) {                return Transaction.success(mutableData);            }            if (p.stars.containsKey(getUid())) {                // 取消博文的赞并将用户移出点赞列表                p.starCount = p.starCount - 1;                p.stars.remove(getUid());            } else {                // 为博文点赞,并且将用户加入博文点赞列表                p.starCount = p.starCount + 1;                p.stars.put(getUid(), true);            }            //成功setValue            mutableData.setValue(p);            return Transaction.success(mutableData);        }        @Override        public void onComplete(DatabaseError databaseError, boolean b,                               DataSnapshot dataSnapshot) {            Log.d(TAG, "postTransaction:onComplete:" + databaseError);        }    });}

这里我们在点击星星时,出发了runTransaction方法,这个方法的参数是一个handler,在这个handler中有两个回调:doTransaction和onComplete,后者显然就是在数据修改完成后进行,重点看一下doTransaction()。
这个函数的参数是MutableData的对象,通过阅读文档得知,这个类的作用是封装了某一位置(节点)将要被修改成的数据以及他的优先级——这点很重要。我们使用mutableData.getValue()获得了节点postRef处的Post对象p,对该对象进行一系列判断和点赞/取消赞修改后,将p的值赋给mutableData,最后调用Transaction.success方法将mutableData的值赋给数据库中的节点。
注:由于 doTransaction() 将多次调用,因此必须能够处理 null 数据。 即使远程数据库中已有数据,但在运行事务处理函数时可能不会本地缓存这些数据,从而导致 null 成为初始值。

以上为JSON树的增改操作,删除操作可以通过增改操作或者removeValue方法实现。

数据持久化方面:如果客户端失去网络连接,应用将继续正常运行。
Firebase会在本地创建一个临时数据库,写入数据时,首先将其写入此本地版本。 然后,Firebase 客户端尽最大程度将这些数据与远程数据库服务器以及其他客户端同步。
因此,在将任何数据写入服务器之前,对数据库执行的所有写入会立即触发本地事件。 这意味着应用将保持随时响应,无论网络延迟或连接情况如何均是如此。
在重新建立连接之后,应用将收到一组适当的事件,以便客户端与当前服务器状态同步,而不必编写任何自定义代码。
开启这个离线功能仅需要几行代码:

在实例化FirebaseDatabase的后就设置

mDatabase.setPersistenceEnabled(true);

激活离线功能,然后在对应的节点处,调用keepSynced(true)即可。

DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");scoresRef.keepSynced(true);

本文先就firebase的配置和增、删、改、持久化的方法进行记录。剩下的部分见下一篇博客。

感谢阅读,理解的不对的地方还请指正。