Как правильно установить ответ A Retrofit в MutableLiveData, чтобы он стал видимым - PullRequest
1 голос
/ 16 января 2020
  • Что я пытаюсь сделать: Я пытаюсь отобразить список городов в RecyclerView в MainActivity, и всякий раз, когда в списке городов нажимается WeatherDetailsActivity должен получить ответ от OpenWeather's API, используя Retrofit. Я использую MVVM архитектуру.
  • Что мне удалось сделать до сих пор: У меня есть список, отображаемый отлично, и даже ответ получен правильно в соответствии с POJO модель, но когда я нажимаю на город, он падает из-за NullPointerException.
  • TL; DR : я не понимаю, почему return weatherResult; в WeatherRepository.java всегда возвращает ноль.

  • Код:

WeatherRepository. java


public class WeatherRepository {
    final String TAG = this.getClass()
                           .getSimpleName();

    private static final String WEATHER_API_URL = "https://api.openweathermap.org/";
    private static WeatherRepository weatherRepository;
    private APIService apiService;
    MutableLiveData weatherResult;


    private WeatherRepository() {
        Retrofit retrofit = new Retrofit.Builder().baseUrl(WEATHER_API_URL)
                                                  .addConverterFactory(GsonConverterFactory.create())
                                                  .build();
        apiService = retrofit.create(APIService.class);
    }

    public synchronized static WeatherRepository getInstance() {
        if (weatherRepository == null) {
            return new WeatherRepository();
        }
        return weatherRepository;
    }

    public MutableLiveData<WeatherResult> getWeatherData(String city, String appid) {
        apiService.getWeatherData(city, appid)
                  .enqueue(
                          new Callback<WeatherResult>() {
                              @Override
                              public void onResponse(Call<WeatherResult> call, Response<WeatherResult> response) {

                                  if (response.isSuccessful()) {
                                      Log.i(TAG, "onResponse: " + response.body()
                                                                          .toString());
                                      //response.body() gets the value perfectly.
                                      weatherResult.setValue(response.body());
                                  }
                              }
                              @Override
                              public void onFailure(Call<WeatherResult> call, Throwable t) {
                                  t.printStackTrace();
                                  Log.d(TAG, "onFailure: " + t.getMessage());
                              }
                          });

        return weatherResult; //this always return null
    }
}



WeatherViewModel. java

public class WeatherViewModel extends ViewModel
{
    private String TAG = this.getClass().getSimpleName();
     private MutableLiveData<WeatherResult> data = new MutableLiveData<>();


    private String APP_ID = /*secret api key*/;


    public void getWeather(String city)
    {
        data.setValue(WeatherRepository.getInstance().getWeatherData(city,APP_ID).getValue()); // this line throws NullPointerException.
        Log.d(TAG, "WeatherViewModel: "+(data.toString()));
    }

    public LiveData<WeatherResult> getCityDetails()
    {
        return data;
    }

}


APIService. java

public interface APIService {

    //Weather API
    //http://samples.openweathermap.org/data/2.5/weather?q=London&appid={APP_ID}

    @GET("data/2.5/weather?")
    Call<WeatherResult> getWeatherData(@Query("q") String city,@Query("appid") String appID);

}

WeatherDetails. java

public class WeatherDetails extends AppCompatActivity {

    WeatherViewModel viewModel;
    TextView textView;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.weather_details);

        textView = findViewById(R.id.weather_info_text);
        viewModel = ViewModelProviders.of(this).get(WeatherViewModel.class);
    }

    @Override
    protected void onStart() {
        super.onStart();
        viewModel.getCityDetails().observe(this, new Observer<WeatherResult>() {
            @Override
            public void onChanged(WeatherResult weatherResult) {
                textView.setText(weatherResult.toString()); //this line throws NullPointerException
            }
        });
    }
}

Все, что я хочу, это вернуть Retrofit response и установить его в MutableLiveData<WeatherResult> так, чтобы он наблюдается внутри WeatherDetails.java и пользовательский интерфейс обновляется соответственно.

Я не понимаю, почему return weatherResult; в WeatherRepository.java всегда возвращает null

Теперь я не знаю, как поступить, я в конце веревки, поэтому я спрашиваю это здесь.

Incase Вы хотите чтобы посмотреть весь код , вот код на github . Спасибо за любую помощь.


ОБНОВЛЕНИЕ Я внес следующие изменения, чтобы решить NullPointerException, и cra sh исправлен. ссылка на diff


ОБНОВЛЕНИЕ 2 Вот окончательный рабочий код , что мне нужно было, чтобы избавиться от MutableLiveData в моем ViewModel классе, и вместо этого используйте public method в моем ViewModel в качестве оболочки для вызова вызова службы репозитория в API server. Вот ссылка на diff . Спасибо всем, кто помог.

...