アンドロイドとリアルタイム
44966 ワード
🤔 何がappwriteですか?
AppWriteは、新しいオープンソース、エンドツーエンド、Webおよびモバイル開発者のためのバックエンドサーバーは、はるかに高速なアプリケーションを構築することができます.これは、概要と簡単なアプリケーションを構築するのを助ける休息APIとツールの背後にある共通の開発タスクを簡素化します.
🤖 アンドロイド用
AppWriteは、クラウド機能、データベース、ストレージなどのWebアプリケーションやモバイルアプリケーションの開発に必要なさまざまな共通の機能を提供します.これは、AppWriteは非常にAndroidアプリケーションを構築したい私たちのために適しています.このチュートリアルでは、AppWriteと新しいリアルタイムAPIを使用して、Androidのリアルタイム製品アプリケーションを構築します.
📝 必要条件
このチュートリアルで続行するには、AppWriteコンソールにアクセスする必要があります.既にAppWriteをインストールしていない場合は、どうぞ.AppWriteのインストールは、Appwriteの公式の次は本当に簡単ですinstallation docs . インストールはわずか2分かかる必要があります.インストールしたら、コンソールにログインし、新しいプロジェクトを作成します.
💾 データベース設定
AppWriteコンソールでは、我々のAndroidアプリのために使用されるプロジェクトを選択してみましょう.あなたがまだプロジェクトを持っていない場合は、簡単に作成プロジェクトボタンをクリックして1つを作成することができます.内側にある場合は、左側のサイドバーからデータベースを選択します.データベースページで
名称
説明
京大理
価格
イメージURL
今コレクションが作成され、我々はAndroidのアプリケーションを設定するに移動することができます.
⚙️ Androidプロジェクトと依存関係の設定
Android Studioを使用して、空のアクティビティテンプレートを選択する新しいAndroidアプリケーションプロジェクトを作成します.プロジェクトが作成されると、次の依存関係をアプリケーションの
build.gradle(.kts)
ファイル // Appwrite
implementation("io.appwrite:sdk-for-android:0.2.0")
// Appcompat, LiveData, ViewModel and Activity extensions
implementation 'androidx.appcompat:appcompat:1.3.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.activity:activity-ktx:1.3.1'
// JSON
implementation 'com.google.code.gson:gson:2.8.7'
// Image loading
implementation 'com.github.bumptech.glide:glide:4.12.0'
kapt 'com.github.bumptech.glide:compiler:4.12.0'
➕️ アンドロイドプラットフォーム
AppWrite SDKを初期化し、AppWriteサービスとの対話を開始するには、まず新しいAndroidプラットフォームをプロジェクトに追加する必要があります.新しいプラットフォームを追加するには、AppWriteコンソールに移動し、プロジェクトを選択します(または、すでに作成されていない場合は1つを作成します)、プロジェクトのダッシュボードの「プラットフォームを追加」ボタンをクリックします.
オプションから、新しいAndroidプラットフォームを追加し、アプリケーションの資格情報を追加を選択します.
あなたのアプリケーション名とパッケージ名を加えてください.あなたのパッケージ名は一般に
applicationId
あなたのアプリケーションレベルで build.gradle
ファイル.また、あなたのパッケージ名を AndroidManifest.xml
ファイル.新しいプラットフォームを登録することにより、あなたのアプリはAppWrite APIと通信することができます.🧱 製品モデルの作成
Android側で製品を表現するモデルを作成する必要があります.新しいKollinファイルを作成します
Product.kt
単純なデータクラスを宣言します.data class Product(
val name: String,
val sku: String,
val price: Double,
val imageUrl: String
)
⚒️ ビルビュー
さて、あなたの
app/src/main/res/layout/activity_main.xml
そして次のようにレイアウトを更新します.<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerProducts"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
app:layout_constraintBottom_toTopOf="@id/btnSubscribe"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:spanCount="3"/>
<Button
android:id="@+id/btnSubscribe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:text="Subscribe to products"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/recyclerProducts"/>
</androidx.constraintlayout.widget.ConstraintLayout>
あなたは、活動が非常に簡単であることに気づくでしょう私たちはButton
購読するRecyclerView
. The RecyclerView
新しい製品を追加するときにリアルタイムで製品コレクションを表示するために使用されます.個々の製品を表現するために使用される別のビューを定義する必要があります.から新しいレイアウトを作成
File > New > Layout Resource File
, 名前item_product.xml
次の行を追加します.<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_margin="2dp">
<ImageView
android:id="@+id/imgProduct"
android:layout_width="match_parent"
android:layout_height="120dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<View
android:layout_width="match_parent"
android:layout_height="34dp"
android:alpha="0.6"
android:background="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/txtName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<TextView
android:id="@+id/txtPrice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
我々のすべての部分RecyclerView
で、我々は設定するに移動することができますViewModel
, どこで重いリフトのほとんどが発生します.👩🔧 クリエイトビューモデル
クリエイト
app/src/main/java/com/example/realtimestarter/RealtimeViewModel.kt
そして、次のコードでそれを更新します.ファイルの上部にあるすべてのプロパティ値を、AppWriteコンソールで見つけることができる独自の値で置き換えるようにしてください.package io.appwrite.realtimestarter
import android.content.Context
import android.util.Log
import androidx.lifecycle.*
import io.appwrite.Client
import io.appwrite.extensions.toJson
import io.appwrite.models.RealtimeResponseEvent
import io.appwrite.models.RealtimeSubscription
import io.appwrite.services.Account
import io.appwrite.services.Database
import io.appwrite.services.Realtime
import kotlinx.coroutines.launch
class RealtimeViewModel : ViewModel(), LifecycleObserver {
private val endpoint = "YOUR_ENDPOINT" // Replace with your endpoint
private val projectId = "YOUR_PROJECT_ID" // Replace with your project ID
private val collectionId = "YOUR_COLLECTION_ID" // Replace with your product collection ID
private val realtime by lazy { Realtime(client!!) }
private val account by lazy { Account(client!!) }
private val db by lazy { Database(client!!) }
private val _productStream = MutableLiveData<Product>()
val productStream: LiveData<Product> = _productStream
private val _productDeleted = MutableLiveData<Product>()
val productDeleted: LiveData<Product> = _productDeleted
private var client: Client? = null
var subscription: RealtimeSubscription? = null
private set
fun subscribeToProducts(context: Context) {
buildClient(context)
viewModelScope.launch {
// Create a session so that we are authorized for realtime
createSession()
// Attach an error logger to our realtime instance
realtime.doOnError { Log.e(this::class.java.name, it.message.toString()) }
// Subscribe to document events for our collection and attach the handle product callback
subscription = realtime.subscribe(
"collections.${collectionId}.documents",
payloadType = Product::class.java,
callback = ::handleProductMessage
)
//createDummyProducts()
}
}
private fun handleProductMessage(message: RealtimeResponseEvent<Product>) {
when (message.event) {
in
"database.documents.create",
"database.documents.update" -> {
_productStream.postValue(message.payload!!)
}
"database.documents.delete" -> {
_productDeleted.postValue(message.payload!!)
}
}
}
private suspend fun createDummyProducts() {
// For testing; insert 100 products while subscribed
val url = "https://dummyimage.com/600x400/cde/fff"
for (i in 1 until 100) {
db.createDocument(
collectionId,
Product("iPhone $i", "sku-$i", i.toDouble(), url).toJson(),
listOf("*"),
listOf("*")
)
}
}
private fun buildClient(context: Context) {
if (client == null) {
client = Client(context)
.setEndpoint(endpoint)
.setProject(projectId)
}
}
private suspend fun createSession() {
try {
account.createAnonymousSession()
} catch (ex: Exception) {
ex.printStackTrace()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun closeSocket() {
// Activity is being destroyed; close our socket connection if it's open
subscription?.close()
}
}
The ViewModel
リアルタイムAPIを呼び出し、コレクション内の任意のドキュメントに関連するUPDATE/UPDATE/DELETEイベントの通知を購読しますcollectionId
, それは私たちのユーザにも見えます.外部からのリアルタイム更新を受信できるようにするには
ViewModel
また、LiveData
プロパティproductStream
, どれが我々を利用するでしょうActivity
後で私たちのリアルタイムアップデートを取得するRecyclerView
.♻️ リサイクリング
私たちを得るために追加する必要があります2つのファイルがあります
RecyclerView
作業ProductAdapter
, それぞれのビューの作成とバインドを処理するProduct
データベースに追加されます.The DiffUtil.ItemCallback
コンストラクタで提供され、バックグラウンドスレッド上のリスト更新差分を計算するために使用され、その後、リアルタイムに最適なUIスレッド上の任意の変更を投稿する!あなたの詳細情報を見つけることができますDiffUtil
here .package io.appwrite.realtimestarter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
class ProductAdapter :
ListAdapter<Product, ProductViewHolder>(object : DiffUtil.ItemCallback<Product>() {
override fun areItemsTheSame(oldItem: Product, newItem: Product) =
oldItem.sku == newItem.sku
override fun areContentsTheSame(oldItem: Product, newItem: Product) =
oldItem == newItem
}) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_product, parent, false)
return ProductViewHolder(view)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val item = currentList[position]
holder.setName(item.name)
holder.setPrice(item.price.toString())
holder.setProductImage(item.imageUrl)
}
fun submitNext(product: Product) {
val current = currentList.toMutableList()
val index = currentList.indexOfFirst {
it.sku == product.sku
}
if (index != -1) {
current[index] = product
} else {
current.add(product)
}
submitList(current)
}
fun submitDeleted(product: Product) {
submitList(
currentList.toMutableList().apply {
remove(product)
}
)
}
}
ProductViewHolder
シングルを記述するProduct
ビューとその位置についてのメタデータRecyclerView
:package io.appwrite.realtimestarter
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private var nameView: TextView = itemView.findViewById(R.id.txtName)
private var priceView: TextView = itemView.findViewById(R.id.txtPrice)
private var imageView: ImageView = itemView.findViewById(R.id.imgProduct)
fun setName(name: String) {
nameView.text = name
}
fun setPrice(price: String) {
priceView.text = "\$$price"
}
fun setProductImage(url: String) {
Glide.with(itemView)
.load(url)
.centerCrop()
.into(imageView)
}
}
💆 アクティビティ
他のすべての場所で、私たちのすべてで一緒にそれを結ぶことができます
MainActivity
. オープンapp/src/main/java/com/example/realtimestarter/MainActivity.kt
このように更新します.package io.appwrite.realtimestarter
import android.os.Bundle
import android.widget.Button
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView
class RealtimeActivity : AppCompatActivity() {
private val viewModel by viewModels<RealtimeViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_realtime)
val button = findViewById<Button>(R.id.btnSubscribe)
button.setOnClickListener {
viewModel.subscribeToProducts(this)
}
val adapter = ProductAdapter()
val recycler = findViewById<RecyclerView>(R.id.recyclerProducts)
recycler.adapter = adapter
viewModel.productStream.observe(this) {
adapter.submitNext(it)
}
viewModel.productDeleted.observe(this) {
adapter.submitDeleted(it)
}
lifecycle.addObserver(viewModel)
}
override fun onStop() {
super.onStop()
lifecycle.removeObserver(viewModel)
}
}
🏎️ リアルタイムになりましょう
それは、すべての残っているアプリケーションを実行し、いくつかのドキュメントを追加することです.エミュレータまたはデバイスで実行する場合は、「購読」をクリックして、リアルタイム更新の待機を開始します.
あなたのappwriteコンソールに戻ってください
Products
我々は以前に作成したコレクション.ここから、我々は新しいドキュメントを追加を開始することができますし、それらが我々のアプリに表示さを参照してください.すぐにあなたがコンソールに製品を追加すると、それらはあなたのアプリケーションのUIに表示されますよ!それは以下に示すように、appwriteリアルタイムの本当の美しさです.
🥂 結論
私はあなたがappwriteとAndroidでこのリアルタイムアプリケーションを構築楽しんだ.このアプリケーションのための完全なソースはDemo Realtime Application リポジトリ.あなたが任意のフィードバックや提案がある場合はお知らせください.コミュニティをAppWriteリアルタイムとAndroidを使用して作成できるものを見て楽しみにして!
🎓 もっと学ぶ
Reference
この問題について(アンドロイドとリアルタイム), 我々は、より多くの情報をここで見つけました https://dev.to/appwrite/appwrite-android-and-realtime-42jdテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol