Доступ к базе данных комнат для обновления виджета в методе onHandleIntent IntentService - PullRequest
0 голосов
/ 25 января 2019

У меня есть виджет, который я хочу обновлять каждый раз, когда обновляю свою базу данных, и хочу показать содержимое из базы данных на виджете, даже если приложение не запущено. Мой db реализован с использованием Room, а виджет обновляется с использованием IntentService. Каждый раз, когда производится обновление, onHandleIntent будет пытаться получить новую запись из БД и обновить виджет.

Но для приведенного ниже кода он всегда возвращает ноль List из db

Есть ли альтернативный способ реализовать это? AsyncTask здесь не будет работать, так как требует выполнения в главном потоке.

Я новичок в Room и RxJava, поэтому не уверен, пропустил ли я что-нибудь очевидное.

@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());
    }

}

1 Ответ

0 голосов
/ 26 января 2019

В реализации много неправильного.

Прежде всего, result.favDoa().getFavPark().getValue() всегда будет возвращать ноль, потому что LiveData является асинхронным. LiveData предназначено для наблюдения.

Также способ, которым вы используете RxJava, кажется неправильным. Вы не выполняете никакой реальной работы асинхронно. Эта реализация может быть написана без использования RxJava.

Также обратите внимание, что не существует простого способа использовать LiveData AND RxJava вместе, потому что они не являются взаимозаменяемыми. Людям нравится идти либо «полный LiveData», «полный RxJava», либо «RxJava, пока компоненты пользовательского интерфейса не переключатся на LiveData.

Есть много разных способов решить эту проблему. Один из вариантов - полностью изменить вашу реализацию на RxJava. (В номере есть поддержка 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");
                        }
                   });
        }
    }
...