0

This question has been answered before, but the solutions doesn't seem to work for me. I would like to know what the best way is to save an ArrayList.

I generate an ArrayList with all the installed applications on the phone. This list is shown in a ListView where the user can (de)select apps. This is all working fine. What I would like is that the Arraylist gets saved when the user presses a save button or when the activity calls onPause().

When the user returns to the list the user will see the list the way he saved/left it.

Here is my code:

onCreate

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_app_list);

    loadApps();
    loadListView();
    addClickListener();
}

loadApps

private void loadApps(){
    manager = getPackageManager();
    apps = new ArrayList<AppDetail>();

    if(apps.size()==0) {
        Intent i = new Intent(Intent.ACTION_MAIN, null);
        i.addCategory(Intent.CATEGORY_LAUNCHER);
        List<ResolveInfo> availableActivities = manager.queryIntentActivities(i, 0);
        for (ResolveInfo ri : availableActivities) {
            AppDetail app = new AppDetail();
            app.label = ri.loadLabel(manager);
            app.name = ri.activityInfo.packageName;
            app.icon = ri.activityInfo.loadIcon(manager);
            app.allowed = false;
            apps.add(app);
        }
        Log.i("applist", apps.toString());
    }
}

AppDetail.class

public class AppDetail {
CharSequence label;
CharSequence name;
Drawable icon;
Boolean allowed;

loadListView

private void loadListView(){

    list = (ListView)findViewById(R.id.apps_list);

    adapter = new ArrayAdapter<AppDetail>(this, R.layout.list_item, apps) {
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView == null){
                convertView = getLayoutInflater().inflate(R.layout.list_item, null);
            }

            ImageView appIcon = (ImageView)convertView.findViewById(R.id.item_app_icon);
            appIcon.setImageDrawable(apps.get(position).icon);

            TextView appLabel = (TextView)convertView.findViewById(R.id.item_app_label);
            appLabel.setText(apps.get(position).label);

            TextView appName = (TextView)convertView.findViewById(R.id.item_app_name);
            appName.setText(apps.get(position).name);

            if(list.isItemChecked(position)){convertView.setBackgroundColor(getResources().getColor(R.color.green));}
            if(!list.isItemChecked(position)){convertView.setBackgroundColor(getResources().getColor(R.color.white));}
            return convertView;
        }
    };
    list.setAdapter(adapter);
    list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
}

addClickListener

private void addClickListener() {
    list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> av, View v, int pos,
                                long id) {
            checked = list.getCheckedItemPositions();
            ArrayList<AppDetail> allowedApps = new ArrayList<>();

            for (int i = 0; i < checked.size(); i++) {
                // Item position in adapter
                int position = checked.keyAt(i);
                // Add sport if it is checked i.e.) == TRUE!
                if (checked.valueAt(i)) {
                    allowedApps.add(adapter.getItem(position));
                }
            }
            adapter.notifyDataSetChanged();
            Log.i("", allowedApps.toString());
        }
    });
}

At this moment I'm creating two lists: List: list of all apps AllowedApps: list of checked (allowed) apps, to use in an other activity

Maveňツ
  • 1
  • 12
  • 50
  • 89
  • AFAIK, you need to find a way to save it to a file on internal storage and populate it from there. – Bhoot May 21 '15 at 11:41
  • 1
    You say that you've researched on the solutions and they don't work for you, please explain what exactly have you tried and why exactly it didn't suit your use case. – Egor May 21 '15 at 11:44
  • 1
    Serialize the list... – Ya Wang May 21 '15 at 11:45
  • Should the selections be persisted even after the app is closed/the phone is shut down? If so you need to save to a database or a file. The list could actually be cleared even without closing the app. Read up on the Android lifecycle http://developer.android.com/training/basics/activity-lifecycle/index.html – Simon May 21 '15 at 11:51

3 Answers3

1

I think you are looking for something like "Parcelable". It can save any ArrayList and retrieve back when you need it just like the Shared Preferences.

Please have a look here,

How to save custom ArrayList on Android screen rotate?

Community
  • 1
  • 1
Prokash Sarkar
  • 11,723
  • 1
  • 37
  • 50
1

ArrayList is serializable. Save it as a serializable object in file on storage

RehanZahoor
  • 322
  • 2
  • 12
1

If you need saving your list when activity is paused, you have several ways to do it. First you need define the private list field in your activity.

private ArrayList<AppDetail> allowedApps;

1) Make AppDetail serializable and use onSaveInstanceState

public class AppDetail implements Serializable {
    CharSequence label;
    CharSequence name;
    Drawable icon;
    Boolean allowed;
}

---------------- EDIT -----------------

I would change Drawable icon field for int icon.

In your loadApps() method change the setence app.icon = ri.activityInfo.getIconResource();

In yout loadListView method change the setence appIcon.setImageResource(apps.get(position).icon);

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putSerializable("allowedApps", allowedApps);
}

Retrieve the list in onCreate method

if (savedInstanceState != null) {
     allowedApps = (List<AppDetail>)savedInstanceState.getSerializable("allowedApps");
}else{
     allowedApps = new ArrayList<AppDetail>();
}

2) Use onRetainCustomNonConfigurationInstance

Return the list in onRetainCustomNonConfigurationInstance

@Override
public Object onRetainCustomNonConfigurationInstance() {
    return allowedApps;
}

Retrieve the list in onCreate method

Object allowedApps= getLastCustomNonConfigurationInstance();
if (allowedApps != null) {
    this.allowedApps = (List<AppDetail>) allowedApps;
}else{
    this.allowedApps = new ArrayList<AppDetail>();
}
juanhl
  • 1,170
  • 2
  • 11
  • 16
  • Thanks for your quick answer! I implemented the first method. When i rotate the screen it will call the onSaveInstanceState. When I log the != null in the onCreate it logs the list correctly. When I click the recents button (the active apps) the app crashes `Channel is unrecoverably broken and will be disposed!` – DevelopingBeaver May 21 '15 at 13:20
  • post the listener from the button. – juanhl May 21 '15 at 13:34
  • For now i use an onClick method. Where i define the onClick in the xml file! Or did you mean the listener of the recents button? – DevelopingBeaver May 21 '15 at 13:48
  • post the method onClick then – juanhl May 21 '15 at 13:49
  • `public void submitButton(View v) { Toast.makeText(getApplicationContext(), " List submitted ", Toast.LENGTH_SHORT).show(); }` – DevelopingBeaver May 21 '15 at 13:50
  • and app crash when you click the button? – juanhl May 21 '15 at 13:52
  • No, it crashes when i click the Recents button (on some phones holding the home button for a longer period). It also crashes when i change the orientation twice (first time it works fine, When turning back to portrait is crashes) – DevelopingBeaver May 21 '15 at 13:55
  • ok, maybe it's a memory issue. You are saving a lot of Drawable objects. Try a change in your AppDetail, use id int resource instead of Drawable object. (activityInfo.getIconResource()) – juanhl May 21 '15 at 14:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78437/discussion-between-developingbeaver-and-juanhl). – DevelopingBeaver May 21 '15 at 14:48