添加数据为空时,RecyclerView不会更新

时间:2016-05-25 06:54:37

标签: android android-linearlayout android-adapter

在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();
    }

}

2 个答案:

答案 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);
}