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;
    }