实现一个同步应用

智能门铃可能有也可能没有本地显示。用于移动设备的配套应用允许用户在嵌入式设备插入时,远程并自动地看到新的门铃环事件和图像。

在本课中,您将构建一个包含与门铃数据库同步的Firebase实时数据库的Android手机应用程序。

创建一个随播应用程序模块

在嵌入式门铃应用程序旁边,在项目中创建第二个模块。创建一个新的项目模块:

  1. 按照说明在Android Studio 中创建新模块
  2. 创建一个新的手机和平板电脑模块。
  3. </ol>

    将Firebase添加到您的模块

    为您的随播应用模块启用Firebase实时数据库:

    1. Firebase Android SDK 安装到您的应用程序模块中。
    2. 按照说明中的说明下载并安装 google-services.json 文件。

      </li>

    3. 将Firebase实时数据库和Firebase UI依赖项添加到应用级 build.gradle 文件中:

      dependencies {
          ...
      
          compile 'com.google.firebase:firebase-core:9.6.1'
          compile 'com.google.firebase:firebase-database:9.6.1'
          compile 'com.firebaseui:firebase-ui-database:0.5.3'
      }
      

      用 Firebase UI显示门铃事件

      为了简化与Firebase数据模型的交互,请创建一个 DoorbellEntry 模型类,其中包含JSON模式中描述的相同属性。

      public class DoorbellEntry {
      
          Long timestamp;
          String image;
          Map<String, Float> annotations;
      
          public DoorbellEntry() {
          }
      
          public DoorbellEntry(Long timestamp, String image, Map<String, Float> annotations) {
              this.timestamp = timestamp;
              this.image = image;
              this.annotations = annotations;
          }
      
          public Long getTimestamp() {
              return timestamp;
          }
      
          public String getImage() {
              return image;
          }
      
          public Map<String, Float> getAnnotations() {
              return annotations;
          }
      }
      

      FirebaseUI 库中的 FirebaseRecyclerAdapter 简化了将Firebase数据绑定到 Recyclerview 进行显示。适配器的子类必须覆盖 populateViewHolder(),并提供将模型中的数据绑定到提供的 ViewHolder 中的逻辑。

      以下 DoorbellEntryAdapterDoorbellEntry 实例的数据绑定到 DoorbellEntryViewHolder中:

      public class DoorbellEntryAdapter extends FirebaseRecyclerAdapter<DoorbellEntry, DoorbellEntryAdapter.DoorbellEntryViewHolder> {
      
          /**
           * ViewHolder for each doorbell entry
           */
          static class DoorbellEntryViewHolder extends RecyclerView.ViewHolder {
      
              public final ImageView image;
              public final TextView time;
              public final TextView metadata;
      
              public DoorbellEntryViewHolder(View itemView) {
                  super(itemView);
      
                  this.image = (ImageView) itemView.findViewById(R.id.imageView1);
                  this.time = (TextView) itemView.findViewById(R.id.textView1);
                  this.metadata = (TextView) itemView.findViewById(R.id.textView2);
              }
          }
      
          private Context mApplicationContext;
      
          public DoorbellEntryAdapter(Context context, DatabaseReference ref) {
              super(DoorbellEntry.class, R.layout.doorbell_entry, DoorbellEntryViewHolder.class, ref);
      
              mApplicationContext = context.getApplicationContext();
          }
      
          @Override
          protected void populateViewHolder(DoorbellEntryViewHolder viewHolder, DoorbellEntry model, int position) {
              // Display the timestamp
              CharSequence prettyTime = DateUtils.getRelativeDateTimeString(mApplicationContext,
                      model.getTimestamp(), DateUtils.SECOND_IN_MILLIS, DateUtils.WEEK_IN_MILLIS, 0);
              viewHolder.time.setText(prettyTime);
      
              // Display the image
              if (model.getImage() != null) {
                  // Decode image data encoded by the Cloud Vision library
                  byte[] imageBytes = Base64.decode(model.getImage(), Base64.NO_WRAP | Base64.URL_SAFE);
                  Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
                  if (bitmap != null) {
                      viewHolder.image.setImageBitmap(bitmap);
                  } else {
                      Drawable placeholder =
                              ContextCompat.getDrawable(mApplicationContext, R.drawable.ic_placeholder);
                      viewHolder.image.setImageDrawable(placeholder);
                  }
              }
      
              // Display the metadata
              if (model.getAnnotations() != null) {
                  ArrayList<String> keywords = new ArrayList<>(model.getAnnotations().keySet());
      
                  int limit = Math.min(keywords.size(), 3);
                  viewHolder.metadata.setText(TextUtils.join("\n", keywords.subList(0, limit)));
              } else {
                  viewHolder.metadata.setText("no annotations yet");
              }
          }
      
      }
      

      创建一个 DoorbellEntryAdapter 的实例,并将其附加到您的活动中的 RecyclerView。 FirebaseUI 适配器会自动向数据库注册事件侦听器。为了避免内存泄漏,请先在 onStart() 中初始化适配器,并调用 onStop() 中的 cleanup() 方法。

      为了确保每个新的门铃事件对用户可见,将列表滚动到每个数据集更改的最新项目。您可以使用连接到适配器的 AdapterDataObserver 侦听更改事件。

      public class MainActivity extends AppCompatActivity {
      
          private DatabaseReference mDatabaseRef;
      
          private RecyclerView mRecyclerView;
          private DoorbellEntryAdapter mAdapter;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
      
              mRecyclerView = (RecyclerView) findViewById(R.id.doorbellView);
              // Show most recent items at the top
              LinearLayoutManager layoutManager =
                      new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, true);
              mRecyclerView.setLayoutManager(layoutManager);
      
              // Reference for doorbell events from embedded device
              mDatabaseRef = FirebaseDatabase.getInstance().getReference().child("logs");
          }
      
          @Override
          protected void onStart() {
              super.onStart();
      
              mAdapter = new DoorbellEntryAdapter(this, mDatabaseRef);
              mRecyclerView.setAdapter(mAdapter);
      
              // Make sure new events are visible
              mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
                  @Override
                  public void onItemRangeChanged(int positionStart, int itemCount) {
                      mRecyclerView.smoothScrollToPosition(mAdapter.getItemCount());
                  }
              });
          }
      
          @Override
          protected void onStop() {
              super.onStop();
      
              // Tear down Firebase listeners in adapter
              if (mAdapter != null) {
                  mAdapter.cleanup();
                  mAdapter = null;
              }
          }
      }
      

      恭喜!您已经为连接的家庭使用 Android Things 构建了启用了云端的门铃!

      results matching ""

        No results matching ""