如何使用 android Kotlin 从实时数据库中读取异步数据?
How to read asynchronous data from real-time database using android Kotlin?
这是我使用 android Kotlin 从实时数据库读取异步数据的代码:
class suDetails : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
su_image.setOnClickListener {
readData(object : MyCallback {
override fun onCallback(imageUrl: String?) {
if (imageUrl != null) {
val imageViewer = Intent(baseContext, suDetails::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", imageUrl)
startActivity(imageViewer)
}
}
})
}
}
fun readData(myCallback: MyCallback) {
val su_resource =intent
val su_res = su_resource.getStringExtra("su_userid")
val suRef = FirebaseDatabase.getInstance().getReference().child("Users").child(su_res!!)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot.exists()){
su_layout.visibility = View.VISIBLE
val userData = dataSnapshot.getValue(profile_model::class.java)
val imageUrl = userData!!.getImageUrl()
Picasso.get().load(imageUrl).placeholder(R.drawable.ic_baseline_image_200).into(su_image)
su_name.text = userData.getnameOfsu()
Toast.makeText(baseContext, imageUrl, Toast.LENGTH_LONG).show()
myCallback.onCallback(imageUrl)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
interface MyCallback {
fun onCallback(value: String?)
}
}
我已经参考了其他问题来从实时数据库中读取异步数据,但是当我尝试该解决方案时,我无法在 ImageView
和 textView
中显示任何数据。我只看到空白屏幕。
Tyler V 回答后的新代码:
class suDetails : AppCompatActivity() {
private var currentImageUrl: String = ""
private var su_res: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
su_res = intent.getStringExtra("su_userid").toString()
// get views
val su_name = findViewById<TextView>(R.id.su_name)
val su_image = findViewById<ImageView>(R.id.su_image)
// onClick launches another activity - if the image
// hasn't loaded yet nothing happens
su_image.setOnClickListener { viewCurrentImage() }
// start the async loading right away - once it is loaded the
// su_layout view will be visible and the view data
// will be populated. It might be good to show a progress bar
// while it's loading
readData()
}
fun readData() {
println("LOG: called readData")
Toast.makeText(baseContext, su_res, Toast.LENGTH_LONG).show()
println("LOG: getting data for ${su_res}")
val suRef = FirebaseDatabase.getInstance()
.getReference()
.child("Users")
.child(su_res)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
println("LOG: data snapshot exists")
su_layout.visibility = View.VISIBLE
val userData = dataSnapshot.getValue(profile_model::class.java)
currentImageUrl = userData?.getImageUrl() ?: ""
su_name.text = userData?.getnameOfsu() ?: ""
println("LOG: Got user data ${currentImageUrl}")
if (currentImageUrl.isNotEmpty()) {
Picasso.get()
.load(currentImageUrl)
.placeholder(R.drawable.ic_baseline_image_200)
.into(su_image)
}
} else {
println("LOG: user not found in database")
}
}
override fun onCancelled(error: DatabaseError) {
println("LOG: cancelled")
}
})
}
private fun viewCurrentImage() {
if (currentImageUrl.isEmpty()) return
Toast.makeText(baseContext, currentImageUrl, Toast.LENGTH_LONG).show()
val imageViewer = Intent(baseContext, ImageViewer::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", currentImageUrl)
startActivity(imageViewer)
}
}
this related question 的最佳答案向您展示了如何进行回调,但这并没有真正回答如何使用异步数据的问题,并且与此类问题。
我没有发现您的回调有任何特别的错误 - 但它默默地吞下了许多可能的错误情况(例如,如果用户不存在)。下面的例子有一些打印语句,应该有助于更好地确定发生了什么。
比额外的回调接口更简洁的方法是 make a separate method 来处理异步结果。这是一个经过清理的示例,说明它的外观 - pseudo-code 您的示例的某些部分丢失了。为了帮助调试,如果您不理解代码的哪些部分是 运行,或者如果某些内容看起来不像您期望的那样,您应该养成使用日志或打印语句的习惯。
private var currentImageUrl: String = ""
private var userId: String = ""
private lateinit var su_name: TextView
private lateinit var su_image : ImageView
private lateinit var su_layout : ConstraintLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
// get views
su_name = findViewById<TextView>(R.id.su_name)
su_image = findViewById<ImageView>(R.id.su_image)
su_layout = findViewById<ConstraintLayout>(R.id.su_layout)
su_layout.visibility = View.INVISIBLE
// get user id from intent
userId = intent.getStringExtra("su_userid").orEmpty()
// TODO: Handle what to do if userId is empty here!
if( userId.isEmpty() ) {
finish()
}
// onClick launches another activity - if the image
// hasn't loaded yet nothing happens
su_image.setOnClickListener { viewCurrentImage() }
// start the async loading right away - once it is loaded the
// su_layout view will be visible and the view data
// will be populated. It might be good to show a progress bar
// while it's loading
startLoading()
}
private fun startLoading() {
println("LOG: getting data for ${userId}")
val suRef = FirebaseDatabase.getInstance()
.getReference()
.child("Users")
.child(userId)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot.exists()) {
println("LOG: data snapshot exists")
val userData = dataSnapshot.getValue(profile_model::class.java)
showData(userData)
}
else {
println("LOG: user not found in database")
}
}
override fun onCancelled(error: DatabaseError) {
println("LOG: cancelled")
}
})
}
private fun showData(userData: profile_model?) {
su_layout.visibility = View.VISIBLE
currentImageUrl = userData?.getImageUrl() ?: ""
su_name.text = userData?.getnameOfsu() ?: "Error"
println("LOG: Got user data ${currentImageUrl}")
if( currentImageUrl.isNotEmpty() ) {
Picasso.get()
.load(currentImageUrl)
.placeholder(R.drawable.ic_baseline_image_200)
.into(su_image)
}
}
private fun viewCurrentImage() {
if( currentImageUrl.isEmpty() ) return
val imageViewer = Intent(this, suDetails::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", currentImageUrl)
startActivity(imageViewer)
}
这是我使用 android Kotlin 从实时数据库读取异步数据的代码:
class suDetails : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
su_image.setOnClickListener {
readData(object : MyCallback {
override fun onCallback(imageUrl: String?) {
if (imageUrl != null) {
val imageViewer = Intent(baseContext, suDetails::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", imageUrl)
startActivity(imageViewer)
}
}
})
}
}
fun readData(myCallback: MyCallback) {
val su_resource =intent
val su_res = su_resource.getStringExtra("su_userid")
val suRef = FirebaseDatabase.getInstance().getReference().child("Users").child(su_res!!)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot.exists()){
su_layout.visibility = View.VISIBLE
val userData = dataSnapshot.getValue(profile_model::class.java)
val imageUrl = userData!!.getImageUrl()
Picasso.get().load(imageUrl).placeholder(R.drawable.ic_baseline_image_200).into(su_image)
su_name.text = userData.getnameOfsu()
Toast.makeText(baseContext, imageUrl, Toast.LENGTH_LONG).show()
myCallback.onCallback(imageUrl)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
interface MyCallback {
fun onCallback(value: String?)
}
}
我已经参考了其他问题来从实时数据库中读取异步数据,但是当我尝试该解决方案时,我无法在 ImageView
和 textView
中显示任何数据。我只看到空白屏幕。
Tyler V 回答后的新代码:
class suDetails : AppCompatActivity() {
private var currentImageUrl: String = ""
private var su_res: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
su_res = intent.getStringExtra("su_userid").toString()
// get views
val su_name = findViewById<TextView>(R.id.su_name)
val su_image = findViewById<ImageView>(R.id.su_image)
// onClick launches another activity - if the image
// hasn't loaded yet nothing happens
su_image.setOnClickListener { viewCurrentImage() }
// start the async loading right away - once it is loaded the
// su_layout view will be visible and the view data
// will be populated. It might be good to show a progress bar
// while it's loading
readData()
}
fun readData() {
println("LOG: called readData")
Toast.makeText(baseContext, su_res, Toast.LENGTH_LONG).show()
println("LOG: getting data for ${su_res}")
val suRef = FirebaseDatabase.getInstance()
.getReference()
.child("Users")
.child(su_res)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if (dataSnapshot.exists()) {
println("LOG: data snapshot exists")
su_layout.visibility = View.VISIBLE
val userData = dataSnapshot.getValue(profile_model::class.java)
currentImageUrl = userData?.getImageUrl() ?: ""
su_name.text = userData?.getnameOfsu() ?: ""
println("LOG: Got user data ${currentImageUrl}")
if (currentImageUrl.isNotEmpty()) {
Picasso.get()
.load(currentImageUrl)
.placeholder(R.drawable.ic_baseline_image_200)
.into(su_image)
}
} else {
println("LOG: user not found in database")
}
}
override fun onCancelled(error: DatabaseError) {
println("LOG: cancelled")
}
})
}
private fun viewCurrentImage() {
if (currentImageUrl.isEmpty()) return
Toast.makeText(baseContext, currentImageUrl, Toast.LENGTH_LONG).show()
val imageViewer = Intent(baseContext, ImageViewer::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", currentImageUrl)
startActivity(imageViewer)
}
}
this related question 的最佳答案向您展示了如何进行回调,但这并没有真正回答如何使用异步数据的问题,并且与此类问题。
我没有发现您的回调有任何特别的错误 - 但它默默地吞下了许多可能的错误情况(例如,如果用户不存在)。下面的例子有一些打印语句,应该有助于更好地确定发生了什么。
比额外的回调接口更简洁的方法是 make a separate method 来处理异步结果。这是一个经过清理的示例,说明它的外观 - pseudo-code 您的示例的某些部分丢失了。为了帮助调试,如果您不理解代码的哪些部分是 运行,或者如果某些内容看起来不像您期望的那样,您应该养成使用日志或打印语句的习惯。
private var currentImageUrl: String = ""
private var userId: String = ""
private lateinit var su_name: TextView
private lateinit var su_image : ImageView
private lateinit var su_layout : ConstraintLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_su_details)
// get views
su_name = findViewById<TextView>(R.id.su_name)
su_image = findViewById<ImageView>(R.id.su_image)
su_layout = findViewById<ConstraintLayout>(R.id.su_layout)
su_layout.visibility = View.INVISIBLE
// get user id from intent
userId = intent.getStringExtra("su_userid").orEmpty()
// TODO: Handle what to do if userId is empty here!
if( userId.isEmpty() ) {
finish()
}
// onClick launches another activity - if the image
// hasn't loaded yet nothing happens
su_image.setOnClickListener { viewCurrentImage() }
// start the async loading right away - once it is loaded the
// su_layout view will be visible and the view data
// will be populated. It might be good to show a progress bar
// while it's loading
startLoading()
}
private fun startLoading() {
println("LOG: getting data for ${userId}")
val suRef = FirebaseDatabase.getInstance()
.getReference()
.child("Users")
.child(userId)
suRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
if(dataSnapshot.exists()) {
println("LOG: data snapshot exists")
val userData = dataSnapshot.getValue(profile_model::class.java)
showData(userData)
}
else {
println("LOG: user not found in database")
}
}
override fun onCancelled(error: DatabaseError) {
println("LOG: cancelled")
}
})
}
private fun showData(userData: profile_model?) {
su_layout.visibility = View.VISIBLE
currentImageUrl = userData?.getImageUrl() ?: ""
su_name.text = userData?.getnameOfsu() ?: "Error"
println("LOG: Got user data ${currentImageUrl}")
if( currentImageUrl.isNotEmpty() ) {
Picasso.get()
.load(currentImageUrl)
.placeholder(R.drawable.ic_baseline_image_200)
.into(su_image)
}
}
private fun viewCurrentImage() {
if( currentImageUrl.isEmpty() ) return
val imageViewer = Intent(this, suDetails::class.java)
imageViewer.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
imageViewer.putExtra("su_image", currentImageUrl)
startActivity(imageViewer)
}