0

I am using Android with java and Retrofit 2.9.0 with Gson converter. I have called a function login(email, password) which should return a Result. I want to make login with email and password using API build in laravel and also I want to use MVVM architecture with Android JAVA

public Result<LoggedInUser> login(String username, String password) {
    try {
        Call<LoggedInUser> call = RetrofitClient.getInstance().getApi().sendCredential(username, password);
        call.enqueue(new Callback<LoggedInUser>() {
            @Override
            public void onResponse(Call<LoggedInUser> call, Response<LoggedInUser> response) {
                      // I have get response here and can make object of LoggedInUser but how to return 
                      // object to this function: "public Result<LoggedInUser> login(String username, String                     
                      //password)"
            }

            @Override
            public void onFailure(Call<LoggedInUser> call, Throwable t) {

            }
        });
        return new Result.Success<>(/* object created in on response */);
    } catch (Exception e) {
        return new Result.Error(new IOException("Error Logging In", e));
    }
}

I also tried

public Result<LoggedInUser> login(String username, String password) {

    LoggedInUser apiResponse;
    try {
        Call<LoggedInUser> call = RetrofitClient.getInstance().getApi().sendCredential(username, password);
        Response<LoggedInUser> response = call.execute(); 
/* at this line i get this error and it move to exception:: D/NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: true*/
        apiResponse = response.body();
        return new Result.Success<>(apiresponse);
    } catch (Exception e) {
        e.printStackTrace();
        return new Result.Error(new IOException("Error Logging In", e));
    }
}

here is the exception

D/NetworkSecurityConfig: Using Network Security Config from resource network_security_config debugBuild: true W/System.err: android.os.NetworkOnMainThreadException W/System.err: at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1303) W/System.err: at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:333) W/System.err: at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:196) W/System.err: at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178) W/System.err: at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356) W/System.err: at java.net.Socket.connect(Socket.java:605)

i have also add network configuration with domain. Actually my API is http build on laravel i have also try


android:usesCleartextTraffic="true"

also the name in api and used in my Application in same

4
  • Welcome to StackOverflow. Please share more details regarding your issue -- header of topic says you have an error on this call, but body of your question says you have response from server, but would you like to pass the result to some other place of your code. Commented Nov 10, 2022 at 7:36
  • i get result in OnResponse but i want to return that result but due to asynchronous there is chance of whether OnResponse has or has not completed if try to use synchronous approach by using execute then it give configuration and main thread error Commented Nov 10, 2022 at 10:51
  • i Have Applied 2 Scenarios both have their respective issue Commented Nov 10, 2022 at 11:34
  • You should not do CPU expensive work in the main thread like network request. The only async network requests are the option here. I haven't met such retrofit usage for a while, the industry has moved forward with new approaches. If you are not restricted within this method, take a look on my code sample how to make web request safely in your android app. Commented Nov 10, 2022 at 13:27

1 Answer 1

0

Android has variety of network mechanisms:

platform native - AsyncTasks, CursorLoaders, Handlers, java native: Threads, Executors

All of them are rarely used nowadays. You still could count Handlers and Executors (and concurrency package overall from java), I mean you should know them.

What is popular for passed years is a Kotlin Flow. Before that - RxJava. Despite on the majority of new projects uses Kotlin Flow, RxJava usage is still widespread.

Code sample:

Retrofit and OkHttpClient:

        val url = context.getString(R.string.url)
        val retrofit = Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient)
            .baseUrl(url)
            .build()

        return retrofit.create(IApi::class.java)
        val logging = HttpLoggingInterceptor()
        logging.setLevel(HttpLoggingInterceptor.Level.BODY)

        val httpClient = OkHttpClient
            .Builder()
            .addInterceptor(logging)
            .build()

        return httpClient

Definition of REST Api for retrofit:

interface IApi {

    @Headers("Content-Type: application/json; charset=utf-8")
    @POST("/api/v1/account")
    suspend fun createProfile(
        @Header("Authorization") credentials: String,
        @Body person: PersonProfile
    ): Response<ApiResponse<PersonProfile>>

Definition of network call in the repository:

    fun createAccount(person: PersonProfile): Flow<Response<PersonProfile>> {
        return flow {
            val response = api.createProfile(
                credentials = AppCredentials.basic(person.contact, person.secret),
                person = person
            )
            if (response.isSuccessful) {
                var payload = response.body()!!
                emit(Response.Data(payload.payload))
            } else {
                val errorPayload = ApiResponseConverter().toDomain(response.errorBody()?.string()!!);
                emit(Response.Error.Message("${response.message()}:\n\n${errorPayload.payload}"))
            }
        }
            .catch { ex ->
                Log.e(App.TAG, "Failed to create account and process result on network layer", ex)
                emit(Response.Error.Exception(ex))
            }
    }

Async request and gathering result at the same place:

  fun createAnAccount(person: PersonProfile) {
        viewModelScope.launch {
            repository.cacheAccount(person)
                .flatMapConcat { it->
                    repository.createAccount(person)
                }
                .flatMapConcat { it ->
                    if (it is Response.Data) {
                        repository.cacheAccount(it.data)
                            .collect { it ->
                                // no op, just execute the command
                                Log.d(App.TAG, "account has been cached")
                            }
                    }
                    flow {
                        emit(it)
                    }
                }
                .catch { e ->
                    Log.e(App.TAG, "Got an exception during network call", e)
                    state.update { state ->
                        val errors = state.errors + getErrorMessage(PersonRepository.Response.Error.Exception(e))
                        state.copy(errors = errors, isLoading = false)
                    }
                }
                .collect { it ->
                    updateStateProfile(it)
                }
        }
    }

Here is official docs and codelab: https://developer.android.com/kotlin/flow https://developer.android.com/codelabs/advanced-kotlin-coroutines#0

Sign up to request clarification or add additional context in comments.

1 Comment

Actually I am working with Android with JAVA! share some solution in java. The solution you provide is in Kotlin and i am not able to work with kotlin

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.