¿Cómo detectar si RecyclerView está vacío?

Tengo un RecyclerView obtener datos JSON externos analizados desde un servidor. Funciona bien, sin embargo la tarea asíncrona Volley en JSON a veces toma un tiempo y cuando lo hace el fragmento muestra una vista vacía en blanco.

¿Cómo puedo crear una prueba para comprobar si la vista está vacía y mostrar un msg si es? Traté de comprobar:

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

Pero esas pruebas no hacen nada o muestran el mensaje de error cada vez, incluso si el RecyclerView no está vacía.

Este es el código en el fragmento:

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

Y el método en el adaptador:

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

La forma en que ahora es el diálogo de progreso siempre se ejecuta sin importar si la vista está vacía o no.

UPDATE: Aquí está el código del adaptador:

 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:

He actualizado otra clase que es prácticamente la misma que la anterior con una interfaz de devolución de llamada sin embargo ahora el recyclerView muestra durante 1 segundo y luego se queda en blanco. El cuadro de diálogo ni siquiera se muestra. Aquí está el código:

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

Y esta es la clase 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; } } 

Puede comprobar si está vacía ejecutando:

 if (adapter.getItemCount() == 0) 

Si no está funcionando, significa que no ha reemplazado el getItemCount en su adaptador! Así que asegúrese de que está sobrepasado:

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

Actualización: Así que, basándose en su actualización, así es como puede proceder. En mi opinión, sólo necesita una devolución de llamada. Está comprobando si la lista está vacía en su onViewCreated. En su lugar, debe utilizar una devolución de llamada. Haz algo como eso:

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

En la clase que está utilizando para llenar su jsonList, asumo que un asynctask o una clase separada agregue esto:

 private OnJsonLoaded mListener; public void setOnJsonLoadedListener(OnJsonLoaded listener) { mListener = listener; } public interface OnJsonLoaded { void onJsonLoaded(ArrayList<HashMap<String, String>> list); } 

Ahora, en el asynctask que puebla ur jsonLise o cuando el parser json termine su trabajo, llame al oyente:

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

En su fragmento (el que tiene NovaAdapter novaAdapter = nuevo NovaAdapter (getActivity (), jsonList) y su recyclerview) agregue la implementación de la interfaz:

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

El código puede contener errores, lo escribí a mano sin usar IDE así que tal vez usted tiene que arreglar las cosas pequeñas, pero la lógica es bastante clara!

Actualización basada en su actualización 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! } } }); } 

Cómo se describe en https://developer.android.com/training/material/lists-cards.html

El método overriden getItemCount() es invocado por el gestor de diseño. Este es el fragmento:

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

Así que para detectar si el recyclerView está vacío, debe solicitarlo a su LayoutManager . Ejemplo:

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

Trato de getItemCount() de mi Adapter pero esto devuelve 0, no sé por qué es …

  • ¿Cuál es el punto de usar decoraciones de artículos en RecyclerView VS edición de los diseños inflados individuales?
  • Lista ampliable con RecyclerView?
  • ¿Cuál es el equivalente listview.setSelection en caso de Recycler View
  • ¿Cómo obtener la Scrollposition en Recyclerview / Layoutmanager?
  • ¿Cómo puedo crear un RecyclerView circular (sin fin)?
  • RecyclerView java.lang.IndexOutOfBoundsException: Inconsistencia detectada. Posición de elemento no válida cuando se reanuda desde fragmento añadido
  • GridLayoutManager setSpanCount no funciona en OnClickListener de un botón
  • RecyclerView GridLayoutManager: cómo detectar el recuento de span?
  • ¿Cómo centrar los elementos de RecyclerView?
  • Android - ¿Cómo cambiar la altura de Recyclerview dinámicamente?
  • Refrescar datos en RecyclerView y mantener su posición de desplazamiento
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.