Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android

Retrieve Object From Listener

Hello.

So the scenario here is that I have an activity that has an ArrayList that I want to display in a DialogFragment. I used an interface to deliver the data from the activity to the DialogFragment:

@Override
    public void addListClickListener(View v, ArrayList<ListObject> objects, ListsAdapter adapter) {
        mObjects = objects; //Delivering the data to the fragment
        mListsAdapter = adapter;
        mNewListFragment.setListener(mListener5);
        mNewListFragment.setListener1(mListener6);
        mTodoListsFragment.dismiss();
        mNewListFragment.show(getSupportFragmentManager(), NEW_LIST_FRAGMENT);
    }

Then in my fragment I display, or at least try to, the data from the interface to the ListAdapter:

   public interface AddListClickListener {
        void addListClickListener(View v, ArrayList<ListObject> objects, ListsAdapter adapter);
    }

   mAddListImage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mListener.addListClickListener(v, mObjects, mListsAdapter);
            }
        });

   protected void RecyclerViewSetup() {
        mListsAdapter = new ListsAdapter(mListener1, mListener2, getActivity(), mObjects);
        mListsAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                super.onChanged();
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount) {
                super.onItemRangeChanged(positionStart, itemCount);
            }

            @Override
            public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
                super.onItemRangeChanged(positionStart, itemCount, payload);
            }

            @Override
            public void onItemRangeInserted(int positionStart, int itemCount) {
                super.onItemRangeInserted(positionStart, itemCount);
            }

            @Override
            public void onItemRangeRemoved(int positionStart, int itemCount) {
                super.onItemRangeRemoved(positionStart, itemCount);
            }

            @Override
            public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
                super.onItemRangeMoved(fromPosition, toPosition, itemCount);
            }
        });

        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getActivity());
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setAdapter(mListsAdapter);
        checkAdapterIsEmpty();

However, I also need to define the mObjects array in the fragment without recreating itself every time the user opens the DialogFragment. How would I do this?

Thank you.

2 Answers

Ben Deitch
STAFF
Ben Deitch
Treehouse Teacher

Hey Diego! You could try making the ArrayList static in your Activity. Just make sure it gets populated before you launch the DialogFragment.

What if the data is user-entered in my case? There is a button in another fragment that adds items to the list:

mConfirmAddListView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String item;
                item = mListEditText.getText().toString();
                if (item.equals("") || item.startsWith(" ")) {
                    String message = "Please fill in the empty field.";
                    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
                } else {
                    mListener1.createListListener(v, item, mListObject);
                    mListener.dismissDialogListener(v);
                    dismiss();
                }
            }
        });

'createListListener' code in MainActivity:

@Override
    public void createListListener(View v, String string, ListObject object) {
        mListObject = object;
        mListObject.setListName(string);
        mObjects.add(mListObject);
        mListsAdapter.notifyDataSetChanged();
    }
Ben Deitch
Ben Deitch
Treehouse Teacher

I think you'd still be fine with a static ArrayList.

I get an error:

01-11 11:47:04.254 3294-3294/com.x.x E/AndroidRuntime: FATAL EXCEPTION: main
                                                                   Process: com.x.x, PID: 3294
                                                                   java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.util.ArrayList.add(java.lang.Object)' on a null object reference
                                                                       at com.x.x.MainActivity.createListListener(MainActivity.java:201)
                                                                       at com.x.x.NewListDialogFragment$1.onClick(NewListDialogFragment.java:63)
                                                                       at android.view.View.performClick(View.java:4764)
                                                                       at android.view.View$PerformClick.run(View.java:19844)
                                                                       at android.os.Handler.handleCallback(Handler.java:739)
                                                                       at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                       at android.os.Looper.loop(Looper.java:135)
                                                                       at android.app.ActivityThread.main(ActivityThread.java:5351)
                                                                       at java.lang.reflect.Method.invoke(Native Method)
                                                                       at java.lang.reflect.Method.invoke(Method.java:372)
                                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:908)
                                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:703)

MainActivity error:

mObjects.add(mListObject);

NewListDialogFragment error:

mListener1.createListListener(v, item, mListObject);

The mObjects ArrayList in my TodoListsFragment is still unassigned too.

Ben Deitch
Ben Deitch
Treehouse Teacher

Ah yep. You'll need to initialize the ArrayList when you declare it:

ArrayList mListObject = new ArrayList();

But if I initialized mObjects in my TodoListFragment, it would override the previous one every time I reopen the fragment (which is why I'm creating the list, that I want to display in the DialogFragment, in the MainActivity). I made my mObjects list in my MainActivity static and initialized the other mObjects list in my DialogFragment and that's whats happening.

Ben Deitch
Ben Deitch
Treehouse Teacher

Hmm, maybe I'm not understanding it correctly. Is the project on Github?

I'll put it on GitHub as soon as I polish a few things.

Ben Deitch
Ben Deitch
Treehouse Teacher

Have you thought about storing your list as a SharedPreference? That way you could access it from anywhere relatively easily.

Hmm...not entirely sure how to do that...at least with lists.

I think there are two ways you could do this:

  • (Option 1) One way is to send the ArrayList as an argument to your Fragment, and retrieve it in the Fragment. However, to do this you will have to make the object in your ArrayList parcelable. To make your object Parcelable, take a look at this helpful guide to do that http://guides.codepath.com/android/Using-Parcelable. Once your object is Parcelable all you need to do is send it to the Fragment as an argument. For example:
    In your Activity:
Bundle args = new Bundle();  
args.putParcelableArrayList("key", mObjects);   
mNewListFragment.setArguments(args);  
...  

In your Fragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...
        ArrayList<ListObject> mObjects = new ArrayList<>();
        Bundle args = getArguments();
        if(args != null) {
           mObjects = args.getParcelableArrayList("key");
        }
        ...
}  
  • (Option 2) I created a small Android utility class that provides a simple way to pass objects between Fragments and Activities. It works pretty much in the same way as you would use Intent Extras to pass a String between Activities. The link to it is (https://gist.github.com/kkuivi/161f254374a4007ae6014f67ae45789e). To use it, first copy the class into your project and then:
    In your Activity
ReferenceMap.getInstance().putObjectReference(NEW_FRAGMENT.class, "myKey", mObjects);  

In your fragment

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ...
        ArrayList<ListObject> mObjects = new ArrayList<>();
        ReferenceMap.ReferenceList refList = ReferenceMap.getInstance().getReferenceList(this);
        if(refList != null) {
           mObject = (ObjectType) refList.get("myKey");
        }
        ...
}  

@Override  
public void onStop(){
   ReferenceMap.getInstance().releaseRefList(this);
   super.onStop();
}  

Let me know if this helps