【问题标题】:Access Room database to update widget in onHandleIntent method of IntentService访问 Room 数据库以更新 IntentService 的 onHandleIntent 方法中的小部件
【发布时间】:2019-01-25 09:18:20
【问题描述】:

我有一个小部件,每次我更新我的数据库时都想更新它,并且即使应用程序没有运行,我也想在小部件上显示数据库中的内容。 我的db 是使用Room 实现的,小部件是使用 IntentService。每次进行更新时,onHandleIntent 将尝试从数据库中获取新条目并更新小部件。

但是对于下面的代码,它总是从数据库返回一个空的List

是否有替代方法来实现这一点? AsyncTask 不能在这里工作,因为它需要在主线程上执行。

我是 RoomRxJava 的新手,所以不确定我是否遗漏了任何明显的东西。

@Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null || intent.getAction() == null) return;
        if (intent.getAction().equals(UPDATE_WIDGET)) {
            Context context = getApplicationContext();
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, ParkWidgetProvider.class));
            Observable.fromCallable(() -> {
                db = FavDatabase.getInstance(context);
                return db;
            })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(result -> {
                        List<FavParkEntity> favParkEntityList = result.favDoa().getFavPark().getValue();
                        if (favParkEntityList != null) {
                            if (favParkEntityList.size() == 1) {
                                FavParkEntity favParkEntity = favParkEntityList.get(0);
                                latLong = favParkEntity.getLatLong();
                                parkCode = favParkEntity.getParkCode();
                                imgUrl = favParkEntity.getImage();
                                title = favParkEntity.getPark_name();
                                Log.e(TAG, "onHandleIntent: HERE: " + title);
                                StringToGPSCoordinates stringToGPSCoordinates = new StringToGPSCoordinates();
                                final String gpsCoodinates[] = stringToGPSCoordinates.convertToGPS(latLong);
                                getLastLocation(gpsCoodinates);
                                String weatherDetails[] = getCurrentWeather(context, gpsCoodinates);
                                ParkWidgetProvider.updateAppWidgets(context, appWidgetManager, appWidgetIds, parkCode, imgUrl, title, weatherDetails, distance);
                            } else {
                                Log.e(TAG, "onHandleIntent: HERE SIZE");
                            }
                        } else {
                            Log.e(TAG, "onHandleIntent: HERE NULL");
                        }
                    });
        }
    }

数据库:

@Database(entities = {FavParkEntity.class},version = 1, exportSchema = false)
@TypeConverters({Converters.class})
public abstract class FavDatabase extends RoomDatabase {

    public static final String DATABASE_NAME = "favorites";

    private static final Object LOCK = new Object();
    private static FavDatabase sInstance;

    public static  FavDatabase getInstance(Context context){
        if(sInstance==null){
            synchronized (LOCK){
                sInstance = Room.databaseBuilder(context.getApplicationContext(),FavDatabase.class, FavDatabase.DATABASE_NAME)
                        .build();
            }
        }
        return sInstance;
    }

    public RoomDatabase dbExist(){
        return sInstance;
    }

    public abstract FavDao favDoa();

}

道:

@Dao
public interface FavDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void save(FavParkEntity park);
    @Query("SELECT * FROM favorites")
    LiveData<List<FavParkEntity>> getFavPark();
    @Query("DELETE FROM favorites")
    void clearTable();
}

型号:

@Entity(tableName = "favorites")
public class FavParkEntity extends ParkEntity {

    public FavParkEntity() {
    }

    public FavParkEntity (ParkEntity parkEntity){
        this.setPark_id(parkEntity.getPark_id());
        this.setPark_name(parkEntity.getPark_name());
        this.setStates(parkEntity.getStates());
        this.setParkCode(parkEntity.getParkCode());
        this.setLatLong(parkEntity.getLatLong());
        this.setDescription(parkEntity.getDescription());
        this.setDesignation(parkEntity.getDesignation());
        this.setAddress(parkEntity.getAddress());
        this.setPhone(parkEntity.getPhone());
        this.setEmail(parkEntity.getEmail());
        this.setImage(parkEntity.getImage());
    }

}

【问题讨论】:

  • 请记住,您已经安装了 RxJava,最好的办法是在大多数数据流事务中使用它(如果不是全部的话)。您能向我们展示您的模型和 favdatabase 设置吗?跨度>
  • 谢谢。我已经用模型和数据库更新了帖子:

标签: android android-widget rx-java android-room android-intentservice


【解决方案1】:

实现有很多问题。

首先,result.favDoa().getFavPark().getValue() 将始终返回 null,因为 LiveData 是异步的。 LiveData 是用来观察的。

您使用RxJava 的方式似乎也不正确。你没有异步做任何真正的工作。完全可以不使用RxJava 来编写该实现。

还请注意,将LiveDataRxJava 一起使用并不容易,因为它们不能直接互换。人们喜欢使用“完整的LiveData”、“完整的RxJava”或“RxJava”,直到 UI 组件切换到 LiveData

有很多不同的方法可以解决这个问题。一种选择是将您的实现完全更改为 RxJava。 (Room 支持 RxJava:https://developer.android.com/topic/libraries/architecture/adding-components#room

道:

@Dao
public interface FavDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void save(FavParkEntity park);
    @Query("SELECT * FROM favorites")
    Single<List<FavParkEntity>> getFavPark(); // Switch to RxJava
    @Query("DELETE FROM favorites")
    void clearTable();
}

你的主要代码:

@Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null || intent.getAction() == null) return;
        if (intent.getAction().equals(UPDATE_WIDGET)) {
            Context context = getApplicationContext();
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, ParkWidgetProvider.class));
            FavDatabase.getInstance(context).favDoa().getFavPark()  // Access database here.
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(favParkEntityList -> {
                        // Put your mainThread works here.
                        if (favParkEntityList != null) {
                            if (favParkEntityList.size() == 1) {
                                FavParkEntity favParkEntity = favParkEntityList.get(0);
                                latLong = favParkEntity.getLatLong();
                                parkCode = favParkEntity.getParkCode();
                                imgUrl = favParkEntity.getImage();
                                title = favParkEntity.getPark_name();
                                Log.e(TAG, "onHandleIntent: HERE: " + title);
                                ...
                            } else {
                                Log.e(TAG, "onHandleIntent: HERE SIZE");
                            }
                        } else {
                            Log.e(TAG, "onHandleIntent: HERE NULL");
                        }
                   });
        }
    }

或者,如果您无法将您的 Dao 从 LiveData 切换到 RxJava,您可以创建 getFavPark() 的同步版本。

道:

@Dao
public interface FavDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void save(FavParkEntity park);
    @Query("SELECT * FROM favorites")
    LiveData<List<FavParkEntity>> getFavPark();
    @Query("SELECT * FROM favorites")
    List<FavParkEntity> getFavParkSync(); // Synchronous access
    @Query("DELETE FROM favorites")
    void clearTable();
}

你的主要代码:

@Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent == null || intent.getAction() == null) return;
        if (intent.getAction().equals(UPDATE_WIDGET)) {
            Context context = getApplicationContext();
            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
            int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, ParkWidgetProvider.class));
            Observable.fromCallable(() -> {
                // fromCallable and subscribeOn will make
                // below code run in a worker thread asynchronously.
                return FavDatabase.getInstance(context).favDoa().getFavParkSync();
            })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(favParkEntityList -> {
                        // Put your mainThread works here.
                        if (favParkEntityList != null) {
                            if (favParkEntityList.size() == 1) {
                                FavParkEntity favParkEntity = favParkEntityList.get(0);
                                latLong = favParkEntity.getLatLong();
                                parkCode = favParkEntity.getParkCode();
                                imgUrl = favParkEntity.getImage();
                                title = favParkEntity.getPark_name();
                                Log.e(TAG, "onHandleIntent: HERE: " + title);
                                ...
                            } else {
                                Log.e(TAG, "onHandleIntent: HERE SIZE");
                            }
                        } else {
                            Log.e(TAG, "onHandleIntent: HERE NULL");
                        }
                   });
        }
    }

【讨论】:

  • 非常感谢!我选择了选项 1,并用 RxJava 完全实现了它。它现在可以工作了!
猜你喜欢
  • 1970-01-01
  • 2016-08-25
  • 1970-01-01
  • 2021-09-27
  • 1970-01-01
  • 2014-04-14
  • 1970-01-01
  • 2016-10-14
  • 1970-01-01
相关资源
最近更新 更多