【发布时间】:2021-10-26 14:16:21
【问题描述】:
我正在使用 Cloud Firestore 和 Kotlin 创建一个应用。当我单击登录按钮时,它将跳转到具有 homeFragment、搜索片段和 settingsFragment 的仪表板活动。在 settingsFragment 中,有一个编辑按钮可以让用户编辑他们的个人资料。但是当我点击编辑按钮时,程序会崩溃。你能帮我解决这个问题吗?
错误信息
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.spaceus, PID: 14094
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.spaceus/com.example.spaceus.ui.activities.UserProfileActivity}: kotlin.UninitializedPropertyAccessException: lateinit property mUserDetails has not been initialized
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: kotlin.UninitializedPropertyAccessException: lateinit property mUserDetails has not been initialized
at com.example.spaceus.ui.activities.UserProfileActivity.onCreate(UserProfileActivity.kt:41)
at android.app.Activity.performCreate(Activity.java:7802)
at android.app.Activity.performCreate(Activity.java:7791)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
SettingsFragment.kt
class SettingsFragment : Fragment() {
private var _binding: FragmentSettingsBinding? = null
private lateinit var mUserDetails: User
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
//notificationsViewModel =ViewModelProvider(this).get(NotificationsViewModel::class.java)
_binding = FragmentSettingsBinding.inflate(inflater, container, false)
val root: View = binding.root
val sharedPreferences = this.requireActivity().getSharedPreferences(Constants.MYSHOPPAL_PREFERENCES, Context.MODE_PRIVATE)
//val sharedPreferences = getSharedPreferences(Constants.MYSHOPPAL_PREFERENCES,Context.MODE_PRIVATE)
val username = sharedPreferences.getString(Constants.LOGGED_IN_USERNAME,"")!!
val email = sharedPreferences.getString(Constants.EMAIL,"")!!
//GlideLoader(this).loadUserPicture(mUserDetails.image.toUri(),iv_user_photo)
root.tv_username.text = "$username"
root.tv_email.text = "$email"
root.btn_logout.setOnClickListener {
FirebaseAuth.getInstance().signOut()
val intent = Intent(requireContext(), LoginActivity::class.java)
startActivity(intent)
Toast.makeText(activity, "Logout Successfully.", Toast.LENGTH_SHORT).show()
}
root.iv_edit.setOnClickListener{
val intent = Intent(requireContext(), UserProfileActivity::class.java)
startActivity(intent)
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
UserProfileActivity.kt
class UserProfileActivity : BaseActivity(), View.OnClickListener {
private lateinit var mUserDetails: User
private var mSelectedImageFileUri: Uri? =null
private var mUserProfileImageURL: String =""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_profile)
if(intent.hasExtra(Constants.EXTRA_USER_DETAILS)){
//Get the user details from instant as a ParcelableExtra.
mUserDetails = intent.getParcelableExtra(Constants.EXTRA_USER_DETAILS)!!
}
et_usernameProfile.isEnabled=false
et_usernameProfile.setText(mUserDetails.username)
et_emailProfile.isEnabled=false
et_emailProfile.setText(mUserDetails.email)
GlideLoader(this@UserProfileActivity).loadUserPicture(mUserDetails.image.toUri(),iv_user_photo)
iv_user_photo.setOnClickListener(this@UserProfileActivity)
btn_save.setOnClickListener(this@UserProfileActivity)
btn_cancel.setOnClickListener(this@UserProfileActivity)
}
override fun onClick(v: View?) {
if(v != null){
when (v.id){
R.id.iv_user_photo ->{
if(ContextCompat.checkSelfPermission(this,android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED){
//showErrorSnackBar("You already have the storage permission.",false)
Constants.showImageChooser(this)
}else{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),Constants.READ_STORAGE_PERMISSION_CODE)
}
}
R.id.btn_save ->{
if(validateUserProfileDetails()){
showProgressDialog("Please Wait ...")
if(mSelectedImageFileUri!=null)
FirestoreClass().uploadImageToCloudStorage(this,mSelectedImageFileUri)
else{
updateUserProfileDetails()
}
}
}
R.id.btn_cancel ->{
val intent = Intent(this@UserProfileActivity, DashboardActivity::class.java)
startActivity(intent)
}
}
}
}
private fun updateUserProfileDetails(){
val userHashMap =HashMap<String,Any>()
val mobileNumber = et_phoneProfile.text.toString().trim{it <= ' '}
val gender = if(rb_male.isChecked){
Constants.MALE
}else{
Constants.FEMALE
}
if(mUserProfileImageURL.isNotEmpty()){
userHashMap[Constants.IMAGE] = mUserProfileImageURL
}
if(mobileNumber.isNotEmpty()){
userHashMap[Constants.MOBILE]=mobileNumber
}
userHashMap[Constants.GENDER]= gender
userHashMap[Constants.COMPLETE_PROFILE] = 1
FirestoreClass().updateUserProfileData(this,userHashMap)
}
fun userProfileUpdateSuccess(){
hideProgressDialog()
Toast.makeText(this@UserProfileActivity,resources.getString(R.string.msg_profile_update_success),Toast.LENGTH_SHORT).show()
startActivity(Intent(this@UserProfileActivity, DashboardActivity::class.java))
finish()
}
override fun onRequestPermissionsResult(requestCode:Int,permissions:Array<out String>,grantResults:IntArray){
super.onRequestPermissionsResult(requestCode,permissions,grantResults)
if(requestCode == Constants.READ_STORAGE_PERMISSION_CODE){
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
//showErrorSnackBar("The storage permission is granted.",false)
Constants.showImageChooser(this)
}else{
Toast.makeText(this,resources.getString(R.string.read_storage_permission_denied),Toast.LENGTH_LONG).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK){
if(requestCode == Constants.PICK_IMAGE_REQUEST_CODE){
if(data !=null){
try{
//the uri of selected image from photo storage
mSelectedImageFileUri= data.data!!
GlideLoader(this).loadUserPicture(mSelectedImageFileUri!!,iv_user_photo)
}catch (e:IOException){
e.printStackTrace()
Toast.makeText(this@UserProfileActivity,resources.getString(R.string.image_selection_failed),Toast.LENGTH_SHORT).show()
}
}
}
}else if (resultCode == Activity.RESULT_CANCELED){
Log.e("Request Cancelled","Image selection cancelled")
}
}
private fun validateUserProfileDetails(): Boolean{
return when{
TextUtils.isEmpty(et_phoneProfile.text.toString().trim { it <= ' ' }) -> {
showErrorSnackBar(resources.getString(R.string.err_msg_enter_phoneNum),true)
false
}
else ->{
true
}
}
}
fun imageUploadSuccess(imageURL:String){
//hideProgressDialog()
mUserProfileImageURL = imageURL
updateUserProfileDetails()
}
}
FirestoreClass.kt
class FirestoreClass {
private val mFireStore = FirebaseFirestore.getInstance()
fun registerUser(activity: RegisterActivity, userInfo:User){
mFireStore.collection(Constants.USERS)
//Document ID for users fields.Here the document it is the User ID.
.document(userInfo.id)
.set(userInfo, SetOptions.merge())
.addOnSuccessListener {
activity.userRegistrationSuccess()
}
.addOnFailureListener { e ->
activity.hideProgressDialog()
Log.e(activity.javaClass.simpleName,"Error while registering the user.",e)
}
}
fun getCurrentUserID(): String{
//An Instance of currentUser using FirebaseAuth
val currentUser = FirebaseAuth.getInstance().currentUser
//A variable to assign the currentUserId if it is not null or else it will be blank
var currentUserID=""
if(currentUser != null){
currentUserID = currentUser.uid
}
return currentUserID
}
fun getUserDetails(activity: Activity){
//Here we pass the collection name from which we wants the data.
mFireStore.collection(Constants.USERS)
// The document id to get the Fields of user.
.document(getCurrentUserID())
.get()
.addOnSuccessListener { document ->
Log.i(activity.javaClass.simpleName,document.toString())
val user = document.toObject(User::class.java)!!
val sharedPreferences = activity.getSharedPreferences(Constants.MYSHOPPAL_PREFERENCES, Context.MODE_PRIVATE)
val editor : SharedPreferences.Editor = sharedPreferences.edit()
editor.putString(Constants.LOGGED_IN_USERNAME,"${user.username}")
editor.putString(Constants.EMAIL,"${user.email}")
editor.apply()
when(activity){
is LoginActivity ->{
activity.userLoggedInSuccess(user)
}
}
//END
}
.addOnFailureListener { e ->
when (activity){
is LoginActivity ->{
activity.hideProgressDialog()
}
}
Log.e(activity.javaClass.simpleName,"Error while getting user details",e)
}
}
fun updateUserProfileData(activity: Activity,userHashMap: HashMap<String,Any>){
mFireStore.collection(Constants.USERS).document(getCurrentUserID())
.update(userHashMap)
.addOnSuccessListener {
when(activity){
is UserProfileActivity -> {
activity.userProfileUpdateSuccess()
}
}
}
.addOnFailureListener { e ->
when (activity){
is UserProfileActivity -> {
//Hide the progress dialog if there is any error.And print the error in log.
activity.hideProgressDialog()
}
}
Log.e(activity.javaClass.simpleName,"Error while updating the user details.",e)
}
}
fun uploadImageToCloudStorage(activity:Activity,imageFileURI: Uri?){
val sRef: StorageReference = FirebaseStorage.getInstance().reference.child(
Constants.USER_PROFILE_IMAGE + System.currentTimeMillis() + "." +Constants.getFileExtension(activity,imageFileURI)
)
sRef.putFile(imageFileURI!!).addOnSuccessListener { taskSnapshot ->
Log.e("Firebase Image URL",taskSnapshot.metadata!!.reference!!.downloadUrl.toString())
taskSnapshot.metadata!!.reference!!.downloadUrl
.addOnSuccessListener { uri ->
Log.e("Downloadable Image URL",uri.toString())
when(activity){
is UserProfileActivity ->{
activity.imageUploadSuccess(uri.toString())
}
}
}
}
.addOnFailureListener{exception ->
when (activity){
is UserProfileActivity -> {
activity.hideProgressDialog()
}
}
Log.e(activity.javaClass.simpleName,exception.message,exception)
}
}
}
常量.kt
object Constants {
const val USERS : String = "users"
const val MYSHOPPAL_PREFERENCES:String = "MyShopPalPrefs"
const val LOGGED_IN_USERNAME: String = "logged_in_username"
const val EXTRA_USER_DETAILS:String = "extra_user_details"
const val READ_STORAGE_PERMISSION_CODE = 2
const val PICK_IMAGE_REQUEST_CODE = 1
const val MALE:String = "Male"
const val FEMALE:String = "Female"
const val MOBILE:String = "mobile"
const val GENDER:String = "gender"
const val IMAGE:String = "image"
const val EMAIL:String ="email"
const val COMPLETE_PROFILE:String = "profileCompleted"
const val USER_PROFILE_IMAGE: String = "User_Profile_Image"
fun showImageChooser(activity : Activity){
val galleryIntent = Intent(Intent.ACTION_PICK,MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
activity.startActivityForResult(galleryIntent, PICK_IMAGE_REQUEST_CODE)
}
fun getFileExtension(activity: Activity,uri: Uri?):String? {
return MimeTypeMap.getSingleton()
.getExtensionFromMimeType(activity.contentResolver.getType(uri!!))
}
}
【问题讨论】:
-
如果您遇到问题,最好在发布问题时创建MCVE。您为此问题发布了近 400(四百)行行代码。人们需要解析和尝试在线调试的内容很多。请编辑您的问题并隔离问题,这样可以增加获得帮助的机会。
-
intent.getParcelableExtra(Constants.EXTRA_USER_DETAILS)是什么意思? -
即时获取用户详细信息
-
如果记录值,是你想要的吗?
-
我认为我的问题是 SettingsFragment 在单击编辑按钮时无法转到 UserProfileActivity。如果LoginActivity->UserProfileActivity,就可以工作了。
标签: firebase android-studio kotlin android-fragments google-cloud-firestore