-1

I have a login view in an android app that I would like to function synchronously. That is, I want the user to stay on the page until the login rest call completes. If it fails, the user can reenter their id and password. If it is successful they are routed to a welcome page.

Retrofit gives examples of how to make synchronous calls. But it comes with a warning that "synchronous requests trigger app crashes on Android 4.0 or newer. You’ll run into the NetworkOnMainThreadException error." I've seen various responses on stackoverflow including using Otto and Robospice. Others to use homegrown listeners and others to use synchronous requests.

What would be the easiest, safest way to implement this functionality.

user6627139
  • 406
  • 6
  • 16

3 Answers3

0

If you run synchronous calls in retrofit, app will crashes on Android 4.0 or newer. You’ll run into the NetworkOnMainThreadException error. Synchronous methods provide the ability to use the return value directly, because the operation blocks everything else during your network request.

For non-blocking UI, you have to handle the request execution in a separated thread by yourself. That means, you can still interact with the app itself while waiting for the response. Ref: enter link description here

Siva Kumar
  • 61
  • 7
0

You can do the following:

Response<T> response = call.execute();
allexiusw
  • 1,533
  • 2
  • 16
  • 23
-3

You don't need synchronous requests to achieve this..

Synchronous requests are carried out on the main thread. In android the main thread is used for drawing your UI so carrying out a network request on that thread will block your UI hence Android raises an exception .

Asynchronous requests carry out the networking in a separate thread and have callbacks to deliver information back to the main thread. This is what you need.

Here's what the sample code using Retrofit would look like in your case

call.enqueue(new Callback<LoginResponse>() {  
    @Override
    public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
        if (response.isSuccessful()) {
            // status code 2xx. start welcome activity
        } else {
            // Recieved a response but not 2xx. 
            // Possibly authentication error. Show error message

        }
    }

    @Override
    public void onFailure(Call<LoginResponse> call, Throwable t) {
        // request could not be executed ( possibly no internet connection)

    }
}
ashkhn
  • 1,642
  • 1
  • 13
  • 18
  • That's what I'm currently doing. The question is how to get the result back to my calling fragment. I could pass an instance of the fragment but that seemed like it might not be the best thing to do as the fragment could be gone. Or I could use something like Otto or Robospice but that seems like overkill. Also, I'd like some representation on the login screen that the authentication was in progress so they don't navigate away. – user6627139 Jun 21 '17 at 16:44
  • That's what `onResponse` is for.. It delivers the response to your calling activity/fragment. You can just show an indeterminate `ProgressBar` before the `enqueue` call and hide it in the `onResponse` block – ashkhn Jun 22 '17 at 02:22
  • Yeah, I get all that. As I said, that's what I'm currently doing. I wanted to put my login rest request in a separate class (for testing, reuse, etc), with all the logic associated in sending and getting my response, not in the fragment or activity. Then have the fragment call a method on my rest service class and get notified on completion. – user6627139 Jun 27 '17 at 01:40
  • You should consider all your requirements and state them clearly when asking your question.. Based on your comments the question that you've asked is pretty much unrelated to the things you've posted as comments. That being said, Retrofit's `Callback` is an interface that your fragment can `implement` and handle the response. – ashkhn Jun 27 '17 at 02:08
  • The question is about Sync call request and not Async call. For eg: making n/w calls inside a service and then updating the SQLite db in onResponse(). This scenario will require Sync call and Async will not work. – Kaveesh Kanwal Jul 29 '17 at 09:41
  • The scenario posted in the question does not require synchronous calls.. And Services should not be used for making network requests anyway.. You should be using an IntentService or threads – ashkhn Jul 31 '17 at 03:22
  • There might be multiple cases why one should make synchronous call instead. For example: I plan to use loader with synchronous retrofit call, because loader already work's in background. Making retorfit asynchronous with loader seems odd to me. – Alex Nov 12 '17 at 23:33
  • Yes I agree that synchronous calls are preferred in a lot of situations but 'being able to move the login request to a different class' is certainly not one of them. The question asked for a way to implement a login request with progress which can easily be carried out asynchronously – ashkhn Nov 13 '17 at 09:02