retrofit problem z synchronicznym wywołaniem

0

witam,
chcę aby aplikacja wysłała hasło i login do serwera i w odpowiedzi dostała token ( jeżeli złe hasło to null)
mam taki kod

Retrofit.Builder builder = new Retrofit.Builder()
                .baseUrl(ConstantsValues.SERVER_URL)
                .addConverterFactory(GsonConverterFactory.create());
        Retrofit retrofit = builder.build();
        UserRetrofitService userService = retrofit.create(UserRetrofitService.class);
        Call<String> call = userService.getToken(user);
        try {
            token =call.execute().body();
        } catch (IOException e) {

        }
        if(token == null){
            return false;
        }
        return true;

jednak aplikacja się wyłącza podczs wykonywania gdy dochodzi do call.execute()

0

Nie możesz w Androidzie wywoływać zapytań sieciowych synchronicznie. Musisz to zrobić w wątku roboczym, nie na UI. Jak chcesz to zrobić przez retrofita2 to jest taka metoda jak enqueue

0

ok
a jak to zrobić tak, żeby aplikacja czekała na odpowiedź servera i dopiero szła dalej i przechodziłą do innej karty? Bo jeżeli wątek główny pójdzie dalej to wykona to co powinno się stać po otrzymaniu informacji z servera

0

Możesz wywołać akcję po tym jak przyjdzie status 200 i Twój token. Taką akcją może być odblokowanie onClicka na karcie. Tutaj ogranicza Cię już tylko wyobraźnia. Enqueue jako parametr przyjmuje interfejs callback który ma dwie metody onFailure i onResponse. W onResponse jesteś w stanie sprawdzić czy zapytanie się powiodło bo jest metoda isSuccess na polu typu Response.

0

Ja proponuje użyć do tego interfejsu authenticator, i Interceptora do dodania w nagłówku.
W metodzie override fun authenticate(route: Route, response: Response): Request wywołujemy synchronicznie pobranie tokena i z głowy. W necie jest jak tego używać.

Ogólnie idea jest taka, że wywołujemy metody Api bez konieczności przekazywania tokena / logowania się, a odpowiednia implementacja tego interfejsu pozwala na obsłużenie błędu 401.
Z punktu widzenia reszty aplikacji nie musimy martwić się czy token jest aktywny, czy wygasł, jeżeli wygasł, to w metodzie authenticate pobiera się nowy, i można powtórzyć zapytanie do serwera, tak, że reszta aplikacji tego nie widzi.

0

Spróbowałem napisać to inaczej

Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(ConstantsValues.SERVER_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        UserRetrofitService userService = retrofit.create(UserRetrofitService.class);
        Call<String> call = userService.getToken(user);    // tu się wysypuje
        call.enqueue(new retrofit2.Callback<String>() {
            @Override
            public void onResponse(Call<String> call, retrofit2.Response<String> response) {
                String token = response.body().toString();
                AuthService.setToken(token);
                if(token != null) {
                    Toast.makeText(LoginActivity.this, token, Toast.LENGTH_LONG).show();
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);
                }

dostaję błąd illegal target expression "Could not execute non-public method for android:onClick" i nie wiem czym on jest spowodowany.
interface UserRetrofitService wygląda następująco

@POST("/user/getToken/")
    Call<String> getToken(@Body User user);
}
0

Could not execute method for android:onClick
taki błąd występuje, nie ten z non public

0

Jak dla mnie za mało danych, możesz pokazać coś więcej? Czy to samo dzieje się jak usuniesz

Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    startActivity(intent);

Kiedy ten kod się wywołuje? Po kliknięciu na button?

0

Problem rozwiązany :) okazało się ze importuje @get z biblioteki retrofit a uzywam wywołań funkcji z retrofit2 dzięki wszystkim za pomoc:)

0

Ten kod to rozwlekły syf. Używaj rxJava i lambdy, to samo napiszesz w 3 linijkach.

0

Czy lambda nie gryzie się ze starszymi wersjami API?
Chciałbym zobaczyć jak w 3 liniach zmieścić to wszystko?

0

Lambda się nie gryzie, stream api się gryzie. Samo wywołanie webserwisu to by było jakoś tak:

userService.getToken(user)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(token -> AuthService.setToken(token),throwable -> Log.e(TAG,throwable.getMessage))

Celowo tu pominąłem logikę związaną z tworzeniem activity (zresztą, ja bym to wydzielił do nowej metody).

0

Trochę jednak się gryzie, nie, że nie można, ale trzeba dodać jack itp https://developer.android.com/guide/platform/j8-jack.html. Jakoś mi nie podeszło. Za to z Kotlinem nieźle działa.
Przykład powyżej to tylko wywołanie już przygotowanej usługi, myślę, że dałoby się to też całkiem zwięźle bez rxjava napisać, faktycznie na dłuższą metę dodanie rxjava nie zaszkodzi.

0

@Andrzej Guziec RxJava najbardziej przydaje się, gdy trzeba wywołać kilka endpointów i przekazać wyniki pomiędzy nimi, to znakomicie skraca zapis. Co do lambdy, to znakomicie sprawdza się właśnie przy RxJava (skraca zapis), ale nie tylko - krócej można zapisać np przypisanie zdarzeń typu onClick, albo skrócić zapis opracji na kolekcjach Guava.

Co do dostępnych funkcjonalności Javy 8, to tu masz dokładne informacje: https://developer.android.com/studio/write/java8-support.html - same lambdy nie mają ograniczeń.

P.S. Jack jeszcze jest potrzebny, ale już niedługo, kolejna wersja Android Studio wprowadza obsługę Javy 8 na domyślnym kompilatorze javac, a Jack jest już deprecated.

0

@panryz: nie lubię retrolambda, wolę lambdy z javy 8. Co do daggera, to nie ma żadnego problemu z Jackiem, jak ci nie działa to znaczy że masz złą konfigurację w build.gradle (pewnie używasz apt)

0

lambd używam, od kiedy są w .net (c#), skracają zapis i robią swoje.
W Androidze zacząłem ich używać dopiero od kiedy przeszedłem na Kotlina.

0

Co się tak wszyscy upierają na tego Kotlina? In bardziej dziwaczna składnia tym lepiej?

0

Co do składni to chyba największe udziwnienia (jak dla mnie) to lambda zarówno w c# jak i java i kotlin. Faktycznie jak dostaje info z linta, że na końcu linii średnik jest nie potrzebny to jest dla mnie trochę dziwne ;)

Też nie lubię udziwnień, ale np. sprawdzenie czy zmienna jest nullem (dość często to sprawdzam) w javie to kilka linii.

0

Yhy, tak. Bo np po co switch to miał być switch. W kotlinie to when. Wszystko postawmy na głowie, wszystko inaczej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1