Subkhan Sarif
Subkhan Sarif

Reputation: 469

Retrofit works but callback doesn't call success or failure methods - Android

I try to make a service that will connect to server using retrofit. But whenever I try to connect, it doesn't reach the callback success or failure methods. It does get the result but then it stopped before reaching success or failure methods so it makes my app not responding. I've done successfully using retrofit before but I didn't use service, and now I need to do this inside a service and it won't work. Please help me. Thanks in advance.

Here is my service class:

public class ConnectionService extends Service implements Messaging,UserManagement, Callback<Response>{

public final IBinder myBinder = new MyBinder();
public final RestAdapter restAdapter = new RestAdapter.Builder()
        .setEndpoint(Api.API_URL)
        .setClient(new OkClient(new OkHttpClient()))
        .setLogLevel(RestAdapter.LogLevel.FULL)
        .build();
private String jsonResponse = "";
private final Object object = new Object();
private Gson gson = new Gson();

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}

@Override
public IBinder onBind(Intent intent) {
    return myBinder;
}

@Override
public boolean getInbox(String token, long limit, long page) {
    return false;
}

@Override
public boolean getMessage(String token, int id_member, long limit, long page) {
    return false;
}

@Override
public boolean sendMessage(String token, int id_teman, String message) {
    return false;
}

@Override
public boolean hideMessage(String token, long id_message) {
    return false;
}

@Override
public boolean getToyotaMessage(String token, long limit, long page) {
    return false;
}

@Override
public void showNotification(String message) {

}

@Override
public boolean Signup(String fullname, String email, String password) {

    return false;
}

@Override
public Me Login(String email, String password) {
    Me me = new Me(email,password);
    Api.Login login = restAdapter.create(Api.Login.class);
    login.fetch(me,this);
    try{
        synchronized (object){
            object.wait();
            if(jsonResponse != null && !jsonResponse.equals("")){
                Type tipe = new TypeToken<ApiResponse<Me>>(){}.getType();
                ApiResponse<Me> apiResponse = gson.fromJson(jsonResponse,tipe);
                Metadata metadata = apiResponse.metadata;
                if(metadata.code==200){
                    return apiResponse.data.get(0);
                }
            }
        }
    }catch (Exception e){
        e.printStackTrace();
    }
    return null;
}

@Override
public void success(Response response, Response response2) {
    synchronized (object){
        jsonResponse = Utils.convertResultToString(response);
        Log.d(ConnectionService.class.getSimpleName(),"Success. Response: "+jsonResponse);
        object.notifyAll();
    }
}

@Override
public void failure(RetrofitError retrofitError) {
    synchronized (object){
        jsonResponse = null;
        object.notifyAll();
    }
}

public class MyBinder extends Binder{
    public ConnectionService getInstance(){
        return ConnectionService.this;
    }
}
}

The connection happens inside function Login.

Here's my Api Login interface:

public class Api {

public interface Signup{

    @POST(Methods.SIGNUP)
    void fetch(
            @Body Me me,
            Callback<Response> callback
    );
}
public interface Login{
    @POST(Methods.LOGIN)
    void fetch(
            @Body Me me,
            Callback<Response> callback
    );
}
}

And here's inside my mainActivity that calls Login method inside my service:

public class MainActivity extends ActionBarActivity {

public boolean isLoggedin = false;
public Me me = null;

public ConnectionService myService;
public ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        Log.d(MainActivity.class.getSimpleName(),"On Service Connected");
        myService = ((ConnectionService.MyBinder)iBinder).getInstance();
        login();
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Log.d(MainActivity.class.getSimpleName(),"On Service Connected");
        myService = null;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

private void login(){
    if(myService != null) {
        me = myService.Login(Settings.EMAIL, Settings.cred);
        if (me != null) {
            Log.d(MainActivity.class.getSimpleName(), "full name: " + me.fullname);
            isLoggedin = true;
        }
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

@Override
protected void onStart() {
    super.onStart();
    if(myService == null){
        bindService(new Intent(this,ConnectionService.class),serviceConnection, Context.BIND_AUTO_CREATE);
        //startActivity(new Intent(this,ConnectionService.class));
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    if(myService != null){
        unbindService(serviceConnection);
        //stopService(new Intent(this,ConnectionService.class));
    }
}
}

Response that I get after on Service Connected:

05-25 14:31:42.954    7006-7006/com.subkhansarif.connecionmodule D/MainActivity﹕ On Service Connected
05-25 14:31:42.993    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ ---> HTTP POST http://103.247.10.71/imsave/v3/account/login
05-25 14:31:42.993    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Content-Type: application/json; charset=UTF-8
05-25 14:31:42.993    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Content-Length: 57
05-25 14:31:42.993    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ {"email":"[email protected]","password":"a","id_member":0,"points":0}
05-25 14:31:42.993    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ ---> END HTTP (57-byte body)
05-25 14:31:43.180    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to find class referenced in signature (Ljava/nio/file/Path;)
05-25 14:31:43.180    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to find class referenced in signature ([Ljava/nio/file/OpenOption;)
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule I/dalvikvm﹕ Could not find method java.nio.file.Files.newOutputStream, referenced from method okio.Okio.sink
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to resolve static method 19323: Ljava/nio/file/Files;.newOutputStream (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Ljava/io/OutputStream;
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule D/dalvikvm﹕ VFY: replacing opcode 0x71 at 0x000a
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to find class referenced in signature (Ljava/nio/file/Path;)
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to find class referenced in signature ([Ljava/nio/file/OpenOption;)
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule I/dalvikvm﹕ Could not find method java.nio.file.Files.newInputStream, referenced from method okio.Okio.source
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule W/dalvikvm﹕ VFY: unable to resolve static method 19322: Ljava/nio/file/Files;.newInputStream (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Ljava/io/InputStream;
05-25 14:31:43.188    7006-7020/com.subkhansarif.connecionmodule D/dalvikvm﹕ VFY: replacing opcode 0x71 at 0x000a
05-25 14:31:43.813    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ <--- HTTP 200 http://103.247.10.71/imsave/v3/account/login (820ms)
05-25 14:31:43.813    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Date: Mon, 25 May 2015 07:31:43 GMT
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Server: Apache/2.4.10 (Unix) OpenSSL/1.0.1j PHP/5.6.3 mod_perl/2.0.8-dev Perl/v5.16.3
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ X-Powered-By: PHP/5.6.3
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Content-Length: 750
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Content-Type: application/json
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ X-Cache: MISS from webcache.cnrglab.itb.ac.id
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ X-Cache-Lookup: MISS from webcache.cnrglab.itb.ac.id:3128
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ X-Cache: MISS from webcache-ng.cnrglab.itb.ac.id
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ X-Cache-Lookup: MISS from webcache-ng.cnrglab.itb.ac.id:3128
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Via: 1.1 webcache.cnrglab.itb.ac.id (squid/3.5.4-20150510-r13825), 1.1 webcache-ng.cnrglab.itb.ac.id (squid/3.5.3)
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ Connection: keep-alive
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ OkHttp-Selected-Protocol: http/1.1
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ OkHttp-Sent-Millis: 1432539103202
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ OkHttp-Received-Millis: 1432539103816
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ {"metadata":{"code":200,"message":"OK","timestamp":"2015-05-25 14:31:43"},"data":[{"image":{"href":"http:\/\/103.247.10.71\/imsave\/assets\/member_image\/174","mime_type":""},"id_member":174,"fullname":"a","email":"[email protected]","phone":"4","birthday":null,"gender":null,"address":null,"city":null,"province":null,"country":"INDONESIA","zip":null,"latitude":null,"longitude":null,"location":null,"device":"EMAIL","login_method":"FB","points":20,"level":"1","badges":[],"created":"2015-05-22 19:29:34","token":"Un87jGj8DB6Q1Jhf08Acct1nsewQC0dwnlEG1YOFzVvAFNQFWrS8UTwn73dK3rgqMV7OTWttSZ4xMVdJm6Sh0oE8rRSvj9V543UYZorSowqbrEUNKM4KbJSCBL7UU30Y6UW6joZHUpSl3N9NzeyKXrnzcvt6yt5Fo2MHqLplaiHe5R2F6Aq42NDej6lRzqxYtkGU65fh"}],"pagination":{"page":1,"limit":1,"size":1}}
05-25 14:31:43.821    7006-7020/com.subkhansarif.connecionmodule D/Retrofit﹕ <--- END HTTP (750-byte body)

as seen in response above, it ends up after connection gets the result and never invoke success or failure methods.

Upvotes: 2

Views: 5107

Answers (2)

mhKarami
mhKarami

Reputation: 1014

In my case the problem was Android Studio Emulator . in real android device onFailure or onResponse always called . also add timeout to OkHttp :

    val httpClient = OkHttpClient.Builder()
        .readTimeout(60, TimeUnit.SECONDS)
        .connectTimeout(60, TimeUnit.SECONDS)
        .writeTimeout(60, TimeUnit.SECONDS)
        .build()

Upvotes: 1

roarster
roarster

Reputation: 4086

Well you shouldn't tell the main thread to wait. That's bad practice and is the reason you're seeing the ANR. Instead do it in a thread, though the point of the async call is that you don't need to wait.

If you really wanted to make a blocking call, why not rename your interface methods to return objects rather than void. Then you can follow the synchronous approach and you won't need your service extending Callback (which I'm not a big fan of btw).

Upvotes: 0

Related Questions