【问题标题】:FirebaseRecyclerAdapter for use in a messaging appFirebaseRecyclerAdapter 用于消息传递应用程序
【发布时间】:2017-09-02 15:52:34
【问题描述】:

我已经搜索了 FirebaseRecyclerAdapter 和相关类的文档,但找不到一种方法来做我想做的事(不自己重建库)。

我正在开发一个内置消息传递功能的应用程序(包括群组和直接向其他用户发送消息)。

群聊有效,因为它从群聊节点下的数据库引用中提取每条消息。

直接消息很棘手。我想跳过参考中不包含当前用户的模型 ID 的节点,以及他们尝试发送消息的用户(这样他们就看不到其他人的消息)。

在下面的代码中,如果 viewType = 10,我会尝试返回 null,因为我不希望显示聊天气泡...正如您所期望的那样,我从 RecyclerViewAdapter 类中得到一个空指针异常。

我知道为什么我会收到错误消息。我故意将 null 传递给它,以尝试跳过(或迭代当前项目),而不在任何位置显示聊天气泡。

这是我的 firebase 结构(导出的 JSON):Database Structure

这是一个堆栈跟踪供参考:

FATAL EXCEPTION: main
                                                                         Process: com.aztechdev.squad, PID: 21249
                                                                 java.lang.NullPointerException: Attempt to write to field 'int android.support.v7.widget.RecyclerView$ViewHolder.mItemViewType' on a null object reference
                                                                     at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6368)
                                                                     at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5555)
                                                                     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)
                                                                     at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)
                                                                     at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
                                                                     at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
                                                                     at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
                                                                     at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:570)
                                                                     at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3583)
                                                                     at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3312)
                                                                     at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3844)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                     at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                                                     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                                                     at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                     at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at com.mxn.soul.flowingdrawer_core.FlowingDrawer.onLayout(FlowingDrawer.java:138)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.support.v4.view.ViewPager.onLayout(ViewPager.java:1795)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.support.constraint.ConstraintLayout.onLayout(ConstraintLayout.java:1197)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.support.design.widget.HeaderScrollingViewBehavior.layoutChild(HeaderScrollingViewBehavior.java:131)
                                                                     at android.support.design.widget.ViewOffsetBehavior.onLayoutChild(ViewOffsetBehavior.java:42)
                                                                     at android.support.design.widget.AppBarLayout$ScrollingViewBehavior.onLayoutChild(AppBarLayout.java:1391)
                                                                     at android.support.design.widget.CoordinatorLayout.onLayout(CoordinatorLayout.java:870)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.support.v4.widget.DrawerLayout.onLayout(DrawerLayout.java:1193)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                     at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                                                     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                                                     at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                     at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
09-02 10:47:22.899 21249-21249/com.aztechdev.squad E/AndroidRuntime:     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                                                     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                                                     at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                                                     at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                                                     at com.android.internal.policy.DecorView.onLayout(DecorView.java:726)
                                                                     at android.view.View.layout(View.java:17637)
                                                                     at android.view.ViewGroup.layout(ViewGroup.java:5575)
                                                                     at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2346)
                                                                     at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2068)
                                                                     at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1254)
                                                                     at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6337)
                                                                     at android.view.Choreographer$CallbackRecord.run(Choreographer.java:874)
                                                                     at android.view.Choreographer.doCallbacks(Choreographer.java:686)
                                                                     at android.view.Choreographer.doFrame(Choreographer.java:621)
                                                                     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:860)
                                                                     at android.os.Handler.handleCallback(Handler.java:751)
                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                     at android.os.Looper.loop(Looper.java:154)
                                                                     at android.app.ActivityThread.main(ActivityThread.java:6119)
                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
                                                                             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

这是我的 FirebaseRecyclerAdapter:

package com.aztechdev.squad.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.aztechdev.squad.helpers.common;
import com.aztechdev.squad.model.DirectChatModel;
import com.firebase.ui.database.FirebaseRecyclerAdapter;
import com.google.firebase.database.DatabaseReference;
import hani.momanii.supernova_emoji_library.Helper.EmojiconTextView;

import com.aztechdev.squad.R;


public class DirectFirebaseAdapter extends FirebaseRecyclerAdapter<DirectChatModel,DirectFirebaseAdapter.MyChatViewHolder> {

private static final int RIGHT_MSG = 0;
private static final int LEFT_MSG = 1;
private static final int RIGHT_MSG_IMG = 2;
private static final int LEFT_MSG_IMG = 3;

public static final String TAG = "DirectFirebaseAdapter";
private ClickListenerChatFirebase mClickListenerChatFirebase;

private String mUID;
private Context mContext;

public DirectFirebaseAdapter(Context context, DatabaseReference ref, String mUID, ClickListenerChatFirebase mClickListenerChatFirebase) {
    super(DirectChatModel.class, R.layout.item_message_left, DirectFirebaseAdapter.MyChatViewHolder.class, ref);
    this.mUID = mUID;
    this.mClickListenerChatFirebase = mClickListenerChatFirebase;
    this.mContext = context;

}


@Override
public MyChatViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    if (viewType == RIGHT_MSG){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_right,parent,false);
        return new MyChatViewHolder(view);
    }else if (viewType == LEFT_MSG){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_left,parent,false);
        return new MyChatViewHolder(view);
    }else if (viewType == RIGHT_MSG_IMG){
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_right_img,parent,false);
        return new MyChatViewHolder(view);
    } else if (viewType == 10) {
        return null;
    } else {
        view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_message_left_img,parent,false);
        return new MyChatViewHolder(view);
    }
}


@Override
public int getItemViewType(int position) {

    DirectChatModel model = getItem(position);

    Log.d(TAG, "getItemCount: " + getItemCount());
    Log.d(TAG, "From UID: " + model.getFrom().getId());
    Log.d(TAG, "To UID: " + model.getTo().getId());


    **if (!model.getFrom().getId().equals(mUID) && !model.getTo().getId().equals(mUID)) {
        Log.d(TAG, "getItemViewType: UID not found");
        return 10;
    }**


    if (model.getMapModel() != null){
        if (model.getFrom().getId().equals(mUID)){
            return RIGHT_MSG_IMG;
        }else{
            return LEFT_MSG_IMG;
        }
    }else if (model.getFile() != null){
        if (model.getFile().getType().equals("img") && model.getFrom().getId().equals(mUID)){
            return RIGHT_MSG_IMG;
        }else{
            return LEFT_MSG_IMG;
        }
    }else if (model.getFrom().getId().equals(mUID)){
        return RIGHT_MSG;
    }else {
        return LEFT_MSG;
    }
}

@Override
protected void populateViewHolder(MyChatViewHolder viewHolder, DirectChatModel model, int position) {

    if (model.getTo().getId().equals(mUID)) {
        viewHolder.setIvUser(model.getTo().getPhoto_profile());
        viewHolder.setTvTimestamp(model.getTimeStamp(), model.getTo().getName());

    } else {
        viewHolder.setIvUser(model.getFrom().getPhoto_profile());
        viewHolder.setTvTimestamp(model.getTimeStamp(), model.getFrom().getName());

    }

    viewHolder.setTxtMessage(model.getMessage());
    viewHolder.tvIsLocation(View.GONE);
    if (model.getFile() != null){
        viewHolder.tvIsLocation(View.GONE);
        viewHolder.setIvChatPhoto(model.getFile().getUrl_file());
    }else if(model.getMapModel() != null){
        viewHolder.setIvChatPhoto(common.local(model.getMapModel().getLatitude(),model.getMapModel().getLongitude()));
        viewHolder.tvIsLocation(View.VISIBLE);
    }
}


public class MyChatViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView tvTimestamp,tvLocation;
    EmojiconTextView txtMessage;
    ImageView ivUser,ivChatPhoto;

    public MyChatViewHolder(View itemView) {
        super(itemView);
        tvTimestamp = (TextView)itemView.findViewById(R.id.timestamp);
        txtMessage = (EmojiconTextView)itemView.findViewById(R.id.txtMessage);
        tvLocation = (TextView)itemView.findViewById(R.id.tvLocation);
        ivChatPhoto = (ImageView)itemView.findViewById(R.id.img_chat);
        ivUser = (ImageView)itemView.findViewById(R.id.ivUserChat);
    }

    @Override
    public void onClick(View view) {
        int position = getAdapterPosition();
        DirectChatModel model = getItem(position);
        if (model.getMapModel() != null){
            mClickListenerChatFirebase.clickImageMapChat(view,position,model.getMapModel().getLatitude(),model.getMapModel().getLongitude());
        }else{
           // mClickListenerChatFirebase.clickImageChat(view,position,model.getUserModel().getName(),model.getUserModel().getPhoto_profile(),model.getFile().getUrl_file());
        }
    }

    public void setTxtMessage(String message){
        if (txtMessage == null)return;
        txtMessage.setText(message);
    }

    public void setIvUser(String urlPhotoUser){
        if (ivUser == null)return;
        CircleTransform circleTransform = new CircleTransform();
        GlideApp.with(ivUser.getContext()).load(urlPhotoUser).centerCrop().transform(circleTransform).override(160,160).into(ivUser);

    }

    public void setTvTimestamp(String timestamp, String sender){
        if (tvTimestamp == null)return;
        tvTimestamp.setText(sender + " - " + convertTimestamp(timestamp));
    }

    public void setIvChatPhoto(String url){
        if (ivChatPhoto == null)return;

        GlideApp.with(ivChatPhoto.getContext()).load(url)
                .override(200, 200)
                .fitCenter()
                .into(ivChatPhoto);
        ivChatPhoto.setOnClickListener(this);
    }

    public void tvIsLocation(int visible){
        if (tvLocation == null)return;
        tvLocation.setVisibility(visible);
    }

}

private CharSequence convertTimestamp(String millis){
    return DateUtils.getRelativeTimeSpanString(Long.parseLong(millis), System.currentTimeMillis(), DateUtils.SECOND_IN_MILLIS);
}

}

【问题讨论】:

    标签: android firebase firebase-realtime-database android-recyclerview


    【解决方案1】:

    您有三个选择:

    1. 改变你的数据结构,这样你就不需要跳过行了。这是实现长期性能的最佳选择,但如果您只是想通过 POC,可能不是您的偏好。

    2. 不要使用 FirebaseUI。使用基本 Firebase 库自行运行查询。然后在客户端对结果进行后处理以删除/省略您不想要的行。您必须向 RecyclerView 返回一个实际的行数,而不是那些您想省略的行,并且拥有一个只包含您想要的行的干净数组是到达那里的最简单方法。

    3. 快速破解:不要返回null,而是返回一个0高度的视图!这是一个非常丑陋的 hack,但它确实有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 2021-10-12
      • 1970-01-01
      • 1970-01-01
      • 2010-11-05
      相关资源
      最近更新 更多