Как определить, является ли RecyclerView пустым?

У меня есть RecyclerView, получающий внешние данные JSON, анализируемые с сервера. Он отлично работает, но задача Async Volley на JSON иногда занимает некоторое время, и когда он делает фрагмент, отображается пустой пустой вид.

Как создать тест, чтобы проверить, является ли представление пустым и отображает сообщение msg, если оно есть? Я попытался проверить:

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

и метод адаптера:

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

Теперь как всегда диалог выполнения всегда запускается независимо от того, пуст или нет.

UPDATE: здесь код адаптера:

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

UPDATE2:

Я обновил другой класс, который почти такой же, как и выше, с интерфейсом обратного вызова, однако теперь 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;

    }


}

Ответ 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, я предполагаю, что асинтекс или отдельный класс добавляют это:

private OnJsonLoaded mListener;

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

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

теперь, в asynctask, которые заполняют ur jsonLise или когда json-парсер завершает свою работу, вызовите слушателя:

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

В вашем фрагменте (тот, который с NovaAdapter novaAdapter = новый 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 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!
            }
        }
    });

}

Ответ 2

Как описано в https://developer.android.com/training/material/lists-cards.html

Метод переопределения getItemCount() вызывается менеджером компоновки. Это фрагмент:

// 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, я не знаю, почему это...

Ответ 3

if (adapter.getItemCount() == 0)

делать это работало на меня...