【问题标题】:How to detect if RecyclerView is empty?如何检测 RecyclerView 是否为空?
【发布时间】:2015-01-29 02:08:42
【问题描述】:

我有一个 RecyclerView 获取从服务器解析的外部 JSON 数据。它工作正常,但是 JSON 上的 Volley 异步任务有时需要一段时间,并且当它执行时,片段会显示一个空的空白视图。

如何创建一个测试来检查视图是否为空,如果是则显示消息?我试图检查:

if (recyclerView == null)
if (jsonList == null)
if (adapter.getItemCount() == 0)
if (bundle == null)

但是这些测试要么不做任何事情,要么每次都显示错误消息,即使 RecyclerView 不为空。

这是片段上的代码:

public void onViewCreated(View view, Bundle savedInstanceState) {

    LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    layoutManager.supportsPredictiveItemAnimations();
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setClickable(true);
    recyclerView.setHasFixedSize(true);
    recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
    NovaAdapter novaAdapter = new NovaAdapter(getActivity(),jsonList);
    if (novaAdapter.getItemCount() != 0) {
        recyclerView.setAdapter(novaAdapter);
    }else{
        pDialog = new ProgressDialog(getActivity());
        pDialog.setMessage("Retrieving data from Server");
        pDialog.show();            
    }
    super.onViewCreated(view, savedInstanceState);

以及Adapter上的方法:

@Override
public int getItemCount() {
    return (null != novaList ? novaList.size() : 0);
}

无论视图是否为空,现在的进度对话框总是运行。

更新:这是适配器代码:

public class NovaAdapter extends RecyclerView.Adapter<NovaListRowHolder> {

ArrayList<HashMap<String, String>> novaList = new ArrayList<HashMap<String, String>>();
public static final String STATUS = "status";
public static final String NAME = "name";
public static final String ID = "id";
private Context mContext;

public NovaAdapter(Context context, ArrayList<HashMap<String, String>> novaList) {
    this.novaList = novaList;
    this.mContext = context;
}

@Override
public NovaListRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.instances_list, null);
    NovaListRowHolder mh = new NovaListRowHolder(v);
    return mh;
}

@Override
public void onBindViewHolder(NovaListRowHolder novaListRowHolder, int i) {

    HashMap<String, String> e = novaList.get(i);
    novaListRowHolder.name.setText(e.get(NAME));
    novaListRowHolder.status.setText(e.get(STATUS));
    novaListRowHolder.setId(e.get(ID));


}


@Override
public int getItemCount() {
    return (null != novaList ? novaList.size() : 0);
}class NovaListRowHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
protected TextView name;
protected TextView status;
protected String id;

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}

public NovaListRowHolder(View view) {
    super(view);
    view.setOnClickListener(this);
    this.name = (TextView) view.findViewById(R.id.nameInstance);
    this.status = (TextView) view.findViewById(R.id.statusInstance);

}

public void onClick(View view){
    Dialog dialog = new Dialog(view.getContext());
    dialog.setContentView(R.layout.instances_listdetail);
    dialog.setTitle("Details " + name.getText() + " " + getPosition());
    dialog.show();
}

更新2:

我用回调接口更新了另一个类,它与上面的类几乎相同,但是现在 recyclerView 显示 1 秒然后变为空白。对话框甚至不显示。代码如下:

public class SubnetsFragment extends Fragment implements OnJSONLoaded{
    /**
     * The fragment argument representing the section number for this
     * fragment.
     */
    private static final String ARG_SECTION_NUMBER = "section_number";
    private OnFragmentInteractionListener mListener;
    public ArrayList<HashMap<String, String>> jsonList;
    public RecyclerView recyclerView;
    public ProgressDialog pDialog;
        /**
     * Returns a new instance of this fragment for the given section
     * number.
     */
    public static SubnetsFragment newInstance(int sectionNumber) {
        SubnetsFragment fragment = new SubnetsFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_SECTION_NUMBER, sectionNumber);
        fragment.setArguments(args);
        return fragment;
    }


    public SubnetsFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        Bundle extras = getArguments();
        Serializable parsedList = extras.getSerializable("SubnetsParsed");
        jsonList = (ArrayList<HashMap<String, String>>)parsedList;
        if (extras == null){
            AlertDialog.Builder alert = new AlertDialog.Builder(getActivity());
            alert.setTitle("Token Expired");
            alert.setMessage("Authentication Token expired! Please login again.")
                    .setNeutralButton("Connect", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            Intent intent = new Intent(getActivity(), Login.class);
                            startActivity(intent);
                            getActivity().finish();
                            getFragmentManager().beginTransaction().remove(SubnetsFragment.this).commit();
                        }
                    });
            AlertDialog alertDialog = alert.create();
            alertDialog.show();
        }
        View rootView = inflater.inflate(R.layout.fragment_subnets, container, false);
        recyclerView = (RecyclerView)rootView.findViewById(R.id.subnetsRV);
        return rootView;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        layoutManager.supportsPredictiveItemAnimations();
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setClickable(true);
        recyclerView.setHasFixedSize(true);
        recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));

        onJsonLoaded(jsonList);

    }

    @Override
    public void onJsonLoaded(ArrayList<HashMap<String, String>> list) {

        SubnetsParser.setOnJSONLoadedListener(new OnJSONLoaded() {
            @Override
            public void onJsonLoaded(ArrayList<HashMap<String, String>> list) {
                if (list.size() != 0){
                    SubnetsAdapter subnetsAdapter = new SubnetsAdapter(getActivity(),jsonList);
                    recyclerView.setAdapter(subnetsAdapter);
                }else {
                    pDialog = new ProgressDialog(getActivity());
                    pDialog.setMessage("Retrieving data from Server");
                    pDialog.show();
                }
            }
        });

    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        ((Stackerz) activity).onSectionAttached(
                getArguments().getInt(ARG_SECTION_NUMBER));
        //try {
        //    mListener = (OnFragmentInteractionListener) activity;
        //} catch (ClassCastException e) {
        //    throw new ClassCastException(activity.toString()
        //            + " must implement OnFragmentInteractionListener");
        //}
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }




    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     * <p>
     * See the Android Training lesson <a href=
     * "http://developer.android.com/training/basics/fragments/communicating.html"
     * >Communicating with Other Fragments</a> for more information.
     */
    public interface OnFragmentInteractionListener {
        // TODO: Update argument type and name
        public void onFragmentInteraction(Uri uri);
    }
}

这是 JSON Parser 类:

public class SubnetsParser extends Activity{
    public static final String NAME = "name";
    public static final String GW = "gw";
    public static final String CIDR = "cidr";
    public static final String ID = "id";

    public String authToken;
    public String neutronURL;

    public static SubnetsParser parser = null;

    public static OnJSONLoaded mListener;

    public static void setOnJSONLoadedListener(OnJSONLoaded listener) {
        mListener = listener;
    }

    public interface OnJSONLoaded {
        void onJsonLoaded(ArrayList<HashMap<String, String>> list);
    }

    public static SubnetsParser shared(){
        if (parser  == null){
            parser  = new SubnetsParser();
        }
        return parser ;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }





    public static ArrayList<HashMap<String, String>> parseJSON(String subnetsJSON){
        ArrayList<HashMap<String, String>> jsonList = new ArrayList<HashMap<String, String>>();
        try {
            Subnets subnets = new Subnets();
            JSONObject subnet = new JSONObject(subnetsJSON);
            JSONArray subnetobj = subnet.getJSONArray("subnets");
            for (int i = 0; i < subnetobj.length(); i++) {
                JSONObject objsrv = subnetobj.getJSONObject(i);
                subnets.setName(objsrv.getString("name"));
                subnets.setGw(objsrv.getString("gateway_ip"));
                subnets.setCidr(objsrv.getString("cidr"));
                subnets.setId(objsrv.getString("id"));
                HashMap<String, String> map = new HashMap<String, String>();
                map.put(NAME, subnets.getName());
                map.put(GW, subnets.getGw());
                map.put(CIDR, subnets.getCidr());
                map.put(ID, subnets.getId());
                jsonList.add(map);
            }
        } catch (JSONException e) {
            Log.d("ErrorInitJSON", e.toString());
            e.printStackTrace();
        }

        Collections.sort(jsonList, new Comparator<HashMap<String, String>>() {
            @Override
            public int compare(HashMap<String, String> lhs, HashMap<String, String> rhs) {
                return (lhs.get("name")).compareToIgnoreCase(rhs.get("name"));
            }
        });

        if (mListener != null) {
            mListener.onJsonLoaded(jsonList);
        }

        return jsonList;

    }


}

【问题讨论】:

  • 为什么不显示进度条??这是 asynctask 的一个非常常见的用途。
  • 如何在 Volley 中使用进度条?我的应用程序的配置方式 volley 在由片段调用的背景类中使用
  • RecyclerView 其实是ViewGroup,你试过“RecyclerView.getChildCount() == 0”吗?
  • 刚试过,但没有运气...当视图开始为空时,我得到一个对话框,但是在加载几秒钟后,对话框仍然存在。

标签: java android android-recyclerview


【解决方案1】:

你可以通过运行检查它是否为空:

if (adapter.getItemCount() == 0)

如果它不起作用,则意味着您没有覆盖适配器上的 getItemCount!所以确保它被覆盖:

@Override
public int getItemCount() {
    return mDataSet.size(); // Where mDataSet is the list of your items
}

更新: 因此,根据您的更新,这就是您可以继续进行的方式。在我看来,你只需要一个回调。您正在检查 onViewCreated 上的列表是否为空。相反,您应该使用回调。做这样的事情:

public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    layoutManager.supportsPredictiveItemAnimations();
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setClickable(true);
    recyclerView.setHasFixedSize(true);
    recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));

    pDialog = new ProgressDialog(getActivity());
    pDialog.setMessage("Retrieving data from Server");
    pDialog.show();   
}

在你用来填充你的 jsonList 的类中,我假设一个 asynctask 或一个单独的类添加这个:

private OnJsonLoaded mListener;

public void setOnJsonLoadedListener(OnJsonLoaded listener) {
    mListener = listener;
}

public interface OnJsonLoaded {
    void onJsonLoaded(ArrayList<HashMap<String, String>> list);
}

现在,在填充你的 jsonLise 的异步任务中,或者当 json 解析器完成他的工作时,调用监听器:

if (mListener != null) {
    mListener.onJsonLoaded(jsonList);
}

在您的片段中(带有 NovaAdapter novaAdapter = new NovaAdapter(getActivity(),jsonList); 和您的 recyclerview 的片段)添加接口实现:

classThatParseJson.setOnJsonLoadedListener(new OnJsonLoaded() {
        @Override
        public void onJsonLoaded(ArrayList<HashMap<String, String>> list) {
            if (list.size() != 0) {
                NovaAdapter novaAdapter = new NovaAdapter(getActivity(),jsonList); 
                recyclerView.setAdapter(novaAdapter);
            } else {
                // Show something like a dialog that the json list is 0 or do whatever you want... here the jsonlist have a count of 0 so it's empty!
            }  
        }
});

代码可能包含错误,我是手工编写的,没有使用 IDE,所以也许你必须修复一些小问题,但逻辑很清楚!

根据您的更新 2 更新:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_subnets, container, false);
    recyclerView = (RecyclerView)rootView.findViewById(R.id.subnetsRV);
    return rootView;
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
    layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
    layoutManager.supportsPredictiveItemAnimations();
    recyclerView.setLayoutManager(layoutManager);
    recyclerView.setItemAnimator(new DefaultItemAnimator());
    recyclerView.setClickable(true);
    recyclerView.setHasFixedSize(true);
    recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));

    // start json parser here instead of passing to fragment as a bundle
    SubnetsParser.parseJSON(yourparams);
}

@Override
public void onJsonLoaded(ArrayList<HashMap<String, String>> list) {

    SubnetsParser.setOnJSONLoadedListener(new OnJSONLoaded() {
        @Override
        public void onJsonLoaded(ArrayList<HashMap<String, String>> list) {
            if (list.size() != 0){
                SubnetsAdapter subnetsAdapter = new SubnetsAdapter(getActivity(),jsonList);
                recyclerView.setAdapter(subnetsAdapter);
            }else {
                //pDialog = new ProgressDialog(getActivity());
                //pDialog.setMessage("Retrieving data from Server");
                //pDialog.show();
                //Instead of a progressdialog, put here a dialog informing that the list is empty!
            }
        }
    });

}

【讨论】:

  • 我试过了,但我得到:java.lang.NullPointerException:尝试在 app.Instances.NovaAdapter 的空对象引用上调用虚拟方法 'int java.util.ArrayList.size()'。 getItemCount
  • 这是之前的方法:@Override public int getItemCount() { return (null != novaList ? novaList.size() : 0); }
  • 所以保持原样@Override public int getItemCount() { return (null != novaList ? novaList.size() : 0);向我展示你的完整源适配器,除了 viewholdercreated 部分
  • 我认为这是正确的方向,但我认为我错过了一些东西。请参阅有关问题的 UPDATE2,您介意看一下代码吗?
  • 我认为 Parser 类的监听器有问题。我刚刚进行了调试,在这部分“if (mListener != null) { Listener.onJsonLoaded(jsonList);}”之后,侦听器返回 null,它只是不加载适配器。
【解决方案2】:

https://developer.android.com/training/material/lists-cards.html中如何描述

布局管理器调用覆盖的方法getItemCount()。 这是sn-p:

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    return mDataset.length;
}

所以要检测recyclerView 是否为空,您必须向您的LayoutManager 请求它。示例:

if( mLayoutManager.getItemCount() == 0 ){
    //Do something
}

我尝试使用 getItemCount()Adapter 但这返回 0,我不知道为什么会这样......

【讨论】:

  • &gt; I try to getItemCount() of my Adapter but this returns 0, I don't know why it is... ...我也是。有人知道为什么吗?
  • 这是一个问题不是答案,有 3 个赞 ¿?
【解决方案3】:

如果 (adapter.getItemCount() == 0)

这样做对我有用...

【讨论】:

  • 像魅力一样工作!
【解决方案4】:

你可以使用接口回调来做到这一点:

  1. 创建界面
public interface OnAdapterCountListener {
    void onAdapterCountListener(int count);
}
  1. 在适配器中添加以下变量和方法
private OnAdapterCountListener onAdapterCountListener; 
    public void setOnAdapterCountListener(OnAdapterCountListener l) { 
        onAdapterCountListener = l; 
    }
  1. 在适配器的 onCreateViewHolder 中添加这一行
onAdapterCountListener.onAdapterCountListener(getItemCount());
  1. 最后,在你的activity中调用接口
listAdapter.setOnAdapterCountListener(new OnAdapterCountListener() {
    @Override 
    public void onAdapterCountListener(int count) { 
        if (count > 0) 
            adapterEmptyText.setVisibility(View.GONE); 
    }
});

【讨论】:

    【解决方案5】:

    创建一个类并继承 Recyclerview - 遵循以下代码

    public class RecyclerviewEmpty extends RecyclerView {
    
    private View emptyView;
    
    private final AdapterDataObserver observer = new AdapterDataObserver() {
        @Override
        public void onChanged() {
            checkIfEmpty();
        }
    
        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            checkIfEmpty();
        }
    
        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            checkIfEmpty();
        }
    };
    
    public RecyclerviewEmpty(@NonNull Context context) {
        super(context);
    }
    
    public RecyclerviewEmpty(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    
    public RecyclerviewEmpty(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    
    
    private void checkIfEmpty() {
        if (emptyView != null && getAdapter() != null) {
            final boolean emptyViewVisible = getAdapter().getItemCount() == 0;
            emptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE);
            setVisibility(emptyViewVisible ? GONE : VISIBLE);
        }
    }
    
    @Override
    public void setAdapter(@Nullable Adapter adapter) {
        final Adapter oldAdapter = getAdapter();
        if (oldAdapter != null) {
            oldAdapter.unregisterAdapterDataObserver(observer);
        }
        super.setAdapter(adapter);
        if (adapter != null) {
            adapter.registerAdapterDataObserver(observer);
        }
    
        checkIfEmpty();
    }
    
    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
        checkIfEmpty();
    }
    

    activity_xml - 在视图中定义类名

        <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bg_main"
        tools:context=".Ui.FavouriteActivity">
    
    
        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">
    
            <view
                android:id="@+id/rv_fav_activity"
                class="com.kumar.random.quotes.Views.RecyclerviewEmpty"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
    
            <TextView
                android:id="@+id/list_empty1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:gravity="center"
                android:text="Empty Favourite"
                android:textSize="14sp" />
        </FrameLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Activity.java

        private RecyclerviewEmpty rvFavourite;
    private void setUpRv() {
            rvFavourite.setEmptyView(emptyView);
            LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
            MainQuotesAdapter adapter = new MainQuotesAdapter(this, favouriteItem);
            rvFavourite.setLayoutManager(layoutManager);
            rvFavourite.setAdapter(adapter);
        }
    

    请注意_01:

     rvFavourite.setEmptyView(emptyView);
    

    请注意_02:

    public void setEmptyView(View emptyView) {
        this.emptyView = emptyView;
        checkIfEmpty();
    }
    

    请注意_03

     <view
            android:id="@+id/rv_fav_activity"
            class="com.kumar.random.quotes.Views.RecyclerviewEmpty"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    

    【讨论】:

    • 声明所有方法
    猜你喜欢
    • 2017-11-15
    • 2017-04-17
    • 1970-01-01
    • 2018-07-12
    • 2017-08-03
    • 2011-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多