解决方法:第一次调用OnCreate()时,我无法从Retrofit Concrete类中检索数据



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

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());
            }
        });
    }
}

预期结果是在首次启动应用时查看有关一个客户端的信息。但是在我更改为横向或纵向之前,我看不到它。

当 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());
            }
        });
    }

然后在您的主活动中调用您的 api 方法

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

这是因为您没有意识到改造在使用call.enqueue()时是异步工作的。首次调用以下内容时:

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

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

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

您正在异步获取客户端,但您正在处理结果,就好像它是同步调用一样。 client将在调用onResponse后保存所需的值。我可以建议你创建一个私人侦听器,当client的值发生变化时会通知你。

为此,我可以这样进行:

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

然后在ClientApi类型为 OnClientFetchedListener 中创建一个成员并添加一个资源库。然后在成功或错误时调用 invoke 适当的方法。这可以通过以下方式实现:

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
        }
        });

    }
}

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

最新更新