Android effectively communicating between Fragments and Activities to avoid null pointer exception errors



Recently we uploaded a new project named Facebook Scheduler which allows the user to schedule wall post messages to his/her own timeline or to his/her friends’ and groups timeline.Here we relied heavily on android compatibility library,Fragment,FragmentAdapter,FragementActivity.

We used android compatibility library ,looking upon the examples provided and we didn’t go deep into it. And all the problem started right from there. After lots of null pointer exception and force closes ,we finally figured out how to communicate between Activity(Fragment Activity) and Fragment. So before diving into solution ,I would like you to explain in brief simple life cycle of Fragment

fragment view


A Fragment is always dependent on FragmentActivity and it always rests or to say lives on FragmentActivity . So life cycle of Fragment depends upon the life cycle of FragmentActivity . Let’s now explain those portion of fragments life cycle that is important in this context

onAttach():
This signifies that the Activity has attached fragment on it and it doesn’t mean that all the views of Activity are created not it means that Activity is fully functional. This is just a point where you can reference the activity

onCreate():
Just a point which shows that Fragment is in the process of creation and in this method just try to access those values that you have saved on onSavedInstanceState(Bundle outState)

onCreateView():
Here we inflate the layout or simply create the view and further if you have to do anything that takes reference to Activity don’t do it like creating dialogs,accessing views of Activity etc because,this place doesn’t ensure that hosting Activity is fully functional

onActivityCreated():
This place signifies that our hosting Activity views are created and hosting Activity is functional and this is the right place to do all your Activity related task.

onResume():
This is the place where I prefer to do all the actions of the fragment



Now moving away from theory lets create a means of communication between Fragment and Activity. Communication should be done with interfaces and interface initialization should be done on Fragment.Lets consider a scenario
1: Fragment has a button named activityButton and Activity has button named fragmentButton on their respective layout

2: On click of activityButton Fragment sends data to Activity and on click of fragmentButton Activity sends data to fragment

3: Further Fragment has ListView,ProgressDialog,Adapters,just to show where to initialize those on fragment

Lets’ create two interfaces named FragmentCommunicator which is used to pass data from Activity to Fragment and ActivityCommunicator which is used to pass data from Fragment to Activity

public interface FragmentCommunicator{
   public void passDataToFragment(String someValue);
}

public interface ActivityCommunicator{
    public void passDataToActivity(String someValue);
}



Now let’s define our Fragment named CustomFragment and as per Android documentation on Fragment it is advisable to add an empty constructor to any subclasses of Fragment

public class CustomFragment extends Fragments implements FragmentCommunicator{
      public Context context;
      private ListView listView;
      private TextView;
      private CustomAdapter customAdapter;
      private ProgressDialog dialog;
      private Button activityButton;
      //interface via which we communicate to hosting Activity
      private ActivityCommunicator activityCommunicator;
      private String activityAssignedValue ="";
      private static final String STRING_VALUE ="stringValue";
      //as per Android Fragment documentation an empty constructor
      public CustomFragment(){    
      }
      public static CustomFragment newInstance(){
        return new CustomFragment();
      }
      //since Fragment is Activity dependent you need Activity context in various cases
      @Override
      public void onAttach(Activity activity){
        super.onAttach(activity);
        context = getActivity();
        activityCommunicator =(ActivityCommunicator)context;
      }
      //now on your entire fragment use context rather than getActivity()
      @Override
      public void onCreate(Bundle savedInstanceState){
       super.onCreate(savedInstanceState);
       if(savedInstanceState != null)
            activityAssignedValue = savedInstanceState.getString(STRING_VALUE);
      }
      @Override
      public void onSaveInstanceState(Bundle outState){
         super.onSaveInstanceState(outState);
         outState.putString(STRING_VALUE,activityAssignedValue);
      }
     //create your fragment view via layout or other views
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
            View fragmentView = inflater.inflate(R.layout.fb_friends_list_view, container, false);
             listView = (ListView)fragmentView.findViewById(R.id.listView);
             activityButton =(Button)fragmentView.findViewById(R.id.activityButton);
             textView =(TextView)fragmentView.findViewById(R.id.textView);
             //don't populate listview,create progress dialog or any other activity related task here
             setRetainInstance(true);
             return fragmentView;
    }
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
	 super.onActivityCreated(savedInstanceState);
	 init();
    }
    public void init() {
     dialog = new ProgressDialog(context);
     dialog.setCancelable(true);
     customAdapter = new CustomAdapter(context,
				R.layout.fb_friend_list_item, new ArrayList());
     listView.setAdapter(customAdapter);
     //communicating to activity via ActivityCommunicator interface
     activityButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View arg0) {
				activityCommunicator.passDataToActivity("Hi from Custom Fragment");
			}
		});
   }
   @Override
   public void onResume() {
    super.onResume();
    textView.setText(activityAssignedValue); 
  }
  //FragmentCommunicator interface implementation
  @Override
  public void passDataToFragment(String someValue){
   activityAssignedValue = someValue;
   textView.setText(activityAssignedValue); 
  }
}

Lets define our FragmentStatePagerAdapter named CustomFragmentAdapter and according to Android documentation better to use FragmentStatePagerAdapter than FragmentPagerAdapter to save the state of the fragments

public class CustomFragmentAdapter extends FragmentStatePagerAdapter {
   private ArrayList<Fragment> list;
   	public CustomFragmentAdapter(FragmentManager fm, ArrayList<Fragment> list) {
		super(fm);
		this.list = list; 
	}
	
	@Override
	public Fragment getItem(int position) {
		return list.get(position);
	}

	@Override
	public int getCount() {
		return list.size();
	}
}

Now lets finally create our Activity class named MainActivity

 public class MainActivity extends FragmentActivity implements ActivityCommunicator{
    	//interface through which communication is made to fragment
        public FragmentCommunicator fragmentCommunicator;
        private Button fragmentButton;
        private ViewPager viewPager;
        private CustomAdapter customAdapter;
        private TextView textView;
        public static ArrayList<Fragment> listFragments;
        
        @Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
                setContentView(R.layout.title_viewpager);
                fragmentButton = (Button)findViewById(R.id.fragmentButton);
                viewPager =(ViewPager)findViewById(R.id.viewPager);
                textView =(TextView)findViewById(R.id.textView);
                listFragments = new ArrayList<Fragment>();
                CustomFragment customFragment = CustomFragment.newInstance();
                WallPostFragment wallPostFragment = WallPostFragment.newInstance();
                listFragments.add(customFragment);
                listFragments.add(wallPostFragment);
                customAdapter = new CustomAdapter(getSupportFragmentManager(),listFragments);
                viewPager.setAdapter(customAdapter);
                setUIListeners();
              
        }

        private void setUIListeners(){
          		fragmentButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
                                if(fragmentCommunicator != null)
				fragmentCommunicator.passDataToFragment("Hi from FragmentActivity");
			}
		});

       }
       @Override
       public void passDataToActivity(String someValue){
          textView.setText(someValue); 
      }
}

If you have noticed carefully ,I haven’t initialized fragmentCommunicator anywhere on the Activity, one should initialize it on CustomFragments onAttach() method

   @Override 
   public void onAttach(Activity activity){
    super.onAttach(activity);
    context = getActivity();
    activityCommunicator =(ActivityCommunicator)context;
    ((MainActivity)context).fragmentCommunicator = this;
  }

This is just a mechanism on how to communicate between fragment and activity and it has one flaw.Since we initialized the fragmentCommunicator on CustomFragment and if we need to pass some data on onCreate() method of Activity like

  fragmentCommunicator.passDataToFragment("Hello I am created");

Then it won’t be always certain that Fragment is created and its possible fragmentCommunicator may be null and result in app force close .If cases are like those,don’t pass values directly to Fragment but instead create a mechanism on Fragment to retrieve values of Activity.Let’s say our Fragment needs to look some value of Activity and then only do its work then

  // on Activity
   public int someIntValue =1;
 
  //on Fragment do this onResume() or on  onActivityCreated() only
  @Override
  public void onResume(){
     super.onResume();
     int activityValue =((MainActivity)context).someIntValue;
     if(activityValue == 0){
        //show one view
     }else{
       // show other view
    } 
      
}

This is just a rough implementation,but you can devise a better way to implement this solution.Hope, you didn’t sleep halfway reading this.The reason ,I made this tutorial,is I couldn’t find a better explanation on the any site,on how to properly communicate between Activity and Fragment without lots of null pointer exception. And if you find any other better implementation than me ,do comment or forward me links. Till then, keep on coding 😉

Advertisements

12 thoughts on “Android effectively communicating between Fragments and Activities to avoid null pointer exception errors

  1. Sir can you plz help me in getting a source code for Moving from a Fragment in FirstActivity to another Fragment of SecondActivity on Button click.
    I have used swipe within the activity for fragments.

    • I couldn’t properly understand your scenario. So,if you have any code snippets I can look upon,then I will able to direct you

    • purple.setOnClickListener(new OnClickListener() {
      @Override
      public void onClick(View v) {
      Fragment fragment = new tasks();
      FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
      FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
      fragmentTransaction.replace(R.id.content_frame, fragment);
      fragmentTransaction.addToBackStack(null);
      fragmentTransaction.commit();
      }
      });
      you write the above code…there we are replacing R.id.content_frame with our fragment. hope this helps you

  2. Guys thanks a lot for this! Not elsewhere is even mentioned; however, how would it be the initialization if instead on an activity there’s a fragment. That is, to send a message from a Fragment to a DialogFragment.

  3. Man you are so right about onAttach(). Thing is you can’t be sure 100% at any life cycle stage if anything is unready. I’ve been busting my ass for past few days trying to get variable like that. And doing it in onResume() or onActivityCreated() definately will do this. But man Android is a mess especially with Fragments.

  4. I´m facing same problem. I´m trying to implement this code. but It is not complete. Please, could you post the complete code?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s