1

I have written code that displays list of installed apps along with checkbox. However, when I close the app, checkbox value resets. I learned that by using Shared Preference I can save state of checkbox. However I am not able to implement it in my project. I am very new to this. So, I request to provide detailed solution. Also, I have one more question.In this code, state of checkbox is saved in array named checklist. Instead is it possible to create boolean variables that has name equal to App name ( which we get from PackageManager) and value will be status of checkbox. for instance boolean Browser or Boolean Camera. The code is posted below. Thanks in advance!!

MainActivity.java

public class MainActivity extends ListActivity {
    private PackageManager packageManager = null;
    private List<ApplicationInfo> applist = null;
    private ApplicationAdapter listadapter = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        packageManager = getPackageManager();

        new LoadApplications().execute();
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        ApplicationInfo app = applist.get(position);
        try {
            Intent intent = packageManager
                    .getLaunchIntentForPackage(app.packageName);

            if (null != intent) {
                startActivity(intent);
            }
        } catch (ActivityNotFoundException e) {
            Toast.makeText(MainActivity.this, e.getMessage(),
                    Toast.LENGTH_LONG).show();
        } catch (Exception e) {
            Toast.makeText(MainActivity.this, e.getMessage(),
                    Toast.LENGTH_LONG).show();
        }
    }

    private List<ApplicationInfo> checkForLaunchIntent(List<ApplicationInfo> list) {
        ArrayList<ApplicationInfo> applist = new ArrayList<ApplicationInfo>();
        for (ApplicationInfo info : list) {
            try {
                if (null != packageManager.getLaunchIntentForPackage(info.packageName)) {
                    applist.add(info);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return applist;
    }

    private class LoadApplications extends AsyncTask<Void, Void, Void> {
        private ProgressDialog progress = null;

        @Override
        protected Void doInBackground(Void... params) {
            applist = checkForLaunchIntent(packageManager.getInstalledApplications(PackageManager.GET_META_DATA));
            listadapter = new ApplicationAdapter(MainActivity.this,
                    R.layout.row, applist);

            return null;
        }

        @Override
        protected void onCancelled() {
            super.onCancelled();
        }

        @Override
        protected void onPostExecute(Void result) {
            setListAdapter(listadapter);
            progress.dismiss();
            super.onPostExecute(result);
        }

        @Override
        protected void onPreExecute() {
            progress = ProgressDialog.show(MainActivity.this, null,
                    "Loading application info...");
            super.onPreExecute();
        }

        @Override
        protected void onProgressUpdate(Void... values) {
            super.onProgressUpdate(values);
        }
    }
}

ApplicationAdapter.java

public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
    private List<ApplicationInfo> appsList = null;
    private Context context;
    private PackageManager packageManager;
    private ArrayList<Boolean> checkList = new ArrayList<Boolean>();

    public ApplicationAdapter(Context context, int textViewResourceId,
                              List<ApplicationInfo> appsList) {
        super(context, textViewResourceId, appsList);
        this.context = context;
        this.appsList = appsList;
        packageManager = context.getPackageManager();

        for (int i = 0; i < appsList.size(); i++) {
            checkList.add(false);
        }
    }

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

    @Override
    public ApplicationInfo getItem(int position) {
        return ((null != appsList) ? appsList.get(position) : null);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (null == view) {
            LayoutInflater layoutInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.row, null);
        }

        ApplicationInfo data = appsList.get(position);
        if (null != data) {
            TextView appName = (TextView) view.findViewById(R.id.app_name);
            TextView packageName = (TextView) view.findViewById(R.id.app_package);
            ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);

            CheckBox checkBox = (CheckBox) view.findViewById(R.id.cb_app);
            checkBox.setTag(Integer.valueOf(position)); // set the tag so we can identify the correct row in the listener
            checkBox.setChecked(checkList.get(position)); // set the status as we stored it
            checkBox.setOnCheckedChangeListener(mListener); // set the listener

            appName.setText(data.loadLabel(packageManager));
            packageName.setText(data.packageName);
            iconview.setImageDrawable(data.loadIcon(packageManager));
        }
        return view;
    }
    CompoundButton.OnCheckedChangeListener mListener = new CompoundButton.OnCheckedChangeListener() {

        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            checkList.set((Integer)buttonView.getTag(),isChecked); // get the tag so we know the row and store the status
        }
    };
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

    </ListView>

</LinearLayout>

row.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/app_icon"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:scaleType="centerCrop"
        android:padding="3dp"
        android:src="@drawable/download" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:orientation="vertical"
        android:paddingLeft="5dp" >

        <TextView
            android:id="@+id/app_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/app_package"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_vertical" />
    </LinearLayout>


    <CheckBox
        android:id="@+id/cb_app"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

EDIT: As per @Falco Winkler suggestion, I modified my custom adapter as below.

ApplicationAdapter.java

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;    

public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
    private List<ApplicationInfo> appsList = null;
    private Context context;
    private PackageManager packageManager;
    private SharedPreferences prefs;
    public ApplicationAdapter(Context context, int textViewResourceId,
                              List<ApplicationInfo> appsList) {
        super(context, textViewResourceId, appsList);
        this.context = context;
        this.appsList = appsList;
        packageManager = context.getPackageManager();
        prefs = context.getSharedPreferences("checkboxstate",Context.MODE_PRIVATE);
    }



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

    @Override
    public ApplicationInfo getItem(int position) {
        return ((null != appsList) ? appsList.get(position) : null);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (null == view) {
            LayoutInflater layoutInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.row, null);
        }

        ApplicationInfo data = appsList.get(position);
        if (null != data) {
            TextView appName = (TextView) view.findViewById(R.id.app_name);
            TextView packageName = (TextView) view.findViewById(R.id.app_package);
            ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);

            CheckBox checkBox = (CheckBox) view.findViewById(R.id.cb_app);
            checkBox.setTag(String.valueOf(appName)); // set the tag so we can identify the correct row in the listener
            checkBox.setChecked(prefs.getBoolean(checkBox.getTag().toString(), false)); // set the status as we stored it

            checkBox.setOnClickListener(onclicklistener);
            appName.setText(data.loadLabel(packageManager));
            packageName.setText(data.packageName);
            iconview.setImageDrawable(data.loadIcon(packageManager));
        }
        return view;
}

    CheckBox.OnClickListener onclicklistener = new View.OnClickListener() {

        @Override
        public void onClick(View v) {

            prefs.edit().putBoolean(v.getTag().toString(),((CheckBox)v).isChecked()).apply();

        }
    };
}

However, the value of checkboxes is still not saved and everything resets after I close the application. What am I missing ?

EDIT1: As per new suggestion, I have modified my Custom adapter. However, even though i see some checkboxes already checked, it is random. For instance, if i check 3rd checkbox and reopen App, 2nd checkbox will be checked instead of 3rd.. Also, some other checkboxes are selected randomly. I am posting modified code below.

package com.example.monika.savenotification;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class ApplicationAdapter extends ArrayAdapter<ApplicationInfo> {
    private List<ApplicationInfo> appsList = null;
    private Context context;
    private PackageManager packageManager;
    public ApplicationAdapter(Context context, int textViewResourceId,
                              List<ApplicationInfo> appsList) {
        super(context, textViewResourceId, appsList);
        this.context = context;
        this.appsList = appsList;
        packageManager = context.getPackageManager();


    }



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

    @Override
    public ApplicationInfo getItem(int position) {
        return ((null != appsList) ? appsList.get(position) : null);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        if (null == view) {
            LayoutInflater layoutInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = layoutInflater.inflate(R.layout.row, null);
        }

        final ApplicationInfo data = appsList.get(position);
        final SharedPreferences prefs = context.getSharedPreferences("checkboxstate", Context.MODE_PRIVATE);
        if (null != data) {
            TextView appName = (TextView) view.findViewById(R.id.app_name);
            TextView packageName = (TextView) view.findViewById(R.id.app_package);
            ImageView iconview = (ImageView) view.findViewById(R.id.app_icon);

            CheckBox checkBox = (CheckBox) view.findViewById(R.id.cb_app);
            checkBox.setTag(data); // set the tag so we can identify the correct row in the listener


            checkBox.setChecked(prefs.getBoolean(data.packageName, false)); // set the status as we stored it


            checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    prefs.edit().putBoolean(data.packageName, isChecked).apply();

                }
            });

            appName.setText(data.loadLabel(packageManager));
            packageName.setText(data.packageName);
            iconview.setImageDrawable(data.loadIcon(packageManager));
        }
        return view;
}


}

What modifications do I need to do further ? Thanks in advance..

Anonymous
  • 336
  • 3
  • 23
  • The online documentation for SharedPreferences is pretty straight forward. Why can't you implement it? Have you tried, and if so what problems were you having? – OneCricketeer Nov 21 '15 at 16:06

1 Answers1

2

With shared preferences, you can use a String as a key, and a boolean or any other primitive data type as value.

So in your onClickListener you can do this:

 SharedPreferences prefs = activity.getSharedPreferences(
                    "com.company.yourapp", Context.MODE_PRIVATE);

 prefs.edit().putBoolean(buttonView.getTag().toString, isChecked).apply();

And if you want to determine the state of a checkbox just do:

prefs.getBoolean(yourTag.toString(), false);

While false is the default value you get when this tag has not been saved before (e.g. the checkbox has not been selected)

Also i would recommend that you set the event listener of your check box like this:

  checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {
                ApplicationInfo info = appsList.get(position);

            }
        }
    });

In the get view method, so you can access your Data source (ApplicationInfo List) directly. Note that you then have to declare the position parameter as final.

Edit

Your problem now seems to be with this line:

checkBox.setTag(String.valueOf(appName));

While app name is the identifier of your TextView. The tag of your check box will thus get set to the string representation of your textView which is some debug information. You probably meant to:

checkBox.setTag(data);

I guess you think way to complicated. Just try this in your get view :

    final ApplicationInfo data = appsList.get(position);
    ...
    final SharedPreferences prefs = activity.getSharedPreferences(
            "com.company.yourapp", Context.MODE_PRIVATE);

    checkBox.setChecked(prefs.getBoolean(data.packageName, false));
    checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

            prefs.edit().putBoolean(data.packageName, isChecked).apply();
        }
    });
Falco Winkler
  • 1,082
  • 1
  • 18
  • 24
  • Hi. @Falco Winker, Thanks a ton for your reply. I modified code as per your suggestion. Still I face problem. Please view EDIT section – Anonymous Nov 22 '15 at 07:56
  • Okay see my edit. there is one obvious error that i pointed out. I also posted a (untested) code snipped that should work for you now. – Falco Winkler Nov 22 '15 at 09:37
  • now i see some checkboxes already checked. however, it is random. For instance, if i check 3rd checkbox, after reopening app, 2nd checkbox will be checked. Also, some other checkboxes are selected randomly. – Anonymous Nov 22 '15 at 11:45
  • well now you don't even use shared preferences anymore, but a local variable as a list of booleans. This makes no sense to me. try my code snippet, it should work for you. I am sorry but i cannot do all the programming work for you. – Falco Winkler Nov 22 '15 at 11:50
  • use shared freferences like everyone said, have your app identifier as the key, and its checked state as the value using the command putBoolean(key, value) – Falco Winkler Nov 22 '15 at 11:51
  • Hi. Am facing above error after modifying code as per your suggestion. Please see EDIT1 section in question to see my updated code. Thanks a ton for your help. – Anonymous Nov 22 '15 at 13:00
  • in getview, i removed if (null == view), line. Everything is working perfectly fine now. Thank you so much.. – Anonymous Nov 22 '15 at 15:52
  • Good to know, Glad it helped! – Falco Winkler Nov 22 '15 at 17:15