在cardview中的线性布局中使用recylerview时,我遇到了一个奇怪的问题。当传入适配器/ recyclerview的初始数据不为空时,它可以正常工作。但是当我尝试动态添加项目时(当初始数据为空时),适配器设置了项目,调用了notifyDataSetChanged,但recyclerview保持为空。
如果我动态添加数据,当初始Collection不为空时,它可以完美地运行。它也在研究其他观点。有谁知道问题可能是什么?
提前致谢!
XML文件:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
</data>
<LinearLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbarComposer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:elevation="4dp"
app:title="@string/title_timeline"
app:titleTextColor="@color/white"
app:navigationIcon="@drawable/ic_arrow_back_black_24dp"
>
</android.support.v7.widget.Toolbar>
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/intercomsdk_white">
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="7dp"
android:background="#E1E2E4">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include android:id="@+id/messageCardView" layout="@layout/item_timeline_message"/>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
card_view:cardElevation="3sp"
card_view:cardUseCompatPadding="true"
android:layout_marginTop="-10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/commentRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#E1E2E4"
tools:listitem="@layout/item_timeline_comment"
android:layout_above="@+id/commentContainer"
android:minHeight="10dp"
android:layout_weight="1"
/>
<LinearLayout
android:id="@+id/commentContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@color/chatWhite">
<EditText
android:id="@+id/commentTextField"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColorHint="@color/chatTextGray"
android:textSize="14dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:paddingBottom="15dp"
android:layout_weight="0.8"
android:hint="@string/commentInputHint" />
<ImageButton
android:id="@+id/sendButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Verstuur"
android:src="@drawable/ic_send_button"
android:layout_gravity="center"
android:layout_marginRight="5dp"
android:tint="@color/chatSendButtonTint"
android:background="@color/chatWhite"
/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
</layout>
活动:
public class TimelineMessageActivity extends BaseActivity implements TimelineMessagePresenter.ViewInterface {
private TimelineMessagePresenter presenter;
private TimelineCommentAdapter adapter;
private TimelineDataManager timelineDataManager;
private NetworkClientInterface timelineNetworkClient;
private UserSettingsStoreInterface userSettingsStore;
private FragmentTimelineMessageBinding binding;
private Menu menu;
public int messageId;
private List<TimelineCommentModel> comments = new ArrayList<>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.userSettingsStore = new UserSettingsStore(getModel().getEnvironment());
this.timelineNetworkClient = new NetworkClient(getModel().getEnvironment(), getModel().getCredentialStore());
this.timelineDataManager = new TimelineDataManager(getModel().getTimelineStore(), timelineNetworkClient);
binding = DataBindingUtil.setContentView(this, R.layout.fragment_timeline_message);
adapter = new TimelineCommentAdapter(new TimelineCommentAdapter.Listener() {
@Override
public void didClickProfileImage(TimelineCommentModel item) {
}
@Override
public void didClickMention(int userId) {
presenter.didClickMention(userId);
}
}, getModel());
SlideInBottomAnimatorAdapter animatorAdapter = new SlideInBottomAnimatorAdapter(adapter, binding.commentRecyclerView);
binding.commentRecyclerView.setItemAnimator(new SlideInOutLeftItemAnimator(binding.commentRecyclerView));
binding.commentRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
binding.commentRecyclerView.setAdapter(animatorAdapter);
binding.commentRecyclerView.setLayoutManager(new LinearLayoutManager(this));
binding.refreshLayout.setOnRefreshListener(() -> presenter.refreshMessage());
binding.refreshLayout.setRefreshing(true);
presenter = new TimelineMessagePresenter(getModel(), getRouter(), this.timelineDataManager);
if(getIntent().getIntExtra("message_id", 0) > 0){
presenter.setMessageId(getIntent().getIntExtra("message_id", 0));
}
}
@Override
public void onDestroy() {
presenter = null;
super.onDestroy();
}
@Override
public void onStart() {
super.onStart();
presenter.attachView(this);
presenter.refreshMessage();
}
@Override
public void onStop() {
presenter.detachView();
View view = this.getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)this.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
super.onStop();
}
@Override
public void setComments(List<TimelineCommentModel> items) {
for(TimelineCommentModel model : items) {
this.comments.add(model);
}
adapter.setItems(this.comments);
binding.refreshLayout.setRefreshing(false);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void setTitle(int title){
this.getSupportActionBar().setTitle(this.getString(title));
}
@Override
public void setEditText(String text) {
binding.commentTextField.setText(text);
}
@Override
public void setButtonEnabled(boolean enabled) {
binding.sendButton.setEnabled(enabled);
binding.sendButton.setAlpha((float) (enabled ? 1.0 : 0.5));
}
@Override
public void didSendComment() {
binding.commentTextField.setText("");
presenter.refreshMessage();
}
public void setMessageId(int messageId){
this.messageId = messageId;
}
public void didClickMention(int userId){
getRouter().openUri(Uri.parse("flexappeal://users/"+userId));
}
public void didClickDeleteButton(int id){
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
dialog.setMessage(getString(R.string.confirm_delete_message));
dialog.setNegativeButton(R.string.no, (dialogInterface, i) -> {
dialogInterface.dismiss();
});
dialog.setPositiveButton(R.string.yes, (dialogInterface, i) -> {
presenter.didClickDeleteButton(id);
});
dialog.show();
}
@Override
public void didClickBackButton(){
this.finish();
}
}
主持人:
public class TimelineMessagePresenter extends BasePresenter<TimelineMessagePresenter.ViewInterface> {
interface ViewInterface extends BasePresenter.ViewInterface {
void setComments(List<TimelineCommentModel> items);
void setTitle(int title);
void didSendComment();
void setButtonEnabled(boolean enabled);
void setEditText(String text);
void didClickBackButton();
}
private TimelineViewModel message = new TimelineViewModel();
private List<TimelineCommentModel> comments = new ArrayList<>();
private String commentMessage;
private int messageId;
@NonNull private final TimelineDataManager dataManager;
private final boolean needsRefresh = true;
public TimelineMessagePresenter(@NonNull Model model, @NonNull RouterInterface router, @NonNull TimelineDataManager dataManager) {
super(model, router);
this.dataManager = dataManager;
}
@Override
protected void onAttachView() {
super.onAttachView();
getModel().getEventBus().register(this);
updateView();
}
@Override
protected void onDetachView() {
getModel().getEventBus().unregister(this);
super.onDetachView();
}
@Subscribe
public void onEvent(SocketEvent event) {
// TODO: handle new comment in message event as soon as we integrate realtime timeline as well
}
public void updateView() {
if (getView() != null) {
getView().setEditText(commentMessage);
getView().setComments(comments);
}
}
private boolean shouldEnableButton() {
return (commentMessage != null && commentMessage.length() > 0);
}
public void didClickHighFiveButton(){
dataManager.postLike(messageId).subscribe(message -> {
refreshMessage();
}, error -> {
Log.w("TimelinePresenter", error);
});
}
public void didClickSendCommentButton(){
this.dataManager.postComment(messageId, commentMessage).subscribe(result -> {
getView().didSendComment();
}, error -> {
Log.w("TimelinePresenter", error);
});
}
public void refreshMessage() {
dataManager.getMessageDetail(messageId).subscribe(messageDetail ->{
this.comments.clear();
this.message = createViewModelForTimelineMessage(messageDetail);
if(messageDetail.getComments() != null){
for(Comments comment : messageDetail.getComments()) {
this.comments.add(createViewModelForTimelineComment(comment));
}
}
updateView();
}, error -> {
Log.w("TimelineMessagePresenter", error);
});
}
private TimelineCommentModel createViewModelForTimelineComment(Comments c) {
TimelineCommentModel vm = new TimelineCommentModel();
vm.commentId = c.getId();
vm.createdBy = c.getUser();
vm.createdAt = c.getCreated_at_diff();
vm.message = c.getMessage();
return vm;
}
public void didChangeMessage(CharSequence message) {
this.commentMessage = message.toString();
if (getView() != null) {
getView().setButtonEnabled(shouldEnableButton());
}
}
public void setMessageId(int messageId){
this.messageId = messageId;
}
public void didClickMention(int userId){
getRouter().openUri(Uri.parse("flexappeal://users/"+userId));
}
public void didClickDeleteButton(int id){
dataManager.deleteMessage(id).subscribe(aBoolean -> {
getView().didClickBackButton();
}, error -> {
getView().didClickBackButton();
});
}
}
适配器:
class TimelineCommentAdapter extends BindingRecyclerViewAdapter<TimelineCommentModel, ItemTimelineCommentBinding> {
private final Listener listener;
private final Model model;
public TimelineCommentAdapter(Listener listener, Model model) {
super(R.layout.item_timeline_comment);
this.listener = listener;
this.model = model;
}
public interface Listener {
void didClickProfileImage(TimelineCommentModel item);
void didClickMention(int userId);
}
@Override
protected void bind(ItemTimelineCommentBinding binding, TimelineCommentModel item, int position) {
Picasso.with(binding.getRoot().getContext()).load(item.createdBy.getProfileImage()).into(binding.userProfileImage);
binding.userProfileImage.setOnClickListener(view -> listener.didClickProfileImage(item));
binding.userFullName.setText(item.createdBy.getFullName());
binding.ago.setText(item.createdAt);
}
@Override
protected void recycle(ItemTimelineCommentBinding binding) {
Picasso.with(binding.getRoot().getContext()).cancelRequest(binding.userProfileImage);
}
}
BindingRecyclerViewAdapter:
public abstract class BindingRecyclerViewAdapter<T, B extends ViewDataBinding>
extends RecyclerView.Adapter<BindingRecyclerViewAdapter<T, B>.ViewHolder> {
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final B binding;
public ViewHolder(B binding) {
super(binding.getRoot());
this.binding = binding;
this.itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (onItemClickListener != null) {
int position = getAdapterPosition();
if (position != RecyclerView.NO_POSITION) {
onItemClickListener.onItemClick(view, position);
}
}
}
}
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
private OnItemClickListener onItemClickListener;
private List<T> items;
private final int layoutRes;
public BindingRecyclerViewAdapter(@LayoutRes int layoutRes) {
this(layoutRes, null, null);
}
public BindingRecyclerViewAdapter(@LayoutRes int layoutRes, Collection<T> items) {
this(layoutRes, items, null);
}
public BindingRecyclerViewAdapter(@LayoutRes int layoutRes, Collection<T> items, OnItemClickListener onItemClickListener) {
this.layoutRes = layoutRes;
this.items = (items == null) ? new ArrayList<>() : new ArrayList<>(items);
this.onItemClickListener = onItemClickListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
B binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), layoutRes, parent, false);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
T item = items.get(position);
bind(holder.binding, item, position);
}
@Override
public void onViewRecycled(ViewHolder holder) {
recycle(holder.binding);
}
@Override
public int getItemCount() {
return items.size();
}
protected abstract void bind(B binding, T item, int position);
protected abstract void recycle(B binding);
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public List<T> getItems() {
return items;
}
public void setItems(Collection<T> items) {
this.items.clear();
if (items != null) {
this.items.addAll(items);
}
notifyDataSetChanged();
}
}
答案 0 :(得分:0)
这是由引用问题引起的,当您设置如下评论时:this.comments = items;
已添加到List
的评论的Adapter
中的引用已切换为不同的List
项目(但Adapter
仍然引用旧的List
}。
因此,要解决此问题,请尝试使用for循环将项添加到注释中,而不是使用新的List
项替换注释。只需遍历所有项目并将其添加到这样的评论中:
for(TimelineCommentModel model: items) {
this.comments.add(model);
}
答案 1 :(得分:0)
如果这样做没有用,那么你必须使scrollview无效,因为你将recyclerview放在其中
public void setComments(List<TimelineCommentModel> items) {
this.comments.clear();
this.comments.addAll(items);
adapter.notifyDatasetChanged();
binding.refreshLayout.setRefreshing(false);
}