android - 房间 : replace SQLite cursor in Dao?

标签 android cursor android-sqlite android-room

我有一个 JobIntentService,它可以从 SQLite 数据库中重新设置挂起的警报通知。它使用查询和游标从数据库中的 4 个不同列获取通知日期。我正在转换为 Room 数据库,但不确定如何将游标转换为 Dao 方法。我是否需要使用 @Transaction 因为我从数据库中的多个列获取通知?如果您有任何关于如何在 Room 中构建的见解或想法,我们将不胜感激。

Service

public class Service extends JobIntentService {

static final int JOB_ID = 9;

public static void enqueueWork(Context context, Intent work) {
    enqueueWork(context, RebootService.class, JOB_ID, work);
} 

@Override
protected void onHandleWork(@NonNull Intent intent) {

    AlarmManager alarmManager1;
    Intent brIntent1;
    PendingIntent pendingIntent1;

    SQLiteDB sqLiteDB = SQLiteDB.getInstance(this);
    Calendar cal1 = Calendar.getInstance();

    Cursor cursor = sqLiteDB.resetNotifications(); 

     try {
          if (cursor.getCount() > 0) { 
              cursor.moveToFirst(); 

              int dueDatentimeColumnIndex = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_DUEDATENTIME);
              int notifColumnIndex1 = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_NOTIFTIME);
              int notif2ColumnIndex2 = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_NOTIFTIME2);
              int randColumnIndex1 = cursor.getColumnIndex(ItemContract.ItemEntry.COLUMN_RANDINT);

              while (!cursor.isAfterLast()) {  

                  do {

                      long notifTime1 = cursor.getLong(notifColumnIndex1);
                      int randInt1 = cursor.getInt(randColumnIndex1);
                      cal1.setTime(new Date(notifTime1));

                      // Set up a system AlarmManager to fire a future alarm that sends a Notification
                      // even if the app is in the background or closed.
                      alarmManager1 = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

                      if (cal1.getTimeInMillis() > System.currentTimeMillis()) {                                            
                          brIntent1 = new Intent(this, AlarmReceiver.class);
                       brIntent1.setAction("24Hour");

                       pendingIntent1 = PendingIntent.getBroadcast(this, randInt1, brIntent1,
                                    PendingIntent.FLAG_ONE_SHOT);

                      if (alarmManager1 != null && notifTime1 != -1) {
                          alarmManager1.set(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(), pendingIntent1);
                      }
...       
}

SQLiteDB.java

...
public Cursor resetNotifications() {

   SQLiteDatabase db = getReadableDatabase();

   String[] columns = new String[]{
                ItemContract.ItemEntry.COLUMN_NOTIFTIME,
                ItemContract.ItemEntry.COLUMN_NOTIFTIME2,
                ItemContract.ItemEntry.COLUMN_DUEDATENTIME,
                ItemContract.ItemEntry.COLUMN_RANDINT};

        return db.query(
                TABLE_NAME, 
                columns, // The columns to return
                null,      
                null,   
                null,      
                null,       
                null       
        ); 
}

This is the code I came up as a replacement:

public class RebootService extends JobIntentService {

// Unique job ID for this service
static final int JOB_ID = 10000;

// Convenience method for enqueueing work to this service.
public static void enqueueWork(Context context, Intent work) {
    enqueueWork(context, RebootService.class, JOB_ID, work);
}

private QuickcardRepository reposit1;

@Override
protected void onHandleWork(@NonNull Intent intent) {

    reposit1 = new QuickcardRepository(getApplication());

    Bundle extras = intent.getExtras(); // Returns the Intent *that started this Service.*
    if (extras != null) {

        String classname = extras.getString("TAG");

        if (classname != null && classname.equals("bootCompleted")) {

            AlarmManager alarmManager1;
            Intent brIntent1, brIntent2, brIntent3;
            PendingIntent pendingIntent1, pendingIntent2, pendingIntent3;

            Calendar cal1 = Calendar.getInstance();
            Calendar cal2 = Calendar.getInstance();
            Calendar cal3 = Calendar.getInstance();

            List<Quickcard> resetNotificationsList = reposit1.getNotifications();
            // Cycle through the Room database rows to get the Notifications data
            for (Quickcard quickcard: resetNotificationsList) {
                 // Quickcards without a Due date get a Due date in the database of -1.
                 // Therefore, only cycle through and get data for those quickcards that have
                //  a Due data and therefore have Notifications (reminders) where the actual
                //  "Due date" is != -1.
                 if(quickcard.getDuedatentime() != -1) {

                     // Set up the 24-Hour calendar object.
                     long notifTime1 = quickcard.getNotiftime();
                     int randInt1 = quickcard.getRandint();
                     cal1.setTime(new Date(notifTime1));

                     // Set up a system AlarmManager to fire a future alarm that sends a Notification
                     // even if the app is in the background or closed.  Have to add "context" here.
                     alarmManager1 = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

                     // If the stated alarm trigger time is in the past, the alarm will be triggered immediately.
                     // So only set Alarms to fire Notifications for Duedates in the future
                     // (meaning > than the current System time).  Ignore those in the past.
                     if (cal1.getTimeInMillis() > System.currentTimeMillis()) {
                         // For the 24Hour Notifications.
                         // Set up a PendingIntent that will perform broadcast to the BroadcastReceiver.
                         brIntent1 = new Intent(this, AlarmReceiver.class);
                         brIntent1.setAction("24Hour");
                         // Need to use FLAG_ONE_SHOT on the PendingIntent, not FLAG_UPDATE_CURRENT.
                         // A random int is used to be able to set multiple alarms and then to be able to
                         // delete them later (if the user for ex., deletes the quickCards Duedate) using
                         // the same random int.
                         pendingIntent1 = PendingIntent.getBroadcast(this, randInt1, brIntent1,
                                 PendingIntent.FLAG_ONE_SHOT);

                         // Alarms have 3 properties below after "set(...)":
                         // 1) Alarm type:  RTC_WAKEUP type is chosen here to wake the device from sleep.
                         // 2) Trigger time: in this case, 24 hours before the Duedate/Duetime is reached.
                         // 3) Pending Intent:  A future Intent that is sent when the trigger time is reached.
                         int SDK_INT1 = Build.VERSION.SDK_INT;
                         if (SDK_INT1 >= Build.VERSION_CODES.M) {
                             // Wakes up the device in Doze Mode for API Level 23 and higher.
                             // The "... != -1" test only sets up pendingIntents for quickCards that have
                             // a Notification.  quickCards with no Duedate & Duetime are bypassed.
                             if (alarmManager1 != null && notifTime1 != -1) {
                                 alarmManager1.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(),
                                         pendingIntent1);
                             }
                         } else if (SDK_INT1 >= Build.VERSION_CODES.KITKAT) {
                             // Wakes up the device in Idle Mode for API Level 19 to 22.
                             // The "... != -1" test only sets up pendingIntents for quickCards that have
                             // a Notification.  quickCards with no Duedate & Duetime are bypassed.
                             if (alarmManager1 != null && notifTime1 != -1) {
                                 alarmManager1.setExact(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(), pendingIntent1);
                             }
                         } else {
                             // Old APIs Level 18 and below.
                             // The "... != -1" test only sets up pendingIntents for quickCards that have
                             // a Notification.  quickCards with no Duedate & Duetime are bypassed.
                             if (alarmManager1 != null && notifTime1 != -1) {
                                 alarmManager1.set(AlarmManager.RTC_WAKEUP, cal1.getTimeInMillis(), pendingIntent1);
                             }
                         }
                     }

最佳答案

我相信 @Transaction 将代码包装在事务中。除了@Query(如果@Query 不是更新/删除查询(如果它是更新或删除查询,它包含在事务中)),这已经完成了。

我认为关于 SELECT 查询是否应该包含在事务中的问题 (@Transaction @Query ......) 是否使用了@Relation。如果是,则相关/关联项目/对象的列表将作为单独的查询运行,因此在事务中运行它们将确保一致的数据。否则,基础数据可能会被其他交易更改,因此结果数据可能会不一致。

表示在不需要的地方使用 @Transaction 几乎不会产生影响,如果在可能无意中未被编码的地方进行编码,甚至可能产生积极影响。

当然,无论如何,您始终可以使用 Room 返回 Cursor。你不妨看看Associating tables using Room database in Android Studio ,其中有一些示例。

根据您的代码,主要是您有一个带有 ItemEntry 子类的 ItemContract,然后 ItemEntry 的实体可以在 ItemEntry.java 中,按照:-

@Entity
public class ItemEntry {

    @PrimaryKey(autoGenerate = true)
    private long id;
    @ColumnInfo(name = COLUMN_NOTIFTIME)
    private long notiftime;
    @ColumnInfo(name = COLUMN_NOTIFTIME2)
    private long notiftime2;
    @ColumnInfo(name = COLUMN_DUEDATENTIME)
    private long duedatentime;
    @ColumnInfo(name = COLUMN_RANDINT)
    public int randint;

    public ItemEntry(){

    }

    @Ignore
    public ItemEntry(long notiftime, long notiftime2, long duedatentime, int randint) {
        this.notiftime = notiftime;
        this.notiftime2 = notiftime2;
        this.duedatentime = duedatentime;
        this.randint = randint;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public long getNotiftime() {
        return notiftime;
    }

    public void setNotiftime(long notiftime) {
        this.notiftime = notiftime;
    }

    public long getNotiftime2() {
        return notiftime2;
    }

    public void setNotiftime2(long notiftime2) {
        this.notiftime2 = notiftime2;
    }

    public long getDuedatentime() {
        return duedatentime;
    }

    public void setDuedatentime(long duedatentime) {
        this.duedatentime = duedatentime;
    }

    public int getRandint() {
        return randint;
    }

    public void setRandint(int randint) {
        this.randint = randint;
    }
} 

连同接口(interface) ItemEntryDao.java 为:-

@Dao
interface ItemEntryDao {
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long[] insertItemEntries(ItemEntry... itemEntries);
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    long insertItemEntry(ItemEntry itemEntry);
    @Update(onConflict = OnConflictStrategy.IGNORE)
    int updateItemEnrties(ItemEntry... itemEntries);
    @Update(onConflict = OnConflictStrategy.IGNORE)
    int updateItemEntry(ItemEntry itemEntry);
    @Delete
    int deleteItemEntries(ItemEntry... itemEntries);
    @Delete
    int deleteItemEntry(ItemEntry itemEntry);
    @Query("SELECT * FROM ItemEntry")
    List<ItemEntry> resetNotifications();
}
  • @Query 等同于 Cursor,但返回一个 ItemEntry 对象列表。

上面的示例可以使用(基本上复制您的代码,但将提取的数据输出到日志),例如:-

public void onHandleWork() {

    ItemEntry ie = new ItemEntry();
    ie.setNotiftime(100);
    ie.setNotiftime2(200);
    ie.setDuedatentime(500000);
    ie.setRandint(567);
    mDB.getItemEntryDao().insertItemEntry(ie);
    List<ItemEntry> mylist = mDB.getItemEntryDao().resetNotifications();
    for (ItemEntry itementry: mylist) {
        Log.d("ITEMENTRY",
                "\n\tnotiftime= " + String.valueOf(itementry.getNotiftime()) +
                        "\n\tnotiftime2= " + String.valueOf(itementry.getNotiftime2()) +
                        "\n\tduedatetime= " + String.valueOf(itementry.getDuedatentime()) +
                        "\n\trandint= " + String.valueOf(itementry.getRandint())

        );
    }
}
  • mDB 是构建对象(即@Database 类的一个实例)

这将导致(对于第一次运行):-

05-28 14:31:14.587 7211-7211/aso.so56326640 D/ITEMENTRY:  notiftime= 100
      notiftime2= 200
      duedatetime= 500000
      randint= 567

关于android - 房间 : replace SQLite cursor in Dao?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56328482/

相关文章:

java - 如何在android对话框窗口中更新多选

android - android中主键的自动更新

java - 如何在 SQLite 中向表添加外键?

android - 无法使用 rawQuery 正确执行删除查询

android - 在 FragmentPagerAdapter 选项卡上显示图标

android - 图片背景根据屏幕大小不使用九 fragment

android - 在 Android 中获取联系方式需要花费大量时间?

Android自定义动画,如机场时间表

android - 卡观 Material 波纹?

solr - Solr 的 Cursor 和 ElasticSearch 的 Scroll 之间的差异