实现一个同步应用
智能门铃可能有也可能没有本地显示。用于移动设备的配套应用允许用户在嵌入式设备插入时,远程并自动地看到新的门铃环事件和图像。
在本课中,您将构建一个包含与门铃数据库同步的Firebase实时数据库的Android手机应用程序。
创建一个随播应用程序模块
在嵌入式门铃应用程序旁边,在项目中创建第二个模块。创建一个新的项目模块:
将Firebase添加到您的模块
为您的随播应用模块启用Firebase实时数据库:
按照说明中的说明下载并安装 google-services.json
文件。
</li>
将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
中的逻辑。
以下 DoorbellEntryAdapter
将 DoorbellEntry
实例的数据绑定到 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 构建了启用了云端的门铃!