파이어베이스를 기반으로한 테스트용 채팅 앱구현 Android Chatting Test App based on Firebase with Kotlin(11)

이번편은 user fragment 부분과 기반앱의 common 패키지의 서비스 부분을 만든다.

 

일단 userfragment의 xml을 복사하고 java 파일을 변환해서 kt로 옮겨 복사한다.

구현중 내부에 UserPWActivity.kt 도  필요해서 xml과 java를 같이 복사해 변환하였다.

 

먼저 UserPWActivity는

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
 
class UserPWActivity : AppCompatActivity() {
 
    private var user_pw1: EditText? = null
    private var user_pw2: EditText? = null
    private var saveBtn: Button? = null
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_userpw)
 
        user_pw1 = findViewById(R.id.user_pw1)
        user_pw2 = findViewById(R.id.user_pw2)
 
        saveBtn!!.setOnClickListener{
 
                val pw1 = user_pw1!!.text.toString().trim { it <= ' ' }
                if (pw1.length < 8) {
                    helpers.showMessage(applicationContext, "Please enter at least eight characters.")
                    return@setOnClickListener
                }
                if (pw1 != user_pw2!!.text.toString().trim { it <= ' ' }) {
                    helpers.showMessage(
                        applicationContext,
                        "Password does not match the confirm password."
                    )
                    return@setOnClickListener
                }
                val user = FirebaseAuth.getInstance().currentUser
                user!!.updatePassword(pw1).addOnCompleteListener {
                    helpers.showMessage(applicationContext, "Password changed")
                    val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(user_pw2!!.windowToken, 0)
                    onBackPressed()
                }
        }
 
 
 
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

위와 같이 바꾸었다.

 

UserFragment는

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
 
@Suppress("DEPRECATION")
class UserFragment : Fragment() {
 
    companion object {
        private val PICK_FROM_ALBUM = 1
    }
 
    private var user_photo: ImageView? = null
    private var user_id: EditText? = null
    private var user_name: EditText? = null
    private var user_msg: EditText? = null
    private var userModel: UserModel? = null
    private var userPhotoUri: Uri? = null
 
 
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        val view = inflater.inflate(R.layout.fragment_user, container, false)
 
        user_id?.isEnabled = false
        user_photo?.setOnClickListener {
            val intent = Intent(Intent.ACTION_PICK)
            startActivityForResult(intent, PICK_FROM_ALBUM)
        }
 
        saveBtn.setOnClickListener{
           if (!validateForm()) return@setOnClickListener
 
                userModel?.usernm = user_name!!.text.toString()
                userModel?.usermsg =  user_msg!!.text.toString()
                val uid = FirebaseAuth.getInstance().currentUser!!.uid
                val db = FirebaseFirestore.getInstance()
 
                if (userPhotoUri != null)   userModel!!.userphoto = uid
 
                db.collection("users").document(uid)
                    .set(userModel!!)
                    .addOnSuccessListener {
                        if (userPhotoUri == null) {helpers.showMessage(activity!!"Success to Save.")}
                        else {
                            // small image
                            Glide.with(context!!)
                                .asBitmap().load(userPhotoUri).apply(RequestOptions().override(150150))
                                .into(object : SimpleTarget<Bitmap>() {
                                    override fun onResourceReady(
                                        bitmap: Bitmap,
                                        transition: Transition<in Bitmap>?
                                    ) {
                                        val baos = ByteArrayOutputStream()
                                        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
                                        val data = baos.toByteArray()
                                        FirebaseStorage.getInstance().reference.child("userPhoto/$uid")
                                            .putBytes(data)
                                        helpers.showMessage(activity!!"Success to Save.")
                                    }
                                })
                        }
                    }
            }
 
 
        changePWBtn.setOnClickListener {
            startActivity(Intent(activity, UserPWActivity::class.java))
        }
 
        getUserInfoFromServer()
        return view
    }
 
    private fun getUserInfoFromServer() {
        val uid = FirebaseAuth.getInstance().currentUser!!.uid
 
        val docRef = FirebaseFirestore.getInstance().collection("users").document(uid)
        docRef.get().addOnSuccessListener { documentSnapshot ->
            userModel = documentSnapshot.toObject<UserModel>(UserModel::class.java)
            user_id!!.setText(userModel?.userid)
            user_name!!.setText(userModel?.usernm)
            user_msg!!.setText(userModel?.usermsg)
            if (userModel?.userphoto != null && "" != userModel?.userphoto) {
                Glide.with(activity!!).load(FirebaseStorage.getInstance().getReference("userPhoto/" + userModel?.userphoto)).into(user_photo!!)
            }
        }
    }
 
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == PICK_FROM_ALBUM && resultCode == Activity.RESULT_OK) {
            user_photo!!.setImageURI(data?.data)
            userPhotoUri = data?.data
        }
    }
 
    private fun validateForm(): Boolean {
        var valid = true
 
        val userName = user_name!!.text.toString()
        if (TextUtils.isEmpty(userName)) {
            user_name!!.error = "Required."
            valid = false
        } else {
            user_name!!.error = null
        }
 
        val userMsg = user_msg!!.text.toString()
        if (TextUtils.isEmpty(userMsg)) {
            user_msg!!.error = "Required."
            valid = false
        } else {
            user_msg!!.error = null
        }
        helpers.hideKeyboard(activity!!)
 
        return valid
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
http://colorscripter.com/info#e" target="_blank" style="text-decoration:none;color:white">cs

 Userfragment는 위와 같이 구성하였다.

 

그러고서 실행을 하면 아래와 같은 오류가 난다.

 

textinputlayout의 문제인것 같아

<com.google.android.material.textfield.TextInputLayout ... 로 바꾸어 다시 실행하였다.

 

그러면 또 문제가 발생하는데 이는 아래와 같다.

 

이는 onCreatedView 생성시 버튼 id를 찾을 시간이 확보되지않아 발생하는 문제이므로

onViewCreated에 버튼 관련 동작을 넣어준다. 그것은 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
 
        user_photo?.setOnClickListener {
            val intent = Intent(Intent.ACTION_PICK)
            startActivityForResult(intent, PICK_FROM_ALBUM)
        }
 
        saveBtn.setOnClickListener{
            if (!validateForm()) return@setOnClickListener
 
            userModel?.usernm = user_name!!.text.toString()
            userModel?.usermsg =  user_msg!!.text.toString()
            val uid = FirebaseAuth.getInstance().currentUser!!.uid
            val db = FirebaseFirestore.getInstance()
 
            if (userPhotoUri != null)   userModel!!.userphoto = uid
 
            db.collection("users").document(uid)
                .set(userModel!!)
                .addOnSuccessListener {
                    if (userPhotoUri == null) {helpers.showMessage(activity!!"Success to Save.")}
                    else {
                        // small image
                        Glide.with(context!!)
                            .asBitmap().load(userPhotoUri).apply(RequestOptions().override(150150))
                            .into(object : SimpleTarget<Bitmap>() {
                                override fun onResourceReady(
                                    bitmap: Bitmap,
                                    transition: Transition<in Bitmap>?
                                ) {
                                    val baos = ByteArrayOutputStream()
                                    bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
                                    val data = baos.toByteArray()
                                    FirebaseStorage.getInstance().reference.child("userPhoto/$uid")
                                        .putBytes(data)
                                    helpers.showMessage(activity!!"Success to Save.")
                                }
                            })
                    }
                }
        }
 
 
        changePWBtn.setOnClickListener {
            startActivity(Intent(activity, UserPWActivity::class.java))
        }
 
    }
 
http://colorscripter.com/info#e" target="_blank" style="color:#4f4f4ftext-decoration:none">Colored by Color Scripter
 

 

이제 MyFirebaseMessagingService를 복사하고 매니패스트에 추가하자.

 

이는 간단히 kotlin converting 기능만으로 해결이 가능하다.

그리고


<service android:name=".common.MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

를 매니페스트에 추가하면된다.

 

그리고 MyAppGlideModule.kt 이 부분도 추가해준다.

 

 

 

 

이제 실행을 하면 저기 floating button(붉은 원에 녹색 + 모양)을 클릭했을때 에러가 나며 종료가 되는데,

이 부분이 문제이므로 따라가본다.

 

확인해보니

 

<android.support.v7.widget.RecyclerView 로 되어있던 xml 의 recyclerview를

<androidx.recyclerview.widget.RecyclerView로 바꾸니까 잘 되었다.

 

 

그 다음으로 여기서 아이디를 클릭하니까 에러가 났다.

 

 

아래와 같은 에러인데... 이는 Null에 대한 처리 문제인듯하다.

 

ChatActivity에서 아래와 같이 되어있는 부분을

일단 아래와 같이 바꾸어 주었다.

그러니까

위와 같은 에러가 생겼는데, 이는 앞선 문제와 동일하므로 onViewCreated으로 EventListener부분 옮겨주었다.

 

그러고나니 또 

위와 같은 에러가 발생하였는데 이를 확인해보면,

 

이때는 문제가 안생기는데 이 디버깅포인트가 다시 한번 호출 되어 아래와 같은 상황이 발생할때가 있다.

 

이때 usermodel의 uid가 null이므로 not null을 보장하는 uid!!을 사용하여 오류가 발생하는 것이다. 따라서 널처리를해주어야한다.

 

위와 같이 조건을 추가해주었고 아래와 같이 제대로 실행되는 것을 확인할 수 있다.

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유