Android 将 LiveData<> 分配给 ListView
Android Assign LiveData<> to ListView
我有一个显示用户的列表视图和一个适配器,可以在普通的用户数组列表上很好地协同工作
但是,我正在尝试实施 ViewModel,但无法让我的 ListView 适配器与 LiveData 一起使用。我无法让任何类似的 questions/answers 为我工作。
但这感觉相当基础,而且应该很容易。
public class MainActivity extends AppCompatActivity {
MainActivityViewModel mainActivityViewModel;
ListView usersLV;
UsersAdapter userAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
usersLV = findViewById(R.id.usersLV);
ArrayList<User> users = (ArrayList<User>)mainActivityViewModel.getUsers().getValue();
if (users != null){
userAdapter = new UsersAdapter(this,users);
usersLV.setAdapter(userAdapter);
}else{
Log.d("gwyd","user list was null");
userAdapter = new UsersAdapter(this,new ArrayList<User>());
usersLV.setAdapter(userAdapter);
}
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
if(users != null) {
userAdapter.setUsers(users);
}else {
Log.d("gwyd","no users found in db");
userAdapter.setUsers(new ArrayList<User>());
}
}
});
}}
视图模型:
public class MainActivityViewModel extends AndroidViewModel {
private DaoRepository daoRepository;
private LiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null){
updateUsersList();
}
return users;
}
public MainActivityViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
users = updateUsersList();
}
public LiveData<List<User>> updateUsersList(){
return daoRepository.getAllUsers();
}}
和用户适配器:
public class UsersAdapter extends ArrayAdapter<User> {
private List<User> users;
public void setUsers(List<User> users) {
this.users = users;
notifyDataSetChanged();
}
public UsersAdapter(Context context, List<User> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
User user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.user_list_item, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.userLvItemTV);
// Populate the data into the template view using the data object
tvName.setText(user.getUserName());
// Return the completed view to render on screen
return convertView;
}}
和 List_item 布局文件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/userLvItemTV"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
变化:
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
playerAdapter.notifyDataSetChanged();
}
});
收件人:
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
playerAdapter.setUsers(users);
}
});
然后在您的适配器中创建一个 setter 例如:
public void setUsers(List<User> users) {
this.users = users;
notifyDataSetChanged();
}
在对自己说了一些严厉的话之后,我想出了这个解决方案:
基本上与我所做的相同,但在您的观察者 onChange 方法中使用 getApplicationContext() 而不是 'this' 来初始化 ArrayAdapter。似乎无法从观察者内部访问活动上下文 class 并抛出导致混淆的模糊错误...
我需要阅读更多关于不同环境如何影响事物的信息。但如果没有人想出灌篮高手,这就是如何做到这一点,我可能会在几天内将其标记为答案,因为它似乎已经解决了问题。
主要活动:
public class MainActivity extends AppCompatActivity {
MainActivityViewModel mainActivityViewModel;
ListView usersLV;
UsersAdapter userAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
usersLV = findViewById(R.id.usersLV);
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
if(users != null) {
userAdapter =new UsersAdapter(getApplicationContext(), users);
usersLV.setAdapter(userAdapter);
}
userAdapter.notifyDataSetChanged();
}
});
}}
查看模型:
public class MainActivityViewModel extends AndroidViewModel {
private DaoRepository daoRepository;
private LiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null){
users = updateUsersList();
}
return users;
}
public MainActivityViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
users = updateUsersList();
}
public LiveData<List<User>> updateUsersList(){
return daoRepository.getAllUsers();
}}
数组适配器:
public class UsersAdapter extends ArrayAdapter<User> {
public UsersAdapter(Context context, List<User> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
User user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.user_list_item, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.userLvItemTV);
// Populate the data into the template view using the data object
tvName.setText(user.getUserName());
// Return the completed view to render on screen
return convertView;
}
}
列表项Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/userLvItemTV"
android:layout_width="match_parent"
android:textSize="20sp"
android:height="20dp"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:layout_height="60dp" />
</LinearLayout>
我建议直接在适配器中使用实时数据:
public class MyAdapter extends BaseAdapter {
private final Context mCtx;
private final LiveData<List<MyModel>> mLiveDate;
public MyAdapter(Context ctx, LiveData<List<MyModel>> livedata) {
mCtx = ctx;
mLiveDate= livedata;
livedata.observeForever(myModels -> notifyDataSetChanged());
}
@Override
public int getCount() {
if (mLiveDate.getValue() == null)
return 0;
return mLiveDate.getValue().size();
}
@Override
public MyModel getItem(int i) {
return Objects.requireNonNull(mLiveDate.getValue()).get(i);
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
...
MyModel data = getItem(i);
...
return view;
}
我有一个显示用户的列表视图和一个适配器,可以在普通的用户数组列表上很好地协同工作 但是,我正在尝试实施 ViewModel,但无法让我的 ListView 适配器与 LiveData 一起使用。我无法让任何类似的 questions/answers 为我工作。 但这感觉相当基础,而且应该很容易。
public class MainActivity extends AppCompatActivity {
MainActivityViewModel mainActivityViewModel;
ListView usersLV;
UsersAdapter userAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
usersLV = findViewById(R.id.usersLV);
ArrayList<User> users = (ArrayList<User>)mainActivityViewModel.getUsers().getValue();
if (users != null){
userAdapter = new UsersAdapter(this,users);
usersLV.setAdapter(userAdapter);
}else{
Log.d("gwyd","user list was null");
userAdapter = new UsersAdapter(this,new ArrayList<User>());
usersLV.setAdapter(userAdapter);
}
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
if(users != null) {
userAdapter.setUsers(users);
}else {
Log.d("gwyd","no users found in db");
userAdapter.setUsers(new ArrayList<User>());
}
}
});
}}
视图模型:
public class MainActivityViewModel extends AndroidViewModel {
private DaoRepository daoRepository;
private LiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null){
updateUsersList();
}
return users;
}
public MainActivityViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
users = updateUsersList();
}
public LiveData<List<User>> updateUsersList(){
return daoRepository.getAllUsers();
}}
和用户适配器:
public class UsersAdapter extends ArrayAdapter<User> {
private List<User> users;
public void setUsers(List<User> users) {
this.users = users;
notifyDataSetChanged();
}
public UsersAdapter(Context context, List<User> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
User user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.user_list_item, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.userLvItemTV);
// Populate the data into the template view using the data object
tvName.setText(user.getUserName());
// Return the completed view to render on screen
return convertView;
}}
和 List_item 布局文件
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/userLvItemTV"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
变化:
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
playerAdapter.notifyDataSetChanged();
}
});
收件人:
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
playerAdapter.setUsers(users);
}
});
然后在您的适配器中创建一个 setter 例如:
public void setUsers(List<User> users) {
this.users = users;
notifyDataSetChanged();
}
在对自己说了一些严厉的话之后,我想出了这个解决方案: 基本上与我所做的相同,但在您的观察者 onChange 方法中使用 getApplicationContext() 而不是 'this' 来初始化 ArrayAdapter。似乎无法从观察者内部访问活动上下文 class 并抛出导致混淆的模糊错误...
我需要阅读更多关于不同环境如何影响事物的信息。但如果没有人想出灌篮高手,这就是如何做到这一点,我可能会在几天内将其标记为答案,因为它似乎已经解决了问题。
主要活动:
public class MainActivity extends AppCompatActivity {
MainActivityViewModel mainActivityViewModel;
ListView usersLV;
UsersAdapter userAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mainActivityViewModel = ViewModelProviders.of(this).get(MainActivityViewModel.class);
usersLV = findViewById(R.id.usersLV);
mainActivityViewModel.getUsers().observe(this, new Observer<List<User>>() {
@Override
public void onChanged(@Nullable List<User> users) {
if(users != null) {
userAdapter =new UsersAdapter(getApplicationContext(), users);
usersLV.setAdapter(userAdapter);
}
userAdapter.notifyDataSetChanged();
}
});
}}
查看模型:
public class MainActivityViewModel extends AndroidViewModel {
private DaoRepository daoRepository;
private LiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
if (users == null){
users = updateUsersList();
}
return users;
}
public MainActivityViewModel(@NonNull Application application) {
super(application);
daoRepository = new DaoRepository(application);
users = updateUsersList();
}
public LiveData<List<User>> updateUsersList(){
return daoRepository.getAllUsers();
}}
数组适配器:
public class UsersAdapter extends ArrayAdapter<User> {
public UsersAdapter(Context context, List<User> users) {
super(context, 0, users);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
User user = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.user_list_item, parent, false);
}
// Lookup view for data population
TextView tvName = (TextView) convertView.findViewById(R.id.userLvItemTV);
// Populate the data into the template view using the data object
tvName.setText(user.getUserName());
// Return the completed view to render on screen
return convertView;
}
}
列表项Xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/userLvItemTV"
android:layout_width="match_parent"
android:textSize="20sp"
android:height="20dp"
android:fontFamily="sans-serif-medium"
android:gravity="center"
android:layout_height="60dp" />
</LinearLayout>
我建议直接在适配器中使用实时数据:
public class MyAdapter extends BaseAdapter {
private final Context mCtx;
private final LiveData<List<MyModel>> mLiveDate;
public MyAdapter(Context ctx, LiveData<List<MyModel>> livedata) {
mCtx = ctx;
mLiveDate= livedata;
livedata.observeForever(myModels -> notifyDataSetChanged());
}
@Override
public int getCount() {
if (mLiveDate.getValue() == null)
return 0;
return mLiveDate.getValue().size();
}
@Override
public MyModel getItem(int i) {
return Objects.requireNonNull(mLiveDate.getValue()).get(i);
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
...
MyModel data = getItem(i);
...
return view;
}