暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用Cloud DB构建APP 快速入门 - Android篇

Gauss松鼠会 2022-05-17
327

概述

此示例应用演示了如何快速的使用Cloud DB构建简单的图书管理服务。通过快速入门和示例应用,您将会了解到如下信息:

  • 如何使用Cloud DB进行应用开发。
  • 应用数据如何写入到Cloud DB。
  • 如何实现数据的查询。
  • 实时侦听数据的更改。
  • 体验端云数据同步等功能。

开发准备

使用Cloud DB构建应用服务,需要完成以下准备工作:

  • 您已经在开发者联盟官网注册帐号并通过实名认证,详细请参见帐号注册认证
  • 您已经在AppGallery Connect控制台上创建项目和应用,详细请参见创建项目。
  • 示例应用使用了认证用户的相关权限,需要开通AppGallery Connect认证服务中“匿名帐号”服务,详细请参见认证服务
  • 您已经获取到示例代码,请从示例代码获取。
  • 您已在本地安装Android Studio。

启用服务

使用Cloud DB服务前,您需要先启用服务。

  1. 登录AppGallery Connect网站,选择“我的项目”。

  2. 在项目列表页面中选择项目,单击项目下需要启用云数据库服务的应用。

  3. 在导航树上选择“构建 > 云数据库”。

  4. 单击“立即开通”,开通云数据库服务。

  5. 如您还未选择数据处理位置,需要您先设置数据处理位置,Cloud DB支持多个数据处理位置,您可以设置一个数据处理位置,也可以设置多个数据处理位置,具体操作请参见设置数据处理位置

  6. 服务初始化成功后,即启用云数据库服务成功。

说明:
您进入云数据库界面后展现的是默认数据处理位置的云数据库,当您的应用需要支持多个数据处理位置时,请在“数据处理位置”选择其他存储地后再分别进行操作。


新增和导出对象类型

  1. 输入对象类型名为“BookInfo”后,单击“下一步”。

单击“导出”。您需要基于AppGallery Connect控制台创建对象类型,请您遵循操作步骤创建示例中涉及的对象类型,并导出用于Android应用开发的java格式对象类型文件。

  1. 登录AppGallery Connect网站,选择“我的项目”。
  2. 在项目列表页面中选择项目,单击项目下需要创建对象类型的应用。
  3. 在导航树上选择“构建 > 云数据库”。
  4. 单击“新增”,进入创建对象类型页面。
  5. 输入对象类型名为“BookInfo”后,单击“下一步”。
  6. 单击 + 新增如下字段后,单击“下一步”。

    表1 字段定义表

    字段类型类型主键非空加密默认值
    idinteger--
    bookNameString----
    authorString----
    priceDouble----
    pulisherString----
    shadowFlagBoolean---true
  7. 单击+ 新增索引,设置索引名为“bookName”,索引字段为“bookName”后,单击“下一步”。
  8. 按照如下要求设置各角色权限后,单击“下一步”。
    表2 权限配置表
    角色queryupsertdelete
    所有人--
    认证用户
    数据创建者
    管理员
  9. 单击“确定”。
    创建完成后返回对象类型列表中,可以查看已创建的对象类型。

  10. 单击“导出”。


  11. 选择导出文件格式,选择“java格式”。
  12. 选择java文件类型,选择“android”。
  13. 输入包名称,即java文件中的package名称。
    包名称只能包含以下3种类型:
    字母(A-Z或a-z)
    数字(0-9)
    特殊字符:_和.
  14. 单击“导出”。
    文件将会导出至本地,其内包含该版本中所有的对象类型。导出的java格式文件在后续步骤用于添加至本地开发环境。

新增存储区

您可基于AppGallery Connect控制台在云侧创建数据存储区,请您遵循操作步骤创建一个存储区名称为“QuickStartDemo”的存储区。

  1. 登录AppGallery Connect网站,选择“我的项目”。

  2. 在项目列表页面中选择项目,单击项目下需要创建存储区的应用。

  3. 在导航树上选择“构建 > 云数据库”。

  4. 选择“存储区”页签。

  5. 单击“新增”,进入创建存储区页面。


  6. 输入存储区名称为“QuickStartDemo”。

  7. 单击“确定”。
    创建完成后返回存储区列表中,可以查看已创建的存储区。

配置开发环境

  1. 使用Android Studio打开示例项目。
  2. 集成AGC SDK,详细请参见集成AGC SDK
  3. 添加Cloud DB SDK至应用级build.gradle文件。
    在<项目名>/app/build.gradle文件中dependencies部分添加Cloud DB SDK。
    dependencies {
        // 添加Cloud DB SDK
        implementation 'com.huawei.agconnect:agconnect-cloud-database:1.5.0.300'
        implementation 'com.huawei.agconnect:agconnect-core:1.5.0.300'
    }
    
  4. 在应用级build.gradle文件中设置Java源码兼容模式为JDK1.8版本。
    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
    

添加对象类型文件

在开发应用时,可直接将AppGallery Connect控制台上导出的java格式文件添加至本地开发环境,并通过AGConnectCloudDB类中的createObjectType()方法实现对象类型的定义和创建。您在进行本地应用开发时,无需再次创建对象类型。

  1. 将已在AppGallery Connect控制台上导出的全部java格式文件添加至本地开发环境,如已存在,请覆盖原文件。文件位置:/app/src/main/java/com/huawei/agc/clouddb/quickstart/model。
  2. 初始化Cloud DB,通过AGConnectCloudDB类中的createObjectType()方法实现对象类型的定义和创建,详细请参见初始化。

初始化

在添加对象类型文件后,您就可以使用云数据库进行应用开发。您开发应用时,需要先执行初始化操作,初始化对应数据处理位置的AGConnectCloudDB、创建Cloud DB zone和对象类型。

  1. 通过initialize()方法初始化AGConnectCloudDB。

    Java:

    public static void initAGConnectCloudDB(Context context) {
        AGConnectCloudDB.initialize(context);
    }
    

    Kotlin:

    fun initAGConnectCloudDB(context: Context?) {
        AGConnectCloudDB.initialize(context!!)
    }
    
  2. 通过setRoutePolicy设置数据处理位置、buildInstance指定配置生成新的AGConnectInstance实例、getInstance(AGConnectInstance connectInstance, AGConnectAuth auth)方法获取对应数据处理位置的AGConnectCloudDB实例,并使用createObjectType()创建对象类型。

    Java:

    AGConnectInstance instance = AGConnectInstance.buildInstance(new AGConnectOptionsBuilder().setRoutePolicy(AGCRoutePolicy.CHINA).build(mContext));
    mCloudDB = AGConnectCloudDB.getInstance(instance, AGConnectAuth.getInstance(instance));
    mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo());
    

    Kotlin:

    var instance = AGConnectInstance.buildInstance(AGConnectOptionsBuilder().setRoutePolicy(AGCRoutePolicy.CHINA).build(context));
    mCloudDB = AGConnectCloudDB.getInstance(instance, AGConnectAuth.getInstance(instance))
    mCloudDB.createObjectType(ObjectTypeInfoHelper.getObjectTypeInfo())
    

    1. 创建Cloud DB zone配置对象,并打开该Cloud DB zone(以Cloud DB zone的同步属性为缓存模式、访问属性为公共存储区为例),详细请参考CloudDBZoneConfig

      Java:

      mConfig = new CloudDBZoneConfig("QuickStartDemo",
          CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
          CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC);
      mConfig.setPersistenceEnabled(true);
      Task<CloudDBZone> openDBZoneTask = mCloudDB.openCloudDBZone2(mConfig, true);
      openDBZoneTask.addOnSuccessListener(new OnSuccessListener<CloudDBZone>() {
          @Override
          public void onSuccess(CloudDBZone cloudDBZone) {
              Log.i(TAG, "open cloudDBZone success");
              mCloudDBZone = cloudDBZone;
              // Add subscription after opening cloudDBZone success
              addSubscription();
          }
      }).addOnFailureListener(new OnFailureListener() {
          @Override
          public void onFailure(Exception e) {
              Log.w(TAG, "open cloudDBZone failed for " + e.getMessage());
          }
      });
      

      Kotlin:

      mConfig = CloudDBZoneConfig("QuickStartDemo",
              CloudDBZoneConfig.CloudDBZoneSyncProperty.CLOUDDBZONE_CLOUD_CACHE,
              CloudDBZoneConfig.CloudDBZoneAccessProperty.CLOUDDBZONE_PUBLIC)
      mConfig!!.persistenceEnabled = true
      val task = mCloudDB.openCloudDBZone2(mConfig!!, true)
      task.addOnSuccessListener {
          Log.i(TAG, "Open cloudDBZone success")
          mCloudDBZone = it
          // Add subscription after opening cloudDBZone success
          addSubscription()
      }.addOnFailureListener {
          Log.w(TAG, "Open cloudDBZone failed for " + it.message)
      }
      

    写入数据

    在本节主要介绍如何在应用程序中进行数据写入操作,以便您了解如何使用Cloud DB SDK实现数据的写入。在应用界面中,增加了“添加”按钮,用于用户新增数据,并在代码中通过executeUpsert()实现数据的写入。

    Java:

    public void upsertBookInfos(BookInfo bookInfo) {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it");
            return;
        }
        Task<Integer> upsertTask = mCloudDBZone.executeUpsert(bookInfo);
        upsertTask.addOnSuccessListener(new OnSuccessListener<Integer>() {
            @Override
            public void onSuccess(Integer cloudDBZoneResult) {
                Log.i(TAG, "Upsert " + cloudDBZoneResult + " records");
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(Exception e) {
                mUiCallBack.updateUiOnError("Insert book info failed");
            }
        });
    }
    

    Kotlin:

    fun upsertBookInfos(bookInfo: BookInfo?) {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it")
            return
        }
        val upsertTask = mCloudDBZone!!.executeUpsert(bookInfo!!)
        upsertTask.addOnSuccessListener { cloudDBZoneResult ->
            Log.i(TAG, "Upsert $cloudDBZoneResult records")
        }.addOnFailureListener {
            mUiCallBack.updateUiOnError("Insert book info failed")
        }
    }
    

    查看数据

    获取数据变化

    用户在应用界面中新增的数据,将会被存储在云侧。在端侧注册数据变化侦听器,当云侧数据发生变化时,端侧能够感知数据变化,及时刷新本地应用数据。通过查询条件与subscribeSnapshot()方法组合使用,可以指定侦听对象,当侦听对象的数据发生变化时,端侧会收到通知,根据快照获取变化的数据信息,从云侧同步数据至端侧应用。

    Java:

    private OnSnapshotListener<BookInfo> mSnapshotListener = new OnSnapshotListener<BookInfo>() {
        @Override
        public void onSnapshot(CloudDBZoneSnapshot<BookInfo> cloudDBZoneSnapshot, AGConnectCloudDBException e) {
            if (e != null) {
                Log.w(TAG, "onSnapshot: " + e.getMessage());
                return;
            }
            CloudDBZoneObjectList<BookInfo> snapshotObjects = cloudDBZoneSnapshot.getSnapshotObjects();
            List<BookInfo> bookInfos = new ArrayList<>();
            try {
                if (snapshotObjects != null) {
                    while (snapshotObjects.hasNext()) {
                        BookInfo bookInfo = snapshotObjects.next();
                        bookInfos.add(bookInfo);
                        updateBookIndex(bookInfo);
                    }
                }
                mUiCallBack.onSubscribe(bookInfos);
            } catch (AGConnectCloudDBException snapshotException) {
                Log.w(TAG, "onSnapshot:(getObject) " + snapshotException.getMessage());
            } finally {
                cloudDBZoneSnapshot.release();
            }
        }
    };
    
    public void addSubscription() {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it");
            return;
        }
    
        try {
            CloudDBZoneQuery<BookInfo> snapshotQuery = CloudDBZoneQuery.where(BookInfo.class)
                .equalTo(BookEditFields.SHADOW_FLAG, true);
            mRegister = mCloudDBZone.subscribeSnapshot(snapshotQuery,
                CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY, mSnapshotListener);
        } catch (AGConnectCloudDBException e) {
            Log.w(TAG, "subscribeSnapshot: " + e.getMessage());
        }
    }
    

    Kotlin:

    private val mSnapshotListener = OnSnapshotListener<BookInfo> { cloudDBZoneSnapshot, e ->
        if (e != null) {
            Log.w(TAG, "onSnapshot: " + e.message)
            return@OnSnapshotListener
        }
        val snapshotObjects = cloudDBZoneSnapshot.snapshotObjects
        val bookInfoList: MutableList<BookInfo> = ArrayList()
        try {
            if (snapshotObjects != null) {
                while (snapshotObjects.hasNext()) {
                    val bookInfo = snapshotObjects.next()
                    bookInfoList.add(bookInfo)
                    updateBookIndex(bookInfo)
                }
            }
            mUiCallBack.onSubscribe(bookInfoList)
        } catch (snapshotException: AGConnectCloudDBException) {
            Log.w(TAG, "onSnapshot:(getObject) " + snapshotException.message)
        } finally {
            cloudDBZoneSnapshot.release()
        }
    }
    private fun addSubscription() {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it")
            return
        }
        try {
            val snapshotQuery = CloudDBZoneQuery.where(BookInfo::class.java)
                    .equalTo(BookEditFields.SHADOW_FLAG, true)
            mRegister = mCloudDBZone!!.subscribeSnapshot(snapshotQuery,
                    CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY, mSnapshotListener)
        } catch (e: AGConnectCloudDBException) {
            Log.w(TAG, "subscribeSnapshot: " + e.message)
        }
    }
    

    数据查询和排序
    在应用界面中,增加了“查询”按钮和排序功能,通过executeQuery()addOnSuccessListener()addOnFailureListener()方法组合,实现异步方式查询数据。

    Java:

    public void queryBooks(CloudDBZoneQuery<BookInfo> query) {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it");
            return;
        }
    
        Task<CloudDBZoneSnapshot<BookInfo>> queryTask = mCloudDBZone.executeQuery(query,
        CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY);
        queryTask.addOnSuccessListener(new OnSuccessListener<CloudDBZoneSnapshot<BookInfo>>() {
            @Override
            public void onSuccess(CloudDBZoneSnapshot<BookInfo> snapshot) {
                processQueryResult(snapshot);
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(Exception e) {
                mUiCallBack.updateUiOnError("Query failed");
            }
        });
    }
    

    Kotlin:

    fun queryBooks(query: CloudDBZoneQuery<BookInfo>) {
        if (mCloudDBZone == null) {
            Log.w(TAG, "CloudDBZone is null, try re-open it")
            return
        }
    
        val queryTask = mCloudDBZone!!.executeQuery(query,
                CloudDBZoneQuery.CloudDBZoneQueryPolicy.POLICY_QUERY_FROM_CLOUD_ONLY)
        queryTask.addOnSuccessListener { snapshot -> processQueryResult(snapshot) }
            .addOnFailureListener { mUiCallBack.updateUiOnError("Query failed") }
    }
    

    通过查询与limit()方法组合,实现限制查询数据显示条数的功能;与orderByAsc()方法或者orderByDesc()方法组合来实现数据的排序功能。
    Java:

    private void queryWithOrder() {
        invalidateViewInNormalMode();
        CloudDBZoneQuery<BookInfo> query = CloudDBZoneQuery.where(BookInfo.class);
        if (!mQueryInfo.bookName.isEmpty()) {
            query.contains(BookEditFields.BOOK_NAME, mQueryInfo.bookName);
        }
        query.greaterThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.lowestPrice);
        if (mQueryInfo.lowestPrice != mQueryInfo.highestPrice || mQueryInfo.lowestPrice != 0.0) {
            query.lessThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.highestPrice);
        }
        if (mQueryInfo.showCount > 0) {
            query.limit(mQueryInfo.showCount);
        }
        if (mSortState.state == SortState.State.UP) {
            query.orderByAsc(mSortState.field);
        } else {
            query.orderByDesc(mSortState.field);
        }
        mHandler.post(() -> mCloudDBZoneWrapper.queryBooks(query));
    }
    

    Kotlin:

    private fun queryWithOrder() {
        invalidateViewInNormalMode()
        val query = CloudDBZoneQuery.where(BookInfo::class.java)
        if (mQueryInfo.bookName!!.isNotEmpty()) {
            query.contains(BookEditFields.BOOK_NAME, mQueryInfo.bookName!!)
        }
        query.greaterThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.lowestPrice)
        if (mQueryInfo.lowestPrice != mQueryInfo.highestPrice || mQueryInfo.lowestPrice != 0.0) {
            query.lessThanOrEqualTo(BookEditFields.PRICE, mQueryInfo.highestPrice)
        }
        if (mQueryInfo.showCount > 0) {
            query.limit(mQueryInfo.showCount)
        }
        if (mSortState.state == SortState.State.UP) {
            query.orderByAsc(mSortState.field!!)
        } else {
            query.orderByDesc(mSortState.field!!)
        }
        mHandler.post { mCloudDBZoneWrapper.queryBooks(query) }
    }
    

    应用编译运行

    到此,您已经了解了示例应用的开发流程。您可以编译并生成APK包,在Android手机上安装、运行示例应用。如需体验示例应用,您可以在A手机上打开应用,并新增数据;然后您可以在B手机上打开应用,查看在A手机上写入的数据。


















        「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
        关注作者
        【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论