java - 在非 View 或非 ViewModel 类中观察 LiveData

我有一个应用程序,它允许用户将他们的凭据输入到片段中,然后片段插入或更新 Room 数据库中的记录。事务由 CredentialsRepository 处理。

在网络方面,我有一个 DataRepository,它与 NetworkServiceController 一起使用来创建对我的远程 API 的调用。为了访问远程 API,我有一个拦截器,它将用户凭据添加到每个调用。

我需要的是在应用程序加载时以及 Room 数据库中的数据发生变化时加载这些凭据。我可以在我的登录屏幕( View )中使用 LiveData 来执行此操作,但我如何使用 LiveData 在我的 DataRepository 中观察用户凭据数据?

如何将我的 DataRepository 类注册为观察者?现在我的应用程序崩溃了……我很确定我注册观察者的方式是错误的。

这是我的 CredentialsRepository:

    import androidx.lifecycle.LiveData;
    import ca.thirdgear.homeautomation.HomeAutomationApp;
    import ca.thirdgear.homeautomation.dao.UserCredentialsDAO;
    import ca.thirdgear.homeautomation.entity.UserCredentials;
    import javax.inject.Inject;
    import javax.inject.Singleton;

    /**
     * Repository Class for data from the Room Database
     */
    @Singleton
    public class CredentialsRepository
    {
        @Inject
        UserCredentialsDAO credentialsDAO;

        @Inject
        public CredentialsRepository()
        {
            HomeAutomationApp.getAppComponent().inject(this);
        }

        public void setCredentials(String userEmail, String password)
        {
            //create UserCredentials object with the credentials provided from the UI.
            UserCredentials newOrUpdatedUserCredentials = new UserCredentials(userEmail, password);

            //insert user credentials into the database
            Runnable myRunnableObject = new SetUserCredentials(credentialsDAO, newOrUpdatedUserCredentials);
            new Thread(myRunnableObject).start();
        }

        public LiveData<UserCredentials> getCredentials()
        {
            return credentialsDAO.getUser();
        }
    }

这是我的 DataRepositoryClass

    /**
     * Repository class for handling network calls to REST API
     */
    @Singleton
    public class DataRepository
    {
        //Network components
        @Inject
        NetworkServiceController networkServiceController;

        @Inject
        UserCredentialsDAO credentialsDAO;

        @Inject
        CredentialsRepository credRepo;

        private HomeAutomationAPI homeAutomationAPIService;
        private MutableLiveData<String> zoneOneState;
        private MutableLiveData<String> zoneTwoState;
        private MutableLiveData<String> garageDoorState;
        private MutableLiveData<String> adtSystemState;
        private MutableLiveData<String> panelTemperature;
        private String username;
        private String password;


        @Inject
        public DataRepository()
        {
            //Inject Network Backend Components & Room DAO
            HomeAutomationApp.getAppComponent().inject(this);

            //create credentials observer
            final Observer<UserCredentials> credentialsObserver = new Observer<UserCredentials>() {
                @Override
                public void onChanged(UserCredentials userCredentials)
                {
                    //update string values for credentials
                    username = userCredentials.getUsername();
                    password = userCredentials.getPassword();

                    //call createNetworkService() to create a new network service object
                    createNetworkService();
                }
            };

            //register the observer
            //this does not work...app crashes
            credRepo.getCredentials().observeForever(credentialsObserver);

            zoneOneState = new MutableLiveData<>();
            zoneTwoState = new MutableLiveData<>();
            garageDoorState = new MutableLiveData<>();
            adtSystemState = new MutableLiveData<>();
            panelTemperature = new MutableLiveData<>();

            //Poll the server every 5 seconds on a separate thread for changes in the IO
            Thread thread = new Thread(new Runnable(){
                public void run()
                {
                    // Moves the current Thread into the background
                    android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

                    while(true)
                    {
                        try {
                            sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        getIoStatus();
                    }
                }
            });
            thread.start();
        }

        /*
             Create the network service when there are changes in the user credentials data.
         */
          private void createNetworkService()
          {
              homeAutomationAPIService = networkServiceController.createService(HomeAutomationAPI.class, username, password);
          }


        ... deleted methods not relevant ...

    }

编辑: 观察者注册可以像这样在 DataRepository 中发生:

credRepo.getCredentials().observeForever(credentialsObserver);

或者像这样:

credentialsDAO.getUser().observeForever(credentialsObserver);

但是,我需要通过调用在构造函数中创建网络服务:

createNetworkService();

否则应用程序仍然会崩溃。

我的应用程序现在可以在添加上面的代码行的情况下运行,但是产生了一个新问题。当应用程序在新进程中启动时,需要几秒钟的时间才能获得任何网络数据。我的猜测是创建 DataRepository 的速度比从数据库中检索数据的速度快,并且我的网络服务最初是使用空的或未知的用户凭据创建的。这是一个正确的假设吗?

最佳答案

问题是我没有设置 Room 来允许主线程查询使用:

allowMainThreadQueries()

用法:

public static CredentialsDatabase getDatabase(final Context context)
{
    if (INSTANCE == null)
    {
        synchronized (CredentialsDatabase.class)
        {
            if (INSTANCE == null)
            {
                INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                        CredentialsDatabase.class, "credentials_database")
                        .addCallback(initializeCallback)
                        //allow main thread queries only used for DataRepository instantiation as
                        //credentials are required to set up network services.
                        .allowMainThreadQueries()
                        .build();
            }
        }
    }
    return INSTANCE;
}

我需要在创建 DataRepository 时将 UserCredentials 的值保存在内存中,这样我就可以在我的 View 处于 Activity 状态时立即进行网络调用。我还在我的 DAO 中创建了一个查询,该查询返回未包装在 LiveData 对象中的 UserCredentials。有关我如何得出此解决方案的信息,请参阅此 Stackoverflow post .

将来我还会创建一个日志文件以方便故障排除。

https://stackoverflow.com/questions/57012639/

相关文章:

c# - 502 Bad Gateway nginx/1.14.1 elasticbeanstalk

angular - Ionic 4 - 在平台硬件后退按钮 android 上关闭或关闭模态

wordpress - 如何优化WP_Query(包括CPT和ACF)

ios - 如果先前已加载某些网页,WKWebView 不会加载 .archive 文件

react-native - 位于 "node_modules/web3-eth-accounts/

json - 如何从 yang 模块生成 JSON 模式?

gcc - 从一个编译器版本到另一个编译器版本的符号重定位

spring-boot - spring boot 微服务 docker 实现中 google oa

c# - C# 中 C++ 结构化绑定(bind)的模拟

jenkins - BlueOcean编辑器 "scm"输入什么