【发布时间】:2020-11-26 23:24:25
【问题描述】:
我一直在使用 Kotlin 编写社交应用程序。最近我在我的主要活动中添加了一个寻找朋友片段(主要活动有三个片段:主页,拒绝/接受朋友请求,以及寻找可以发送朋友请求的朋友)。此外,Main Activity 有一个选项卡布局,它位于所有片段之上,并有一个将用户引导到个人资料页面的按钮。这就是问题发生的地方。当我尝试使用以下方式注销用户时:
mAuth!!.signOut()
startActivity(Intent(applicationContext, LoginActivity::class.java))
finishAffinity()
我收到一个错误:
Caused by: java.lang.IllegalAccessException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at com.example.realtimechat.findfriends.FindFriendsFragment$onViewCreated$1.onCancelled(FindFriendsFragment.kt:104)
但仅当我在点击个人资料页面按钮以将应用程序重定向到我可以退出的个人资料页面之前访问 FindFriends 片段时才会出现此错误。例如,如果我启动应用程序(以主页片段开头)并立即转到个人资料页面退出,错误消失了,我成功退出并重定向到登录页面。但是,如果我启动应用程序,去寻找朋友片段,然后去个人资料页面注销,我会收到错误消息。是不是我做错了什么?
(顺便找朋友有recycler view)
FindFriendsFragment.kt
package com.example.realtimechat.findfriends
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.realtimechat.R
import com.example.realtimechat.common.Constants
import com.example.realtimechat.common.NodeNames
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.*
import java.lang.NullPointerException
class FindFriendsFragment: Fragment() {
private var rvFindFriends: RecyclerView? = null
private var findFriendsAdapter: FindFriendAdapter? = null
private var findFriendsModelList: MutableList<FindFriendModel> = ArrayList()
private var tvEmptyFriendsList: TextView? = null
private var databaseReference: DatabaseReference? = null
private var currentUser: FirebaseUser? = null
private var progressBar: View? = null
private var databaseReferenceFriendRequests: DatabaseReference? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_find_friends, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
rvFindFriends = view.findViewById(R.id.rvFindFriends)
tvEmptyFriendsList = view.findViewById(R.id.tvEmptyFriendsList)
progressBar = view.findViewById(R.id.progressBar)
rvFindFriends!!.layoutManager = LinearLayoutManager(activity)
findFriendsModelList = ArrayList()
findFriendsAdapter = FindFriendAdapter(activity!!, findFriendsModelList)
rvFindFriends!!.adapter = findFriendsAdapter
databaseReference = FirebaseDatabase.getInstance().reference.child(NodeNames.USERS);
currentUser = FirebaseAuth.getInstance().currentUser;
databaseReferenceFriendRequests = FirebaseDatabase.getInstance().reference.child(NodeNames.FRIEND_REQUESTS).child(currentUser!!.uid);
tvEmptyFriendsList!!.visibility = View.VISIBLE;
progressBar!!.visibility = View.VISIBLE;
val query: Query = databaseReference!!.orderByChild(NodeNames.USERNAME)
query.addValueEventListener(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
progressBar?.visibility = View.GONE
findFriendsModelList.clear()
for(ds: DataSnapshot in snapshot.children){
val userId = ds.key
if(userId.equals(currentUser?.uid)){
continue
}
if(ds.child(NodeNames.USERNAME).value !=null){
val username = ds.child(NodeNames.USERNAME).value.toString()
val photoFileName = ds.child(NodeNames.PHOTO).value.toString()
databaseReferenceFriendRequests!!.child(userId!!).addListenerForSingleValueEvent(object: ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if(snapshot.exists()){
val requestType = snapshot.child(NodeNames.REQUEST_TYPE).value.toString()
if(requestType == Constants.REQUEST_STATUS_SENT){
findFriendsModelList.add(FindFriendModel(userId, photoFileName, username, true))
findFriendsAdapter!!.notifyDataSetChanged()
}
}else{
findFriendsModelList.add(FindFriendModel(userId, photoFileName, username, false))
findFriendsAdapter!!.notifyDataSetChanged()
}
}
override fun onCancelled(error: DatabaseError) {
progressBar?.visibility = View.GONE
}
})
progressBar?.visibility = View.GONE
tvEmptyFriendsList?.visibility = View.GONE
}
}
}
override fun onCancelled(error: DatabaseError) {
try {
progressBar?.visibility = View.GONE
Toast.makeText(activity, "Failed to fetch friend list ${error.message}", Toast.LENGTH_SHORT).show()
}catch (e: NullPointerException){
throw(IllegalAccessException(e.message))
}
}
})
}
}
FindFriendsAdapter.kt
package com.example.realtimechat.findfriends
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.GlideException
import com.example.realtimechat.R
import com.example.realtimechat.common.Constants
import com.example.realtimechat.common.NodeNames
import com.example.realtimechat.requests.RequestsFragment
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.storage.FirebaseStorage
class FindFriendAdapter(private val context: Context,
private val findFriendModelList: List<FindFriendModel> = mutableListOf()) : RecyclerView.Adapter<FindFriendAdapter.FindFriendViewHolder>() {
private var friendRequestDatabase: DatabaseReference? = null
private var currentUser: FirebaseUser? = null
private var userId: String? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FindFriendAdapter.FindFriendViewHolder {
val view: View = LayoutInflater.from(context).inflate(R.layout.custom_find_friends_layout, parent, false)
return FindFriendViewHolder(view)
}
override fun onBindViewHolder(holder: FindFriendAdapter.FindFriendViewHolder, position: Int) {
val friendModel = findFriendModelList[position]
holder.tvUsername.text = friendModel.username
val fileRef = FirebaseStorage.getInstance().reference.child(Constants.IMAGES_FOLDER + "/" + friendModel.photoFileName!!.substring(friendModel.photoFileName!!.lastIndexOf("/")+1))
fileRef.downloadUrl.addOnSuccessListener {uri ->
Glide.with(context)
.load(uri)
.placeholder(R.drawable.ic_profileicon)
.error(R.drawable.ic_profileicon)
.into(holder.ivProfile)
}
friendRequestDatabase = FirebaseDatabase.getInstance().reference.child(NodeNames.FRIEND_REQUESTS)
currentUser = FirebaseAuth.getInstance().currentUser
if(friendModel.requestSent!!){
holder.btnSendRequest.visibility = View.GONE
holder.pbRequest.visibility = View.VISIBLE
}else{
holder.btnSendRequest.visibility = View.VISIBLE
holder.pbRequest.visibility = View.GONE
}
holder.btnSendRequest.setOnClickListener {
holder.btnSendRequest.visibility = View.GONE
holder.pbRequest.visibility = View.VISIBLE
userId = friendModel.userId
friendRequestDatabase!!.child(currentUser!!.uid).child(userId!!).child(NodeNames.REQUEST_TYPE).setValue(Constants.REQUEST_STATUS_SENT)
.addOnCompleteListener { task ->
if(task.isSuccessful){
friendRequestDatabase!!.child(userId!!).child(currentUser!!.uid).child(NodeNames.REQUEST_TYPE)
.setValue(Constants.REQUEST_STATUS_RECEIVED)
.addOnCompleteListener { task ->
if(task.isSuccessful){
Toast.makeText(context, "Request sent successfully!", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.GONE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.VISIBLE
}
}.addOnFailureListener{ exception ->
Toast.makeText(context, "Failed to send request ${exception.localizedMessage}", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.VISIBLE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.GONE
}
}
}.addOnFailureListener{ exception ->
Toast.makeText(context, "Failed to send request ${exception.localizedMessage}", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.VISIBLE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.GONE
}
}
holder.btnCancelRequest.setOnClickListener {
holder.btnCancelRequest.visibility = View.GONE
holder.pbRequest.visibility = View.VISIBLE
userId = friendModel.userId
friendRequestDatabase!!.child(currentUser!!.uid).child(userId!!).child(NodeNames.REQUEST_TYPE).setValue(null)
.addOnCompleteListener { task ->
if(task.isSuccessful){
friendRequestDatabase!!.child(userId!!).child(currentUser!!.uid).child(NodeNames.REQUEST_TYPE)
.setValue(null)
.addOnCompleteListener { task ->
if(task.isSuccessful){
Toast.makeText(context, "Request cancelled successfully!", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.VISIBLE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.GONE
}
}.addOnFailureListener{ exception ->
Toast.makeText(context, "Failed to cancel request ${exception.localizedMessage}", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.GONE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.VISIBLE
}
}
}.addOnFailureListener{ exception ->
Toast.makeText(context, "Failed to cancel request ${exception.localizedMessage}", Toast.LENGTH_SHORT).show()
holder.btnSendRequest.visibility = View.GONE
holder.pbRequest.visibility = View.GONE
holder.btnCancelRequest.visibility = View.VISIBLE
}
}
}
override fun getItemCount(): Int {
return findFriendModelList.size
}
inner class FindFriendViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val ivProfile: ImageView = itemView.findViewById(R.id.ivProfilePic)
val tvUsername: TextView = itemView.findViewById(R.id.tvUsername)
val btnSendRequest: Button = itemView.findViewById(R.id.btnSendRequest)
val btnCancelRequest: Button = itemView.findViewById(R.id.btnCancelRequest)
val pbRequest: ProgressBar = itemView.findViewById(R.id.pbRequest)
}
}
错误代码将我引导至这部分代码:
override fun onCancelled(error: DatabaseError) {
try {
progressBar?.visibility = View.GONE
Toast.makeText(activity, "Failed to fetch friend list ${error.message}", Toast.LENGTH_SHORT).show()
}catch (e: NullPointerException){
throw(IllegalAccessException(e.message))
}
}
具体来说,这个:
throw(IllegalAccessException(e.message))
但是,原来的代码是:
override fun onCancelled(error: DatabaseError) {
progressBar?.visibility = View.GONE
Toast.makeText(activity, "Failed to fetch friend list ${error.message}", Toast.LENGTH_SHORT).show()
}
错误将我引导至
Toast.makeText(activity, "Failed to fetch friend list ${error.message}", Toast.LENGTH_SHORT).show()
对此问题的任何帮助/解决方案将不胜感激!
更新
我从override fun onCancelled(error: DatabaseError) 中删除了 Toast,代码运行正常。但是,我需要这个 Toast 是显而易见的,那么有没有办法解决这个问题?
【问题讨论】:
-
databaseReferenceFriendRequests可能为 Null 并导致问题 -
@chandmohd 我该如何解决这个问题?
-
@chandmohd 我已经添加了一个条件
if(databaseReferenceFriendRequests!=null),但错误仍然存在,所以我认为这不是解决方案 -
一般来说,你应该避免使用
var和nullable类型。如果你这样做了,请用null支票保护他们。浏览您的代码,我找不到您甚至拥有nullable类型的理由。如果你完全摆脱它,你将没有任何null-pointer exceptions。 -
不要使用
!!,除非您确定某些内容不能为空。通常没有必要使用它。
标签: android firebase authentication kotlin nullpointerexception