【发布时间】:2018-02-03 23:43:08
【问题描述】:
我一直在用头撞墙,我不明白为什么会这样。我正在使用适用于 Android 的新架构组件,但在使用对象列表更新 LiveData 时遇到问题。 我有两个旋转器。当我更改第一个选项时,第二个必须更改其内容。但是最后一部分没有发生。 谁能帮帮我?
State.java
@Entity(tableName = "states")
public class State{
@PrimaryKey(autoGenerate = false)
private int id;
private String name;
@ColumnInfo(name = "countryId")
private String CountryId;
@Ignore
private Object geoCenter, geoLimit;
public State(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCountryId() {
return CountryId;
}
public void setCountryId(String countryId) {
CountryId = countryId;
}
}
StateDAO
@Dao
public interface StateDao {
@Query("SELECT * FROM states")
LiveData<List<State>> getAllStates();
@Query("SELECT * FROM states WHERE countryId = :countryID")
LiveData<List<State>> getStatesFromCountry(String countryID);
@Query("SELECT COUNT(*) FROM states")
int getNrStates();
@Query("SELECT COUNT(*) FROM states WHERE countryId = :countryID")
int getNrStatesByCountry(String countryID);
@Insert(onConflict = IGNORE)
void insertAll(List<State> states);
@Delete
void delete(State state);
}
StateRepository
@Singleton
public class StatesRepository {
private final WebServices services;
private final StateDao stateDao;
private final Executor executor;
@Inject
public StatesRepository(Executor executor, StateDao stateDao, WebServices services) {
this.services = services;
this.stateDao = stateDao;
this.executor = executor;
}
public LiveData<List<State>> getStates(String token){
refreshStates(token);
return stateDao.getAllStates();
}
public LiveData<List<State>> getStatesFromCountry(String countryID){
return stateDao.getStatesFromCountry(countryID);
}
private void refreshStates(final String token){
executor.execute(() -> {
Log.d("oooooo", stateDao.getNrStates() + "");
if(stateDao.getNrStates() == 0){
try {
Response<List<State>> response = services.getStates("Bearer "+token).execute();
stateDao.insertAll(response.body());
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
StateViewModel
public class StatesViewModel extends ViewModel {
private LiveData<List<State>> states;
private StatesRepository repo;
@Inject
public StatesViewModel(StatesRepository repository){
this.repo = repository;
}
public void init(String token){
states = repo.getStates(token);
}
public void getStatesFromCountry(String countryID){
states = repo.getStatesFromCountry(countryID);
}
public LiveData<List<State>> getStates(){
return this.states;
}
}
片段
public class EditAddressFragment extends LifecycleFragment implements View.OnClickListener, Injectable{
private Spinner country, city, state, zip_code;
private String token;
private List<Country> countries;
private List<City> cities;
private List<State> states;
@Inject ViewModelFactory viewModelFactory;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.addresses_edit_layout, container, false);
city = view.findViewById(R.id.city);
state = view.findViewById(R.id.state);
country = view.findViewById(R.id.country);
...
countries = new ArrayList<>();
cities = new ArrayList<>();
states = new ArrayList<>();
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
CountrySpinnerAdapter adapter = new CountrySpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, countries);
country.setAdapter(adapter);
CitySpinnerAdapter cityAdapter = new CitySpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, cities);
city.setAdapter(cityAdapter);
StateSpinnerAdapter stateAdapter = new StateSpinnerAdapter(getActivity(), android.R.layout.simple_spinner_item, states);
state.setAdapter(stateAdapter);
CountriesViewModel countriesViewModel = ViewModelProviders.of(this, viewModelFactory).get(CountriesViewModel.class);
countriesViewModel.init(token);
countriesViewModel.getCountries().observe(this, adapter::setValues);
CityViewModel cityViewModel = ViewModelProviders.of(this, viewModelFactory).get(CityViewModel.class);
cityViewModel.init(token);
cityViewModel.getCities().observe(this, cityAdapter::setValues);
StatesViewModel statesViewModel = ViewModelProviders.of(this, viewModelFactory).get(StatesViewModel.class);
statesViewModel.init(token);
statesViewModel.getStates().observe(this, states -> {
Log.d("called", states.toString());
stateAdapter.setValues(states); } );
country.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
Country c = (Country) adapterView.getItemAtPosition(i);
Log.d("cd", c.getId());
//states = new ArrayList<State>();
statesViewModel.getStatesFromCountry(c.getId());
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
....
适配器
public void setValues(List<State> states)
{
this.states = states;
Log.d("s", states.isEmpty()+" "+states.toString());
notifyDataSetChanged();
}
【问题讨论】:
-
很难看到全貌……(我最初以为你没有 LiveData)但你有。但是,我建议你检查你的线程/并发性,因为你在你的 repo 中使用了一个执行器……我采取的方法(我认为)是每个微调器都在观察 LiveData(不同),并且 ViewModel 会确保在UI/Spinner1 发生变化,因此 UI/Spinner2 观察到的 LiveData 发生变化。如果这是你在 atm 做的,在代码中很难看到。
-
@MartinMarconcini 我在存储库中执行此操作,因为那是我拥有 DAO 实例的地方。 MY Repository 是我调用 API 或数据库的地方。在这种情况下,我只需要转到本地数据库,因为之前我已经检索了所有状态。从我所有的测试来看,他显然可以从数据库中获取值,但是没有调用观察者的 onchange 方法。
-
@MartinMarconcini 就是这样。我有两个不同的微调器观察两个不同的 LiveData。我还看到有人在谈论线程问题,但我使用的是同一个 DAO 实例,所以我认为应该没有任何问题......
-
值得注意的是,我在 RXJava2 中也使用了所有这些新的废话……但我非常怀疑这与任何事情有关。
-
您的
StatesRepository是单身人士吗?如果您有两个数据库实例,来自一个实例的事件不会传播到另一个实例上设置的观察者。
标签: android viewmodel dagger-2 android-room dagger