When clicking on action bar item checkbox change it state

1.8k Views Asked by At

I've been implementing an app where I use a listview with three items (Image view, text view and checkbox) the listview works fine (except for when scrolling down it does not keep the state of the views) but my question is why when I touch an icon of the action bar it changes completely the states of the checkboxes?

This is the normal behaviour of my app:

enter image description here

When I click on a checkBox it change the state to checked

enter image description here

But when I press on my action button of my toolbar this is what happens:

enter image description here

If you do not click on any action an click elsewhere to hide the action menu the states of the checkboxes becomes the normal state

I do not exactly why this is happening but I think it has to be something about the lifecycle of the fragment

Can you please help me?

This is the code of this fragment:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        establecimientosList = new ArrayList<HashMap<String, String>>();
        rootView = inflater.inflate(R.layout.fragment_establecimientos,
                container, false);

        mDrawerToggle = new ActionBarDrawerToggle(getActivity(), null, 0, 0);

        return rootView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);
        // ListView lv = getListView();

        if (savedInstanceState == null) {
            new GetEstablecimientos().execute();
        }

        ListView lv = getListView();
        lv.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
                    long arg3) {
                // TODO Auto-generated method stub
                Fragment fragment = null;
                fragment = new MostrarEstablecimientoFragment();

                // mDrawerToggle.setDrawerIndicatorEnabled(false);
                Bundle bundle = new Bundle();
                bundle.putSerializable("HashMap",
                        establecimientosList.get(arg2));
                bundle.putInt(ID, arg2);
                fragment.setArguments(bundle);

                android.app.FragmentManager fragmentManager = getFragmentManager();
                fragmentManager.beginTransaction()
                        .replace(R.id.content_frame, fragment)
                        .addToBackStack(null).commit();
                ((ActionBarActivity) getActivity()).getSupportActionBar()
                        .setTitle(
                                establecimientosList.get(arg2).get(TAG_NOMBRE));

            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub;
        mDrawerToggle.setDrawerIndicatorEnabled(true);
        return super.onOptionsItemSelected(item);
    }

I have inside this fragment an Asystask for retrieving the ListView data from Internet

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            // Dismiss the progress dialog
            if (pDialog.isShowing())
                pDialog.dismiss();
            /**
             * Updating parsed JSON data into ListView
             * */
            if (!establecimientosList.isEmpty()) {
                LazyAdapter mAdapter = new LazyAdapter(getActivity(),
                        establecimientosList, "RobotoTTF/Roboto-Thin.ttf");
                setListAdapter(mAdapter);
            } else {
                TextView textoError = (TextView) rootView
                        .findViewById(R.id.textViewEstablecimientoError);
                textoError.setVisibility(View.VISIBLE);
                ListView lv = getListView();
                lv.setVisibility(View.GONE);
                Toast.makeText(getActivity(), "Error", Toast.LENGTH_LONG)
                        .show();
            }
        }

enter image description here

This is the code of the Adapter:

  public class LazyAdapter extends BaseAdapter {

    private Activity activity;
    private ArrayList<HashMap<String, String>> data;
    private static LayoutInflater inflater = null;
    public ImageLoader imageLoader;
    private Typeface tf;

    private final ArrayList<Establecimiento> listEstab;

    private SharedPreferences sharedP;

    public LazyAdapter(Activity a, ArrayList<HashMap<String, String>> d,
            String font, ArrayList<Establecimiento> posEstablecimiento) {
        activity = a;
        data = d;
        inflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        imageLoader = new ImageLoader(activity.getApplicationContext());
        tf = Typeface.createFromAsset(a.getAssets(), font);
        sharedP = a.getSharedPreferences(PREFENCIAS_FAVORITOS,
                Context.MODE_PRIVATE);
        listEstab = posEstablecimiento;
    }

    public int getCount() {
        return data.size();
    }

    public Object getItem(int position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        final int pos = position;
        if (convertView == null) // {
            vi = inflater.inflate(R.layout.list_item, null);

        TextView nombre = (TextView) vi
                .findViewById(R.id.nombreEstablecimientoList);
        TextView descripcion = (TextView) vi.findViewById(R.id.descripcionList);
        TextView localidad = (TextView) vi.findViewById(R.id.localidadList);
        // thumb image
        ImageView thumb_image = (ImageView) vi.findViewById(R.id.list_image);
        CheckBox checkFav = (CheckBox) vi.findViewById(R.id.imageList);

        HashMap<String, String> establecimiento = new HashMap<String, String>();
        establecimiento = data.get(position);

        // Setting all values in listview
        nombre.setText(establecimiento.get(TAG_NOMBRE));
        descripcion.setText(establecimiento.get(TAG_DESCRIPCION));
        localidad.setText(establecimiento.get(TAG_LOCALIDAD));
        imageLoader.DisplayImage(establecimiento.get(TAG_IMAGEN_TIPO),
                thumb_image);
        checkFav.setChecked(listEstab.get(position).getFavorito());
        checkFav.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                // Actualizo lo que vale en las variables de entorno
                sharedP.edit()
                        .putBoolean(
                                String.valueOf(listEstab.get(pos).getId()),
                                !sharedP.getBoolean(String.valueOf(listEstab
                                        .get(pos).getId()), false)).commit();

                listEstab.get(pos).setFavorito(
                        !listEstab.get(pos).getFavorito());
                Toast.makeText(activity,
                        String.valueOf(listEstab.get(pos).getFavorito()),
                        Toast.LENGTH_SHORT).show();
            }
        });
        checkFav.setFocusable(false);

        return vi;

    }
}

But actually I don't think that the problem has to be with the adapter at all, because when you click on a item in the listview it opens another fragment with a detail list (this fragment does only consist of textviews and a checkbox). This is a screenshot o the problem:

enter image description here

This is what happend when I click on the setting menu

enter image description here

Weird thing because if you click on the hamburger icon of the drawer, the checkbox has it normal state (without any change)

This is the fragment for the last screenshot:

public class MostrarEstablecimientoFragment extends Fragment {

    SharedPreferences editor;

    HashMap<String, String> establecimiento = new HashMap<String, String>();

    CheckBox favButton;

    public MostrarEstablecimientoFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);

        setHasOptionsMenu(true);
        // ((ActionBarActivity) getActivity()).getSupportActionBar()
        // .setDisplayHomeAsUpEnabled(true);
        editor = getActivity().getSharedPreferences(PREFENCIAS_FAVORITOS,
                Context.MODE_PRIVATE);
    }

    @SuppressWarnings("unchecked")
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {

        View rootView = inflater.inflate(
                R.layout.fragment_mostrar_establecimiento, container, false);

        getActivity().setTitle("Mostrar información");

        favButton = (CheckBox) rootView.findViewById(R.id.favorite_button);

        if (getArguments() != null) {

            establecimiento = (HashMap<String, String>) getArguments()
                    .getSerializable("HashMap");

            Boolean isFav = editor.getBoolean(establecimiento.get(TAG_ID),
                    false);

            if (isFav) {
                if (favButton.isChecked() == false)
                    favButton.setChecked(true);
            }

            TextView tvTitle = (TextView) rootView
                    .findViewById(R.id.nameEstablecimiento);
            tvTitle.setText(establecimiento.get(TAG_NOMBRE));
            TextView tvHorario = (TextView) rootView
                    .findViewById(R.id.textViewHorario);
            tvHorario.setText(establecimiento.get(TAG_HORARIO));
            TextView tvDescp = (TextView) rootView
                    .findViewById(R.id.textViewDescp);
            tvDescp.setText(establecimiento.get(TAG_DESCRIPCION));
            TextView tvDirec = (TextView) rootView
                    .findViewById(R.id.textViewDirec);
            tvDirec.setText(establecimiento.get(TAG_DIRECCION));
            TextView tvLocal = (TextView) rootView
                    .findViewById(R.id.textViewLocalidad);
            tvLocal.setText(establecimiento.get(TAG_LOCALIDAD));
            TextView tvProv = (TextView) rootView
                    .findViewById(R.id.textViewProv);
            tvProv.setText(establecimiento.get(TAG_PROVINCIA));
            TextView tvCodPostal = (TextView) rootView
                    .findViewById(R.id.textViewCodigo);
            tvCodPostal.setText(establecimiento.get(TAG_CODIGOPOSTAL));
            TextView tvEmail = (TextView) rootView
                    .findViewById(R.id.textViewWeb);
            tvEmail.setText(establecimiento.get(TAG_EMAIL));
            TextView tvTlf1 = (TextView) rootView
                    .findViewById(R.id.textViewTlf1);
            tvTlf1.setText(establecimiento.get(TAG_TLF1));
            TextView tvTlf2 = (TextView) rootView
                    .findViewById(R.id.textViewTlf2);
            tvTlf2.setText(establecimiento.get(TAG_TLF2));
        }

        favButton.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                // favButton.setActivated(true);

                editor.edit().putBoolean(establecimiento.get(TAG_ID),
                        !editor.getBoolean(establecimiento.get(TAG_ID), false)).commit();

            }
        });
        return rootView;

    }

    @Override
    public void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        editor.edit().commit();
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // TODO Auto-generated method stub

        switch (item.getItemId()) {
        case (R.id.action_back):
            getFragmentManager().popBackStackImmediate();
            break;

        default:
            getActivity().onBackPressed();
            break;
        }
        return super.onOptionsItemSelected(item);

    }
}

enter image description here


EDIT AdapterClass

I've been struggling and I have solved the first problem. The one that when the recycle views changes the rows it loses the state of the checkbox and causes that the checkboxes are constantly changing its state. I've made this by creating a new class of Establecimiento where I save all the data, then before calling the adapter I made an ArrayList saving the state along the other values. I've updated my Adapter Class to reflect this situation, now the checkboxes always maintain their state but when you click on the option menu and the option menu pop up while this is happening the checkboxes changes their states then when you click elsewhere it recover the normal state

2

There are 2 best solutions below

1
On

There is a problem here:

    if (sharedP.getBoolean(String.valueOf(position), false)) {
        checkFav.setChecked(true);
    }

You're setting checked to true, but never to false. That means that when views are recycled and then reused for a different row, they will show up as favorites even if they are not.

This should be something like:

    boolean isFav = sharedP.getBoolean(String.valueOf(position), false);
    checkFav.setChecked(isFav);
0
On

Well I think I finally know what was happening.. I was using a custom drawable for the star image (with two images, one for checked and one for not checked) this is my star drawable:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Enabled states -->

    <item android:state_checked="true" android:state_window_focused="false"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_not_important" />
    <item android:state_checked="false" android:state_window_focused="false"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_important_cb" />

    <item android:state_checked="true" android:state_pressed="true"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_important_cb" />
    <item android:state_checked="false" android:state_pressed="true"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_not_important" />

    <item android:state_checked="true" android:state_focused="true"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_important_cb" />
    <item android:state_checked="false" android:state_focused="true"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_not_important" />

    <item android:state_checked="false"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_not_important" />
    <item android:state_checked="true"
          android:state_enabled="true"
          android:drawable="@drawable/ic_action_important_cb" />


</selector>

I just had a hunch I've removed my custom image and instead use a @android/drawable="btn_star" instead (I don't like it because it is a pretty old design and breaks the entire look on my app) but with this resource the behaviour now is completely normal, so I think I've got something wrong in my custom drawable but can't find what it is