获取 LiveData 的初始值总是返回 Null

当应用程序启动时,我正在尝试从本地房间数据库加载loggedInUser 。如果之前保存的用户保存的身份验证令牌仍然有效,我想跳过提示用户登录!


因此,从DAO中,我想返回一个包含先前登录的用户的LiveData对象,然后观察它以进行后续更改。我面临的挑战是,如果我将结果包装在LiveData中,获取当前登录用户的方法总是返回 null,但如果返回为POJO ,它将返回预期的用户。


如何强制LiveData同步运行以初始化值,然后收听后续更改?我真的想结合这两种行为,因为身份验证可能会因后台同步任务或用户注销而失效(这些操作将替换或更新保存的令牌,我希望在实时数据)。


这是我到目前为止所尝试的:


AuthorizationDAO.java


public interface AuthorizationDAO {


    @Query("SELECT * FROM Authorization LIMIT 1") //Assume only one Authentication token will exist at any given time

    LiveData<Authorization> getLoggedInUser(); //I want to keep this behaviour


    @Insert(onConflict = REPLACE)

    long insertAuth(Authorization authorization);


    @Update

    void logoutCurrentUser(Authorization authorization);



}

AuthorizationRepository.java


public class AuthorizationRepository {

    private AuthorizationDAO mAuthorizationDAO;


    private MutableLiveData<Authorization> mAuthorization = new MutableLiveData<>();


    public AuthorizationRepository(Application application){


        AppDatabase db = AppDatabase.getDatabase(application);


        this.mAuthorizationDAO = db.mAuthorizationDAO();

    }


    public LiveData<Authorization> getLoggedInUser(){

               mAuthorization.postValue(mAuthorizationDAO.getLoggedInUser().getValue()); //this is always null at startup

        return this.mAuthorization;

    }

AuthorizationViewModel.java


public class AuthorizationViewModel extends AndroidViewModel {


    private AuthorizationRepository mAuthorizationRepository;


    private LiveData<Resource<Authorization>> mAuthorization;

    private LiveData<Authorization> loggedInUserAuth;


    public AuthorizationViewModel(@NonNull Application application) {

        super(application);

        this.mAuthorizationRepository = new AuthorizationRepository(application);

        });

如您所见,我正在调用mAuthorizationViewModel.init()以便我可以从本地数据库加载或初始化loggedInUserAuth,然后在下一行使用mAuthorizationViewModel.getLoggedInUserAuth().observe()观察相同的LiveData实例!但是为loggedInUserAuth返回的值始终为 null!


请帮忙,谢谢!


互换的青春
浏览 290回答 3
3回答

手掌心

我终于在@Krishna 的大力帮助下解决了这个问题,以下是要点:DAO 方法应该返回LiveData在Repository 类中,创建一个LiveData 私有成员变量而不是MutableLiveData(这是因为我们将通过更新/插入来改变数据库记录)。成员变量将保存对DAO 方法返回的LiveData对象的引用在Repository 的构造函数中,将LiveData对象初始化为DAO 方法返回的结果。这样,每次activity启动时,都会加载当前保存的记录在Repository 类中,创建一个getter,它将LiveData对象公开给ViewModel在ViewModel 类中,创建一个将LiveData对象公开给View Controller(活动或片段)的方法在Activity 或 Fragment中,只需侦听或订阅ViewModel提供的Accessor Method公开的LiveData上的更改DAO还可以公开更新LiveData的方法,允许Repository通过ViewModel启用Activity 或 Fragment向LiveData发送更新,同时保持所有侦听器的响应!这是此场景的工作代码:AuthorizationDAO.javapublic interface AuthorizationDAO {&nbsp; &nbsp; @Query("SELECT * FROM Authorization LIMIT 1") //Assume only one Authentication token will exist at any given time&nbsp; &nbsp; LiveData<Authorization> getLoggedInUser(); //I want to keep this behaviour&nbsp; &nbsp; @Insert(onConflict = REPLACE)&nbsp; &nbsp; long insertAuth(Authorization authorization);&nbsp; &nbsp; @Update&nbsp; &nbsp; void logoutCurrentUser(Authorization authorization); //this will be used to toggle login status by Activity or Fragment}AuthorizationRepository.javapublic class AuthorizationRepository {&nbsp; &nbsp; private AuthorizationDAO mAuthorizationDAO;&nbsp; &nbsp; private AuthorizationWebAPI mAuthorizationWebAPI;&nbsp; &nbsp; private LiveData<Authorization> mAuthorization; //reference to returned LiveData&nbsp; &nbsp; public AuthorizationRepository(Application application){&nbsp; &nbsp; &nbsp; &nbsp; AppDatabase db = AppDatabase.getDatabase(application);&nbsp; &nbsp; &nbsp; &nbsp; this.mAuthorizationDAO = db.mAuthorizationDAO();&nbsp; &nbsp; &nbsp; &nbsp; this.mAuthorization = mAuthorizationDAO.getLoggedInUser(); //initialize LiveData&nbsp; &nbsp; }&nbsp; &nbsp; public LiveData<Authorization> getAuthorizationResult() { //getter exposing LiveData&nbsp; &nbsp; &nbsp; &nbsp; return mAuthorization;&nbsp; &nbsp; }&nbsp; &nbsp; public void logoutCurrentUser(){ //toggle login status&nbsp; &nbsp; &nbsp; &nbsp; if (this.mAuthorization != null){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AppExecutors.getInstance().getDiskIO().execute(()->{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Authorization mAuthorizationObj = this.mAuthorization.getValue();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationObj.setLoggedIn(false);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationDAO.logoutCurrentUser(mAuthorizationObj); //update LiveData and changes will be broadcast to all listeners&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}AuthorizationViewModel.javapublic class AuthorizationViewModel extends AndroidViewModel {&nbsp; &nbsp; private AuthorizationRepository mAuthorizationRepository;&nbsp; &nbsp; public AuthorizationViewModel(@NonNull Application application) {&nbsp; &nbsp; &nbsp; &nbsp; super(application);&nbsp; &nbsp; &nbsp; &nbsp; this.mAuthorizationRepository = new AuthorizationRepository(application);&nbsp; &nbsp; }&nbsp; &nbsp; public LiveData<Authorization> getLoggedInUserAuth() { //exposes LiveData to the Activity or Fragment&nbsp; &nbsp; &nbsp; &nbsp; return mAuthorizationRepository.getAuthorizationResult();&nbsp; &nbsp; }&nbsp; &nbsp; public void logoutCurrentUser(){ //allows activity or fragment to toggle login status&nbsp; &nbsp; &nbsp; &nbsp; this.mAuthorizationRepository.logoutCurrentUser();&nbsp; &nbsp; }}AppActivity.javapublic class AppActivity extends AppCompatActivity {&nbsp; &nbsp; public AuthorizationViewModel mAuthorizationViewModel;&nbsp; &nbsp; public&nbsp; @Nullable Authorization mAuthorization;&nbsp; &nbsp; private NavController mNavController;&nbsp; &nbsp; private NavHostFragment mNavHostFragment;&nbsp; &nbsp; private BottomNavigationView mBottomNavigationView;&nbsp; &nbsp; private boolean mIsLoggedIn;&nbsp; &nbsp; private ActivityAppBinding mBinding;&nbsp; &nbsp; private boolean mIsTokenExpired;&nbsp; &nbsp; @Override&nbsp; &nbsp; protected void onCreate(Bundle savedInstanceState) {&nbsp; &nbsp; &nbsp; &nbsp; super.onCreate(savedInstanceState);&nbsp; &nbsp; &nbsp; &nbsp; mBinding = DataBindingUtil.setContentView(this, R.layout.activity_app);&nbsp; &nbsp; &nbsp; &nbsp; mNavHostFragment = (NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.app_nav_host_fragment);&nbsp; &nbsp; &nbsp; &nbsp; mNavController = mNavHostFragment.getNavController();&nbsp; &nbsp; &nbsp; &nbsp; mBottomNavigationView = findViewById(R.id.nav_bottom_nav_view);&nbsp; &nbsp; &nbsp; &nbsp; NavigationUI.setupWithNavController(mBottomNavigationView, mNavController);&nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationViewModel = ViewModelProviders.of(this).get(AuthorizationViewModel.class);&nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationViewModel.getLoggedInUserAuth().observe(this, new Observer<Authorization>() { //Observe changes to Authorization LiveData exposed by getLoggedInUserAuth()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void onChanged(@Nullable Authorization authorization) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mBinding.setViewModel(authorization);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mIsLoggedIn = authorization == null? false: authorization.isLoggedIn();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mIsTokenExpired = authorization == null ? true : authorization.isTokenExpired();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(!mIsLoggedIn || mIsTokenExpired){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (authorization != null){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Log.i("CurrentAuth", "tokenExpiresAt?: "+ authorization.getExp());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mNavController.navigate(R.id.start_login); //every time authorization is changed, we check if valid else we react by prompting user to login&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; }}LogoutFragment.javapublic class LogoutFragment extends Fragment {&nbsp; &nbsp; private AuthorizationViewModel mAuthorizationViewModel;&nbsp; &nbsp; private Authorization mAuth;&nbsp; &nbsp; private FragmentLogoutBinding mBinding;&nbsp; &nbsp; public LogoutFragment() {&nbsp; &nbsp; &nbsp; &nbsp; // Required empty public constructor&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public View onCreateView(LayoutInflater inflater, ViewGroup container,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Bundle savedInstanceState) {&nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationViewModel = ViewModelProviders.of(getActivity()).get(AuthorizationViewModel.class);&nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationViewModel.getLoggedInUserAuth().observe(getActivity(), new Observer<Authorization>() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void onChanged(Authorization authorization) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mAuth = authorization;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; // Inflate the layout for this fragment&nbsp; &nbsp; &nbsp; &nbsp; mBinding = DataBindingUtil.inflate(inflater,R.layout.fragment_logout,container,false);&nbsp; &nbsp; &nbsp; &nbsp; View view = mBinding.getRoot();&nbsp; &nbsp; &nbsp; &nbsp; mBinding.setViewModel(mAuth);&nbsp; &nbsp; &nbsp; &nbsp; return view;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {&nbsp; &nbsp; &nbsp; &nbsp; super.onViewCreated(view, savedInstanceState);&nbsp; &nbsp; &nbsp; &nbsp; new AlertDialog.Builder(getContext())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .setTitle(R.string.title_logout_fragment)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void onClick(DialogInterface dialogInterface, int i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mAuthorizationViewModel.logoutCurrentUser(); //toggle login status, this will mutate LiveData by updating the database record then UI will react and call login fragment&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void onClick(DialogInterface dialogInterface, int i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dialogInterface.cancel();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Navigation.findNavController(view).popBackStack();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .setOnDismissListener(new DialogInterface.OnDismissListener() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public void onDismiss(DialogInterface dialogInterface) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; })&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .show();&nbsp; &nbsp; }}

慕标琳琳

mAuthorization在类中创建一个getter方法AuthorizationRepositorypublic MutableLiveData<Authorization> getAuthorizationResult() {&nbsp; &nbsp;return mAuthorization;}然后像下面这样修改你的AuthorizationViewModel类public void init() {&nbsp; &nbsp; mAuthorizationRepository.getLoggedInUser();}public LiveData<Authorization> getLoggedInUserAuth() {&nbsp; &nbsp; return mAuthorizationRepository.getAuthorizationResult();}

智慧大石

为时已晚,但可能会帮助某人。我这样做时遇到了同样的问题MyDao myDao;private LiveData<List<T>> liveList;//in constructor of repo after initializing myDao;&nbsp; &nbsp; this.liveList = myDao.getAllData();//somewhere in repo&nbsp; &nbsp; for(T t : liveList.getValue()){/*computation*/}这就是我解决它的方法MyDao myDao;//in constructor of repo don't do this because called on main thread&nbsp; &nbsp; this.list = myDao.getAll();//in constructor of repo initialize your Dao (in this case myDao)//somewhere in repo&nbsp; (must not be on main thread)&nbsp; &nbsp; for(T t : myDao.getAll()){/*computation*/} //do this on background thread在我的道@Query("SELECT * FROM myTable")List<T> getAll();@Query("SELECT * FROM myTable")LiveData<List<T>> getAllData();或者,如果您在其他地方(而不是存储库)访问 liveList,那么您必须为相同的地方设置一个观察者
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java