简体   繁体   中英

Android ViewModel LiveData update view on button click

I am following this tutorial to learn ViewModel and LiveData. In my case, instead of getting data from network, I am simply generating random string on button click and trying to update a textview. The problem is that the textview does not get updated when the data is changed by button click, but only gets updated when orientation is toggled.

Activity Class (extends LifecycleActivity)

public class PScreen extends BaseActivity {
  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.places_screen);

final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
viewModel.init();

viewModel.getUser().observe(this, new Observer<User>() {
  @Override public void onChanged(@Nullable User user) {
    ((TextView) findViewById(R.id.name)).setText(user.getName());
  }
});

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View v) {
    final MutableLiveData<User> data = new MutableLiveData<>();
    User user = new User();
    user.setName(String.valueOf(Math.random() * 1000));
    data.postValue(user);
    viewModel.setUser(data); // Why it does not call observe()
  }
});
  }
}

ViewModel Class

package timsina.prabin.tripoptimizer.model;

import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.ViewModel;

public class UserModel extends ViewModel {
  private LiveData<User> user;

  public void init() {
    if (this.getUser() != null) {
      return;
    }
    this.user = new LiveData<User>() {
      @Override protected void setValue(User value) {
        value.setName("Fresh New Name");
        super.setValue(value);
      }
    };
  }

  public LiveData<User> getUser() {
    return user;
  }

  public void setUser(LiveData<User> user) {
    this.user = user;
  }
}

You are creating a new LiveData instance each time! You are not supposed to do that. If you do that all previous observers will be ignored.

In this case you could replace your setUSer(LiveData<User>) method on your ViewModel to setUser(User u) (taking a User instead of a LiveData) and then do user.setValue(u) inside it.

Of course, will have to initialize the LiveData member in your ViewModel class, like this:

final private LiveData<User> user = new MutableLiveData<>();

It will work then because it will notify the existing observers.

I was somehow able to resolve this by using MutableLiveData instead of LiveData. Model class

private MutableLiveData<User> user2;
  public void init() {
    if (user2 == null) {
      user2 = new MutableLiveData<>();
    }
}

  public MutableLiveData<User> getUser2() {
    return user2;
  }

  public void setUser2(final User user) {
    user2.postValue(user);
  }

Activity

 viewModel.getUser2().observe(this, new Observer<User>() {
      @Override public void onChanged(@Nullable User user) {
        ((TextView) findViewById(R.id.name)).setText(user.getName());
      }
    });

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
      @Override public void onClick(View v) {
       User user = new User();
        viewModel.getUser().postValue(user);
        }
    });

You replace the reference to the object inside UserModel, try to swap the lines of code

data.postValue(user);
viewModel.setUser(data); // Why it does not call observe()

replace on

viewModel.setUser(data); // Why it does not call observe()
data.postValue(user);

Try to modify your code as @niqueco mentioned, set your updated method inside setUser() method and change your onclick() listener in the activity to send the new user data info only. Other works the LiveData will help u.

public class UserModel extends ViewModel {
  private LiveData<User> user;

  public void init() {
    if (this.getUser() != null) {
      return;
    }
    this.user = new LiveData<User>() {
      @Override protected void setValue(User value) {
        value.setName("Fresh New Name");
        super.setValue(value);
      }
    };
  }

  public LiveData<User> getUser() {
    return user;
  }

  public void setUser(LiveData<User> user) {
    this.user.setValue(user); //the live data will help u push data
  }
}

Activity Class

public class PScreen extends BaseActivity {
  @Override protected void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.places_screen);

final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
viewModel.init();

viewModel.getUser().observe(this, new Observer<User>() {
  @Override public void onChanged(@Nullable User user) {
    ((TextView) findViewById(R.id.name)).setText(user.getName());
  }
});

findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View v) {
    //final MutableLiveData<User> data = new MutableLiveData<>();
    User user = new User();
    user.setName(String.valueOf(Math.random() * 1000));
    //data.postValue(user);
    viewModel.setUser(user); // Why it does not call observe() 
  }
});
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM