如何解决:第一次调用OnCreate()时,我无法从Retrofit Concrete Class

时间:2019-06-17 23:38:19

标签: java android retrofit2

我正在使用Retrofit从REST API检索数据。首先,我在MainActivity上尝试了所有方法,并且效果很好。 然后,我将一些方法移至单例模式ClientApi类(这是正确的方法吗?我认为是正确的方法,但我做得不好) 现在,我看不到第一个OnCreate()方法的结果,我看到的只是“空”。 最终,如果我等待1秒钟并旋转手机以更改为横向(因此再次调用onCreate()),它将起作用。

public class MainActivity extends AppCompatActivity {
    //UI components
    TextView textViewHello;
    //variables
    private static final String TAG = "MainActivity";

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

        textViewHello = findViewById(R.id.text_hello);
        ClientApi clientApi = ClientApi.getInstance();
        Client client = clientApi.getClient(2);
        String clientString = client.toString();
        textViewHello.setText(clientString);
    }
}


public class ClientApi {

    private static final String TAG = "ClientApi";
    private static final String API_BASE_URL = "https://my-json-server.typicode.com/";
    private ClientsService clientsService;
    public Client client = new Client();

    private static ClientApi instance = null;

    private ClientApi() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        clientsService = retrofit.create(ClientsService.class);
    }

    public static ClientApi getInstance() {
        if (instance == null) {
            instance = new ClientApi();
        }
        return instance;
    }

    public Client getClient(int clientId){
        getClient1(clientId);
        return client;
    }

    private void getClient1(int clientId) {
        Call<Client> call = clientsService.getClient(clientId);
        call.enqueue(new Callback<Client>() {
            @Override
            public void onResponse(Call<Client> call, Response<Client> response) {
                if (response.isSuccessful()) {
                    client = response.body();
                    Log.d(TAG, "onResponse: response successfull, client: " + client);
                } else {
                    Log.d(TAG, "onResponse: response not successfull: " + response.code());
                }
            }

            @Override
            public void onFailure(Call<Client> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
            }
        });
    }
}

预期结果是在首次启动应用程序时查看有关一个客户端的信息。但是直到我变成风景或肖像我才能看到它。

3 个答案:

答案 0 :(得分:0)

调用clientApi.getClient(2)时,返回的立即值是 在您的ClientApi类中创建的客户端的新实例,因此,当再次调用OnCreate时,由于您的api已经完成,因此数据可用。

public Client client = new Client();

如果方法 private void getClient1(int clientId){...} 是异步的,则需要传递一个侦听器以接收您的API结果已返回数据

类似的东西

// create a interface to your response
public interface ApiResponse {
   onResponse(Object response);
}
//update your getClient method
public void getClient(int clientId, ApiResponse apiResponse){
    getClient1(clientId, apiResponse);
    return client;
}
//update your getClient1 method and call the listener
private void getClient1(int clientId, ApiResponse apiResponse) {
        Call<Client> call = clientsService.getClient(clientId);
        call.enqueue(new Callback<Client>() {
            @Override
            public void onResponse(Call<Client> call, Response<Client> response) {
                if (response.isSuccessful()) {
                    client = response.body();
                    // Call the listener
                    // apiResponse.onResponse(client)
                    Log.d(TAG, "onResponse: response successfull, client: " + client);
                } else {
                    Log.d(TAG, "onResponse: response not successfull: " + response.code());
                }
            }

            @Override
            public void onFailure(Call<Client> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
            }
        });
    }

然后在MainActivity中调用您的api方法

Client client = clientApi.getClient(2, new ApiResponse() {
    @Override()
    public void onResponse(Object response) {
       // response is your client data
    }

});

答案 1 :(得分:0)

这是因为在使用call.enqueue()时,您还没有意识到Retrofit在异步工作。第一次拨打以下电话时:

    ClientApi clientApi = ClientApi.getInstance();
    Client client = clientApi.getClient(2);
    String clientString = client.toString();
    textViewHello.setText(clientString);
client中的

ClientApi变量尚未用Retrofit调用中的数据填充。但是,当您等待1秒钟然后旋转设备时,您的client变量已经充满了上一次Retrofit调用中的数据。因此,您实际上没有在TextView中获取当前数据。

您需要使用回调或将TextView传递给ClientApi实例。

答案 2 :(得分:0)

您正在异步获取客户端,但是您正在像处理同步调用一样处理结果。 client将在调用onResponse之后保存您想要的值。我建议您创建一个私有侦听器,当client的值更改时,该侦听器将通知您。

为此,我可以这样进行:

public interface OnClientFetchedListener{
  void onClientFetched(Client client);
  void onError(String errorMessage);
}

然后在ClientApi类型的OnClientFetchedListener中创建一个成员并添加一个setter。然后,在成功或出错时调用调用适当的方法。可以通过以下方式实现:

public class ClientApi {

    private static final String TAG = "ClientApi";
    private static final String API_BASE_URL = "https://my-json-server.typicode.com/";
    private ClientsService clientsService;
    public Client client = new Client();

    private static ClientApi instance = null;

    //our listener is just here
    private OnClientFetchedListener listener;

    //our setter is just here
    public void setListener(OnClientFetchedListener listener){
      this.listener = listener;
    }

    private ClientApi() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        clientsService = retrofit.create(ClientsService.class);
    }

    public static ClientApi getInstance() {
        if (instance == null) {
            instance = new ClientApi();
        }
        return instance;
    }

    public Client getClient(int clientId){
        getClient1(clientId);
        return client;
    }

    private void getClient1(int clientId) {
        Call<Client> call = clientsService.getClient(clientId);
        call.enqueue(new Callback<Client>() {
            @Override
            public void onResponse(Call<Client> call, Response<Client> response) {
                if (response.isSuccessful()) {
                    client = response.body();

                  //invoke an appropriate method when on success
                  if(listener!=null)
                  {listener.onClientFetched(client);
                  }
                    Log.d(TAG, "onResponse: response successfull, client: " + client);
                } else {
                    Log.d(TAG, "onResponse: response not successfull: " + response.code());
                }
            }

            @Override
            public void onFailure(Call<Client> call, Throwable t) {
                Log.d(TAG, "onFailure: " + t.getMessage());
                //invoke an appropriate method when on failure
                  if(listener!=null)
                  {listener.onError(t.getMessage());
                  }
            }
        });
    }
}

然后,在onCreate内部,将侦听器设置为ClientApi对象,并侦听事件。您可以根据需要使活动/片段实现该接口。第一种方法可以通过以下方式实现:

public class MainActivity extends AppCompatActivity {
    //UI components
    TextView textViewHello;
    //variables
    private static final String TAG = "MainActivity";

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

        textViewHello = findViewById(R.id.text_hello);
        ClientApi clientApi = ClientApi.getInstance();

        //let's set our listener
        clientApi.setListener(new OnClientFetchedListener(){
        @Override
        public void onClientFetched(Client client)
        {
          if(client!=null)
          {
            String clientString = client.toString();
        textViewHello.setText(clientString);
          }
        }

        @Override
        public void onError(String errorMessage)
        {
        //log the error or something else
        }
        });


    }
}

无论如何,这就是我如何做到这一点。解决方案太多...