我有一个应用程序,它允许用户将他们的凭据输入到片段中,然后片段插入或更新 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 .
将来我还会创建一个日志文件以方便故障排除。
关于java - 在非 View 或非 ViewModel 类中观察 LiveData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57012639/