簡體   English   中英

如何解決:第一次調用 OnCreate() 時,我無法從 Retrofit Concrete Class 檢索數據

[英]How to fix: The first time OnCreate() is called, I can't retrieve data from Retrofit Concrete Class

我正在使用 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());
            }
        });
    }
}

預期的結果是在第一次啟動應用程序時看到有關一個客戶端的信息。 但是直到我更改為橫向或縱向我才能看到它。

當調用 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
    }

});

這是因為您沒有意識到在使用call.enqueue()時 Retrofit 是異步工作的。 當您第一次調用以下內容時:

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

ClientApi client變量尚未填充來自 Retrofit 調用的數據。 但是當您等待 1 秒然后旋轉設備時,您的client變量已經填充了來自先前 Retrofit 調用的數據。 因此,您實際上並未在 TextView 中獲取當前數據。

您需要使用回調或將您的 TextView 傳遞給您的ClientApi實例。

您正在異步獲取您的客戶端,但您正在處理結果,就好像它是一個同步調用一樣。 client將在onResponseonResponse您想要的值。 我可以建議您創建一個私人偵聽器,當client的值發生變化時會通知您。

為此,我可以這樣進行:

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

然后在ClientApi中創建一個OnClientFetchedListener類型的成員並添加一個 setter。 然后在成功或錯誤時調用 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
        }
        });


    }
}

無論如何,這就是我能做到的。 解決方法太多了...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM