Office Hours Transcript: 2021-05-25

Tad joined

Hey Mark

hello, Tad!

 

how can I help you today?

Hey I’ve got an odd situation with Volley going on. Is that something you can brainstorm with me on?

I have not used Volley in several years

Hmmm…ok. Do you use a different library for what it does?

OkHttp and Retrofit, mostly

 

Volley is not well-maintained or well-supported, IMHO

ok - well the question also involves making sure I understand what is going on under the covers prior to me making a call to it.

yeah, if you have questions that are not tied into the Volley API, I can probably help

I’m not sure it is a Volley thing, although I’ve walked through enough times in the debugger now where I think it is some sort of race condition in there.

 

What I use it for is to make HTTPS calls to an API that is the backend of my website.

 

Validating user credentials, etc. etc.

 

When the app starts up, the entire flow works flawlessly.

 

But, for example, on some Samsung phones I notice if the user pops out to the phone settings, then turns off a permission that my app has been previously granted by the user (access to the microphone for example), what Samsung does is actually restart the app.

that is not unique to Samsung

When it does this, the Application class gets onCreate called, then whatever activity was previously active gets its onCreate called and so forth.

if the user revokes a dangerous permission, it should kill your process on all Android devices with runtime permissions (6.0 and higher)

Standard stuff I guess

right

OK so when I go through the same initialization sequence on that startup, Volley freezes.

 

I’ve traced it far enough where I know it is making the web call, I know it is getting data back from the web server.

 

Then nothing.

 

No error, no nothing.

 

Just goes into a black hole.

 

If I step through it in the debugger, this does not happen.

 

Hence me thinking it is a race condition of some sort.

I cannot explain how your revoked-permission scenario is different from any other cold start

Me either

by "Then nothing", do you mean that Volley does not call your listener with the results?

Except it doesn’t go through my "SplashActivity", which then would launch a main activity vs. going directly to "main" (or whatever other activity had previously been active)

 

Correct Volley does not

 

It also doesn’t call the error listener

 

It just…stops

 

And the app hangs, as if it is a deadlock on the UI thread

 

which it isn’t

with respect to SplashActivity, that’s probably because your task is still outstanding, and so Android wants to return to the last activity the user had been in

Yes I understand why it isn’t called on the restart

 

I was just mentioning that because it isn’t exactly the same code path

if you revoke the permission, then swipe the task off the overview screen, do you get the same stuck-Volley behavior?

Yes - my way to cause this behavior is to have the main screen of my app up.

 

Then hit the "multiple windows" button on the device (this is Samsung Android 8)

 

Swipe over to Settings

 

Change the permission

 

Then pop back to the app

 

It actually starts working until it hits that request of Volley to access my website

OK, no offense, though, but that’s not what I suggested trying

Doesn’t matter which web API I call - it’s all the same behavior

after the "Change the permission" step, swipe your app’s task off the overview screen, then launch the app normally from the launcher

Right - I thought you were asking how I get it to fail

now, I’m trying to see how important SplashActivity really is

ok one sec

with the task killed, your launcher icon should run you through your splash screen

I think at the moment that I change the permission, it restarts the app before I can do anything

the overview screen (where you are swiping between apps) should still have your app, and you should still be able to swipe and remove it

 

that removes your task, and it will cause Android to run your app normally from the launcher icon, rather than attempt to go directly to your main activity

What you are calling the "overview screen" is the view I get when I tap the icon on this device which shows me recently run apps?

 

(It’s an older Samsung S7)

 

"overview screen" is Google’s term for it

ok one second - I need to rebuild this app (another annoying issue I’m having with AS 4.2.1 is that it thinks it can’t delete the build directory for some reason, all of a sudden)…

 

Have you run into that with anyone else?

 

I assume it must be some sort of environment problem on my system, but I’ll be darned if I can tell.

the build directory problem? no

Started happening when I upgraded from 4.1.3

 

Yeah I’m having to do full rebuilds now a bunch.

 

OK just so I am clear

 

I start the app, get it to the main screen where it normally gets ok.

 

Then I use the overview screen to go to settings, and change the permission?

 

(or get to Settings however you want)

Then I go back to the overview screen, and swipe left on my app?

um, assuming left will swipe it off the screen, then yes

 

(the overview screen varies a lot)

Swipe off the screen - ok. I guess I don’t normally do that

 

ok going to settings

 

Swiped it off

now launch the app normally, and see if it gets hung up in the same spot

It did not

 

Started normally

OK, that’s kinda what I expected

 

my guess is that your problem is more tied to the process termination with the task still outstanding, rather than it being tied strictly to the permission revocation

 

you could test that via adb shell am kill ..., where ... is your application ID

onDestroy() gets called in these cases?

not necessarily

Hmmmm. ok

but your process goes "poof", so there will be nothing in memory, as you will have no more memory

I do have some "shut down" code where I stop the Volley Queue, clear out any pending requests, etc.

yeah, that shouldn’t be the problem here, since the process is gone

ok

anyway, so things work if your process is started normally and runs through your splash screen, but things break if your process is started and bypasses the splash screen

Right

 

The weird thing is that I’ve verified that in both cases, the https call gets made and valid data comes back.

 

It is what is happening with that return value after that point that is different

so, either the splash screen path is doing something important, or showing the splash screen is changing the conditions enough to avoid your presumed race condition, akin to how running in the debugger is changing the conditions

Right.

 

For all other activities, I have a base class that extends AppCompatActivity, and in that class in onCreate and onResume I’m verifying that the Volley queue is initialized prior to anything else getting done.

 

For all other activities other than splashactivity I mean

SplashActivity is not triggering a Volley request itself, I take it?

So I can see that on re-entry to the app, those methods are getting called, and Volley is getting initialized.

 

And of course, like I said it actually makes the call and receives data.

 

So it isn’t the queue or queue mechanincs

 

Something else

 

Back to what you are doing - I haven’t used okHttp directly. Does it offer the high level functionality of Volley or would I have to roll my own?

what specifically are you referring to with respect to Volley?

here is an example:

 
public static void performNonBlockingHttpGet(String url,
                                             HashMap<String, Object> params,
                                             final Response.Listener<String> listener,
                                             final Response.ErrorListener errorListener,
                                             int timeoutInSeconds) throws Exception {
    String newUrl;
    Timber.d("Lifecycle: performNonBlockingHttpGet with timeout: %d url: %s, Volley queue shows %s entries.", timeoutInSeconds, url,getRequestQueueCount());
    Response.Listener<String> internalListener = response -> {
        decrementRequestQueueCount();
        try {
            listener.onResponse(response);
            Timber.d("Lifecycle: performNonBlockingHttpGet for %s ends normally.", url);
        } catch (Exception e) {
            Timber.e("Lifecycle: performNnBlockingHttpGet for %s ends in exception: %s", url, e.getMessage());
            throw e;
        }
    };
    Response.ErrorListener internalErrorListener = error -> {
        decrementRequestQueueCount();
        try {
            errorListener.onErrorResponse(error);
            Timber.d("Lifecycle: performNonBlockingHttpGet for %s ends with an error:%s.",url, error.getMessage());
        } catch (Exception e) {
            Timber.e("Lifecycle: performNonBlockingHttpGet for %s ends in exception: %s", url, e.getMessage());
            throw e;
        }
    };
    if (params != null) {
        newUrl = createGetRequestUrl(url, params);
    } else {
        newUrl = createGetRequestUrl(url, null);
    }

    StringRequest request =
            new StringRequest(Request.Method.GET,
                    newUrl,
                    internalListener,
                    internalErrorListener) {
                @Override
                public Priority getPriority() {
                    return Priority.NORMAL;
                }
            };
    request.setRetryPolicy(new DefaultRetryPolicy(timeoutInSeconds * 1000,
            1,
            DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    addToRequestQueue(request, true);
 

I set two listeners, and make the Url call

 

Processing the result in my listeners

 

OkHttp uses one listener rather than two, and its setup work is simpler

And its supported :)

yes, they publish updates every month or so, as opposed to once in a blue moon for Volley

 

and, there are a lot more people out there who know how to help with OkHttp questions

How do I get around the fact that other libraries I am using (PubNub being one) also has their own dependency on OkHttp which may not be the version I would be using?

 

i.e. it is within their shipping library

Gradle will choose the newer of the requested versions

 

that occasionally causes problems, if the API changes

Yeah, I was using okHttp originally for some other reason, and when I upgraded my PubNub stopped working correctly and those guys said "don’t do that"

 

So I dropped it

FWIW, I’m using OkHttp with PubNub successfully on my main client’s project

Which version?

 

of each?

 

I’m using PubNub 5.0.0

we’re back on 4.35.0 of PubNub and 4.9.0 of OkHttp

That’s a pretty recent version of OkHttp right?

Interesting

 

I think the OkHttp that they use internally is fairly old

that’s certainly possible

Have you been pretty happy with PubNub? I’ve noticed a fair number of intermittent disconnects.

it’s been reasonable, but I wouldn’t run a nuclear power plant on it

It generally will always reconnect, but I’ve had to really tighten down my recovery code.

 

Probably a good thing anyway

 

Is your client using it world-wide or just in one region?

mostly US, with trace amounts elsewhere

Are you using the heartbeat mechanism?

I haven’t looked at the PubNub bits in quite some time, so I forget, sorry

I started, then stopped using it. For me decided it was ok to recover on re-connect rather than proactively detect disconnect.

 

Plus it costs extra $

 

I’ll look into OkHttp again, thanks.

 

Anything big on the horizon that you think is going to be a game-changer?

 

Android-wise?

not sure how far out of a horizon you’re considering

 

Jetpack Compose will be a game-changer, insofar as Google is going to push the heck out of it

Yep, that’s a good call.

that is supposed to ship 1.0.0 stable in July

Are they still supporting Flutter in a big way?

that’s actually about the only game-changer I can think of off the top of my head

 

Flutter? oh, yeah

 

lots of material on that at the recent Google I|O conference

So continuing to gain steam in your opinion…

I’m uncertain about the "gain" part

 

they have a fair bit of steam

 

I’m uncertain if it has hit a ceiling of adoption or not

That’s the real question

 

o me

 

to me

 

I’ve read a few articles in the last 6 months or so of the "So I decided to give Flutter a try and compare it to Xamarin" (or <name your other favorite>)

it certainly has its adherents

 

I would not be surprised if 5% of Android app development is done in Flutter today

 

I would be surprised if the figure were substantially higher than that

OK - thanks again for your insights, gonna jet.

have a pleasant evening!