- Что я пытаюсь сделать: Я пытаюсь отобразить список городов в
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 . Спасибо всем, кто помог.