Search code examples
javaandroidandroid-fragmentscallbackandroid-viewmodel

returning an object from an android ViewModel to the fragment from a callback function


I am using ViewModel in android to obtain an object and then pass it to a fragment to update UI components. I am trying to obtain the value of the object asynchronously and then pass the object to the fragment from the callback function. I already have a non-null value of the object in the callback and in the asynchronous task. I just am having trouble sending the object to the fragment by calling the function in the fragment java code. Here's the code snippet

Code snippet of the ViewModel

EventViewModel.java

class EventViewModel extends AndroidViewModel {

  private OnEventListener mListener;
  Obj obj;

  //setting the listener
  public void registerOnEventListener(OnEventListener mListener){
    this.mListener = mListener;
  }

  public void getObj(){

     new Thread(new Runnable() {
        @Override
        public void run() {
          //code to obtain non-null value of object
          //& obtains non-null value here
          obj = some-non-null-value

          if(mListener != null){
                //invoke the callback
                mListener.onEvent();
          }
        }
      });
  }

   interface OnEventListener(){
     Obj onEvent();
   }

   class A implements  OnEventListener {

     @Override
     public Obj onEvent() {

       System.out.println(obj.property1); //obj is non-null here

       //....
       return obj;
   }

 }
}

Code snippet of the fragment to which I want to send the object

EventFragment.java

public class EventFragment extends Fragment {

 private EventViewModel vm;

 @Override
 public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    vm = ViewModelProviders.of(this).get(EventViewModel.class);

    EventViewModel.OnEventListener mListener = vm. new A();
    vm.registerOnEventListener(mListener);
    vm.getObj();
    Obj o = mListener.getEvent()  //shows error as 'Incompatible Types'
                                  //so o is also null   
   }
}

Now I know that I cannot return obj directly in the getObj() method, it gets returned before obj is given a non-null value, i.e. before the asynchronous task is over. On trying the above method, object o in the EventFragment remains null always. So, please tell a way to send the object to the fragment EventFragment.java. Please point if I need to post any more code. Thanks in advance.


Solution

  • Use LiveData:

    class EventViewModel extends AndroidViewModel {
      private MutableLiveData<Obj> liveObjects = new MutableLiveData<>();
    
      LiveData<Obj> getObjects() {
        return liveObjects;
      }
    
      public void loadObject(){
         new Thread(new Runnable() {
            @Override
            public void run() {
              Obj object = // TODO get the value
    
              liveObjects.postValue(object);
            }
          }).start();
      }
    }
    
    public class EventFragment extends Fragment {
    
     private EventViewModel vm;
    
     @Override
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    
        vm = ViewModelProviders.of(this).get(EventViewModel.class);
    
        vm.getObjects().observe(this, new Observer<Obj>() {
            @Override
            public void onChanged(@Nullable final Obj newValue) {
                // TODO something useful
            }
        });
    }
    

    Then, when appropriate, call loadObject() on the EventViewModel to trigger the background work and delivery of the new object.