【发布时间】:2019-10-19 10:23:48
【问题描述】:
我需要知道如何使用从 Main Activity 启动的 Service 更新 LiveData 对象的数据
我正在使用android architecture components,所以我有对象类、dao 接口、存储库、房间数据库和视图模型。
一切正常,数据在 RoomDatabase 中创建数据库时成功加载,但是,我需要更新服务中生成的数据,问题是它需要下一行中的活动上下文:
LiveData<List<WifiClass>> wifiViewModel = ViewModelProviders.of(this).get(WifiViewModel.class);
道接口:
@Dao
public interface WifiDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insert(WifiClass wifiObject);
@Insert(onConflict = OnConflictStrategy.IGNORE)
void insertAll(List<WifiClass> wifiList);
@Query("DELETE FROM wifi_table")
void deleteAll();
@Query("SELECT * from wifi_table ORDER BY SSID ASC")
LiveData<List<WifiClass>> getAllWifi();
@Query("SELECT * from wifi_table LIMIT 1")
WifiClass[] getAnyWifi();
}
存储库:
public class WifiRepository {
private WifiDao wifiDao;
private LiveData<List<WifiClass>> allWifi;
WifiRepository(Application application) {
WifiRoomDatabase db = WifiRoomDatabase.getDatabase(application);
wifiDao = db.wifiDao();
allWifi = wifiDao.getAllWifi();
}
// Get all Wifi objects
LiveData<List<WifiClass>> getAllWifi() {
return allWifi;
}
//Insert one Wifi object
public void insert (WifiClass wifiObject){
new insertAsyncTask(wifiDao).execute(wifiObject);
}
private static class insertAsyncTask extends AsyncTask<WifiClass, Void, Void> {
private WifiDao mAsyncTaskDao;
insertAsyncTask(WifiDao wifiDao) {
mAsyncTaskDao = wifiDao;
}
@Override
protected Void doInBackground(final WifiClass... params) {
mAsyncTaskDao.insert(params[0]);
return null;
}
}
}
房间数据库:
@Database(entities = {WifiClass.class}, version = 1, exportSchema = false)
public abstract class WifiRoomDatabase extends RoomDatabase implements Serializable{
public abstract WifiDao wifiDao();
private static WifiRoomDatabase INSTANCE;
public static Context context;
static List<ScanResult> results;
private static WifiManager wifiManager;
public static WifiRoomDatabase getDatabase(final Context contextt) {
context = contextt;
if (INSTANCE == null) {
synchronized (WifiRoomDatabase.class) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), WifiRoomDatabase.class, "wifi_database")
.fallbackToDestructiveMigration() // Wipes and rebuilds
.addCallback(sRoomDatabaseCallback) //
.build();
}
}
}
return INSTANCE;
}
private static RoomDatabase.Callback sRoomDatabaseCallback = new RoomDatabase.Callback(){
@Override
public void onOpen (@NonNull SupportSQLiteDatabase db){
super.onOpen(db);
new PopulateDbAsync(INSTANCE).execute();
}
};
//Populate the database in the background.
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
private final WifiDao mDao;
PopulateDbAsync(WifiRoomDatabase db) {
mDao = db.wifiDao();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
wifiManager = (WifiManager) context.getSystemService(WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()){
//Toast.makeText(this, "Wifi disable... Activating...", Toast.LENGTH_SHORT).show();
wifiManager.setWifiEnabled(true);
}
results = wifiManager.getScanResults();
wifiManager.startScan();
//Toast.makeText(this, "Scanning...", Toast.LENGTH_SHORT).show();
}
@Override
protected Void doInBackground(Void... voids) {
for (ScanResult scanResult : results) {
String ssid = scanResult.SSID;
if (ssid == null || ssid.isEmpty()){
ssid = "Hide SSID";
}
String bssid = scanResult.BSSID;
String capabilities = scanResult.capabilities;
int level = scanResult.level;
int frequency = scanResult.frequency;
long timestamp = scanResult.timestamp;
int passpoint; int channelWidth; int centerFreq0; int centerFreq1; int responder;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (scanResult.isPasspointNetwork() == true) {
passpoint = 1;
}else{
passpoint = 0;
}
channelWidth = scanResult.channelWidth;
centerFreq0 = scanResult.centerFreq0;
centerFreq1 = scanResult.centerFreq1;
if (scanResult.is80211mcResponder() == true){
responder = 1;
}else{
responder = 0;
}
}else{
passpoint = 0;
channelWidth = 0;
centerFreq0 = 0;
centerFreq1 = 0;
responder = 0;
}
WifiClass wifiObject = new WifiClass(ssid, bssid, capabilities, level, frequency,
timestamp, passpoint, channelWidth, centerFreq0, centerFreq1, responder);
mDao.insert(wifiObject);
}
return null;
}
}
视图模型:
public class WifiViewModel extends AndroidViewModel {
private WifiRepository wifiRepository;
private LiveData<List<WifiClass>> allWifi;
public WifiViewModel(@NonNull Application application) {
super(application);
wifiRepository = new WifiRepository(application);
allWifi = wifiRepository.getAllWifi();
}
LiveData<List<WifiClass>> getAllWifi() {
return allWifi;
}
public void insert(WifiClass wifiObject) {
wifiRepository.insert(wifiObject);
}
}
服务:
public class Wifi_Service extends IntentService {
private Handler handler;
private Runnable runnable;
private static Context classContext;
//private static WifiViewModel wifiViewModel;
static List<ScanResult> results;
private static WifiManager wifiManager;
private LiveData<List<WifiClass>> mAllWifi;
public Wifi_Service(/*WifiRoomDatabase db*/) {
super("wifi_service");
}
@Override
protected void onHandleIntent(Intent intent) {
}
//Populate the database in the background.
private static class PopulateDbAsync extends AsyncTask<Void, Void, Void> {
private final WifiDao mDao;
PopulateDbAsync(WifiRoomDatabase db) {
mDao = db.wifiDao();
}
@Override
protected void onPreExecute() {
super.onPreExecute();
wifiManager = (WifiManager) classContext.getApplicationContext().getSystemService(WIFI_SERVICE);
if (!wifiManager.isWifiEnabled()){
Toast.makeText(classContext, "Wifi disable... Activating...", Toast.LENGTH_SHORT).show();
wifiManager.setWifiEnabled(true);
}
results = wifiManager.getScanResults();
wifiManager.startScan();
Toast.makeText(classContext, "Scanning...", Toast.LENGTH_SHORT).show();
}
@Override
protected Void doInBackground(Void... voids) {
for (ScanResult scanResult : results) {
String ssid = scanResult.SSID;
if (ssid == null || ssid.isEmpty()){
ssid = "Hide SSID";
}
String bssid = scanResult.BSSID;
String capabilities = scanResult.capabilities;
int level = scanResult.level;
int frequency = scanResult.frequency;
long timestamp = scanResult.timestamp;
int passpoint; int channelWidth; int centerFreq0; int centerFreq1; int responder;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (scanResult.isPasspointNetwork() == true) {
passpoint = 1;
}else{
passpoint = 0;
}
channelWidth = scanResult.channelWidth;
centerFreq0 = scanResult.centerFreq0;
centerFreq1 = scanResult.centerFreq1;
if (scanResult.is80211mcResponder() == true){
responder = 1;
}else{
responder = 0;
}
}else{
passpoint = 0;
channelWidth = 0;
centerFreq0 = 0;
centerFreq1 = 0;
responder = 0;
}
WifiClass wifiObject = new WifiClass(ssid, bssid, capabilities, level, frequency,
timestamp, passpoint, channelWidth, centerFreq0, centerFreq1, responder);
//The problem
wifiViewModel.insert(wifiObject);
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(classContext, "Scanning finished", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Scanning...", Toast.LENGTH_SHORT).show();
Bundle extras = intent.getExtras();
if(extras == null) {
Log.d("Service", "null");
}else {
Log.d("Service","not null");
classContext = getApplicationContext();
}
//The problem
// wifiViewModel = ViewModelProviders.of(this).get(WifiViewModel.class);
// mWifiViewModel.getAllWifi().observe(this, new Observer<List<WifiClass>>() {
// @Override
// public void onChanged(@Nullable List<WifiClass> wifiClasses) {
//
// }
// });
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Toast.makeText(this, "Destroy scanning service", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
}
我希望服务在 LiveData 列表中执行、保存和刷新新结果,但我无法声明 LiveData 列表。
【问题讨论】:
-
getAllWifi()onWifiDao应该已经将更新返回给它的观察者,基于您将实体插入到该表中。getAnyWifi()可以做同样的事情,如果你让它返回一个LiveData。一般来说,您的服务不应该与 Room 一起使用,而应与WifiRepository一起使用,而WifiRepository(与 Room 一起)负责向相关方提供响应式更新。 -
但是,如果我尝试使用服务中的存储库,我如何访问 WifiRepository?同样的情况,我需要再次通过活动,所以这是同样的问题。
-
“同样的情况,我需要再次传递活动” --
WifiRepository没有对活动的任何引用,也不应该。它引用了Application,为此,您可以在Service上调用getApplicationContext()。 -
您永远不应该从您的 ViewModel 或其他类中引用您的活动;它完全违背了生命周期感知设计模式的目的。
标签: android service android-room lifecycle android-livedata