0

I have a problem I have not yet been able to understand, nor solve.

On my android project, I have a BaseActivity. There, among other functions, I decided to add a function to show or hide a loading view when necessary. It works as intended, but sometimes an error happens.

I will try to raise some important info about my project I think can be useful. My app is integrated with an external login app. I call it when the services I call need to refresh it's token. When the user logs in on the app, it calls a listener and give me back control on mine.

The problem is the next one:

I come to an activity that needs to call a service and I have the token all right, but then I lock the phone. After a long period of time, I unlock the phone and, from the same activity, I call again the service. My activity shows de loader as intended and, as my token is expired, I call the login app from it's SDK.

When I come back to my app, and I call the service I wanted successfully, the app tries to hide the loader. This is where the fail comes, as I can't change the visibility to GONE. I looked for it on the view hierarchy and find it, but with visibility = VISIBLE.

Here is the piece of code from the loader, hope someone can find where I'm making the mistake!

abstract class BaseActivity : DaggerAppCompatActivity(){
    // These are the IDS of the Views I'm adding to the activity, so I can track them and change their visibility
    var imgLoadingID = -1
    var rvLoadingID = -1

    fun showLoading() {
        // If the views are added I show them
        if (imgLoadingID > 0 && rvLoadingID > 0) {
            val imageView = findViewById<ImageView>(imgLoadingID)
            val relativeLayout = findViewById<RelativeLayout>(rvLoadingID)
            relativeLayout.visibility = View.VISIBLE
            imageView.visibility = VISIBLE
            imageView.isClickable = false
            imageView.isFocusable = false
        } else {
            // else I create them and show them
            val imgLoading = ImageView(this)
            imgLoading.id = View.generateViewId()
            imgLoadingID = imgLoading.id

            val maxpx = CustomUtils.ViewUtils.converIntToDps(65, this)
            Glide.with(this).asGif().load(R.mipmap.loading).into(imgLoading)
            val relativeLayout = RelativeLayout(this)
            relativeLayout.id = View.generateViewId()
            rvLoadingID = relativeLayout.id

            var params = RelativeLayout.LayoutParams(maxpx, WRAP_CONTENT)
            params.addRule(RelativeLayout.CENTER_IN_PARENT)
            relativeLayout.addView(imgLoading, params)
            relativeLayout.background = getDrawable(R.color.pure_white_97)
            relativeLayout.isClickable = true
            relativeLayout.isFocusable = true

            findViewById<ViewGroup>(android.R.id.content).addView(relativeLayout, RelativeLayout.LayoutParams(MATCH_PARENT,  MATCH_PARENT))

            imgLoading.visibility = VISIBLE
        }
        // I lock the back button so people don't cancel my requests
        esBackPressedBlocked = true
    }

    // Here I find the views and change their visibility.
    fun hideLoading(){

        if(imgLoadingID > 0 && rvLoadingID > 0) {
            val imageView = findViewById<ImageView>(imgLoadingID)
            val relativeLayout = findViewById<RelativeLayout>(rvLoadingID)
            relativeLayout.visibility = View.GONE
            imageView.visibility = View.GONE
        }

        esBackPressedBlocked = false
    }
}

I deleted some logs I added to the whole function, but when it fails, it enters on the hideLoading() function, even on the relativeLayout.visibility = View.GONE part.

The function used to be with the Views as an whole object instead of their ids, but I found it more reliable this way, and saving the views instead of their Id's had the same problem.

My main concern is how Android manages my application while the phone is locked for this period of time (the fails happened after 8-10 hours of inactivity). I think something there can be creating this issue. I thought also about the external Login app, since it's sdk is launching their app's intent and calling me from a listener when coming back, but, since my code is being executed, I think Android it's managing my views on an strange way. Or maybe I try to hide the loading view before I'm on the resumed activity... I don't really know.

BTW, I know there are easier solutions on showing a loader, but I wanted to create it the cleanest way. If you have any cleaner approach I'm open to any solution.

If there is anything unclear let me know in the comments, and I hope my English was clear enough to express myself, it's a tricky problem that I can't understand, so it's difficult for me to explain it.

Thanks!!

Davidaz
  • 56
  • 7
  • 1
    My guess is, when the bug occurs, you've accidentally added two `RelativeLayouts` to the activity. Then, you're successfully hiding one, but the original remains. When you do `relativeLayout.visibility = VIew.GONE`, you may want to print `relativeLayout.toString()` and verify that it is, in fact, the same one you're seeing on the view hierarchy. – greeble31 Dec 11 '18 at 18:37
  • Nice guess, I didn't thought about this possible issue... I will try to reproduce it and comment back with the results looking for that view. Thank you!! – Davidaz Dec 12 '18 at 07:46

0 Answers0