androidkotlinlocalbroadcastmanager

Kotlin LocalBroadcastManager not working after call to display values on UI


I have an android application I am working on in which I am making API request with Volley, after making the API call, I get a bunch of JSON objects returned. I now saved the values into a default values. after saving, I now tried displaying the values into my ui elements but everything is blank and does noy show the values. My codes are highlighted below

fun loginUser(context: Context, email: String, password: String, completion: (Boolean) -> Unit): Unit {

        val jsonBody = JSONObject()
        jsonBody.put("email", email)
        jsonBody.put("password", password)
        val requestBody = jsonBody.toString()

        val loginRequest = object : JsonObjectRequest(Method.POST, URL_LOGIN, null, Response.Listener {response ->

            try {
                userEmail = response.getString("user")
                authToken = response.getString("token")
                isLoggedIn = true
                completion(true)
            } catch (e: JSONException) {
                Log.d("JSON", "EXC:" + e.localizedMessage)
                completion(false)
            }
        }, Response.ErrorListener { error ->
            Log.d("ERROR", "Could not login user: $error")
            completion(false)

        }) {
            override fun getBodyContentType(): String {
                return "application/json; charset=utf-8"
            }
            override fun getBody(): ByteArray {
                return requestBody.toByteArray()
            }
        }
        Volley.newRequestQueue(context).add(loginRequest)
    }

fun findUserByEmail(context: Context, completion: (Boolean) -> Unit): Unit {
        val finUserByEmailRequest = object : JsonObjectRequest(Method.GET, "$URL_GET_USER$userEmail", null, Response.Listener {response ->
            try {
                UserDataService.name = response.getString("name")
                UserDataService.email = response.getString("email")
                UserDataService.avatarName = response.getString("avatarName")
                UserDataService.avatarColor = response.getString("avatarColor")
                UserDataService.id = response.getString("_id")
                val userDataChanaged = Intent(BROADCAST_USER_DATA_CHANGED)
                LocalBroadcastManager.getInstance(context).sendBroadcast(userDataChanaged)
                completion(true)
            } catch (e: JSONException) {
                Log.d("JSON", "EXC:" + e.localizedMessage)
                completion(false)
            }
        }, Response.ErrorListener { error ->
            Log.d("ERROR", "Could not find user: $error")
            completion(false)

        }) {
            override fun getBodyContentType(): String {
                return "application/json; charset=utf-8"
            }
            override fun getHeaders(): MutableMap<String, String> {
                val headers = HashMap<String, String>()
                headers["Authorization"] = "Bearer $authToken"
                return headers
            }
        }
        Volley.newRequestQueue(context).add(finUserByEmailRequest)
    }

my MainActivity

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setSupportActionBar(toolbar)
        val toggle = ActionBarDrawerToggle(
                this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
        drawer_layout.addDrawerListener(toggle)
        toggle.syncState()
   LocalBroadcastManager.getInstance(this).registerReceiver(userDataChangeReceiver, IntentFilter(BROADCAST_USER_DATA_CHANGED))
    }

    private val userDataChangeReceiver = object : BroadcastReceiver() {
        override fun onReceive(contect: Context?, intent: Intent?) {
            if (AuthService.isLoggedIn) {
                userNameNavHeader.text = UserDataService.name
                userEmailNavHeader.text = UserDataService.email

                val resourceId = resources.getIdentifier(UserDataService.avatarName, "drawable", packageName)
                userImageNavHeader.setImageResource(resourceId)
                userImageNavHeader.setBackgroundColor(UserDataService.returnAvatarColor(UserDataService.avatarColor))
                loginBtnNavHeader.text = "Logout"
            }
        }
    }

Where loginUser method gets called

fun loginLoginBtnClicked(view: View): Unit {

        val email = loginEmailTxt.text.toString()
        val password = loginPasswordTxt.text.toString()

        AuthService.loginUser(this, email, password) {success ->
            if (success) {
                AuthService.findUserByEmail(this) {fsuccess ->
                    if (fsuccess) {
                        finish()
                    }
                }
            }

        }
    }

Solution

  • You first need to obtain the reference to the nav_header_main layout first to be able to update the text-View and image-view in the nav_header_main. Instead of using the id of the elements directly you should use nav_header reference then id like this

    private val userDataChangeReceiver = object: BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
    
            if(AuthService.isLoggedIn){
                Log.d("qwe", UserDataService.name)
                Log.d("qwe", UserDataService.email)
                Log.d("qwe", UserDataService.avatarName)
                Log.d("qwe", "Made it inside the broadcast bro")
    
                Log.d("qwe", "Wrap")
    
    
                nav_drawer_header_include.userEmailNavHeader.text = UserDataService.email
                nav_drawer_header_include.userNameNavHeader.text = UserDataService.name
                userEmailNavHeader.text = UserDataService.email
                val resourseid= resources.getIdentifier(UserDataService.avatarName,"drawable",packageName)
                nav_drawer_header_include.userImageNavHeader.setImageResource(resourseid)
                nav_drawer_header_include.loginBtnNavHeader.text="Logout"
    
    
    
            }
    
        }
    }
    

    We should use Log most often, it helped me to get to the problem directly instead of wasting my time on perfectly fine working things.

    I too stumbled on this problem while doing the Android Kotlin course but after searching I found this is faced by many people they asked question on different platforms but no answer was provided. But after searching same terms "UI elements not updating android" found some stack overflow answers in java How to change text of a TextView in navigation drawer header?

    They all explained to first get reference then we can be able to update the View. Then I tried and fortunately it worked perfectly fine.

    PS: This is my first answer please don't mind the mistakes, I apologize.