【问题标题】:For some reason my Android room DAO insert doesn't work on Temi Robot出于某种原因,我的 Android 房间 DAO 插入在 Temi Robot 上不起作用
【发布时间】:2021-10-01 07:44:05
【问题描述】:

由于某种原因even after following some parts of the guide,我无法在我的数据库中插入新条目。检索是可以的。我真的不想做指南中提到的呼吸和视图模型样板

我已经将相关的依赖项放在了 build.gradle 中。 我正在使用 Java 11。

TemiPatrolRoomDatabase.java:

@Database(entities = {AudioFile.class},version = 1)
public abstract class TemiPatrolRoomDatabase extends RoomDatabase {
    public abstract TemiPatrolDAO temiPatrolDAO();

    private static volatile TemiPatrolRoomDatabase INSTANCE;
    private static final int NUMBER_OF_THREADS = 8;
    public static final ExecutorService databaseWriteExecutor =
            Executors.newFixedThreadPool(NUMBER_OF_THREADS);

   public static TemiPatrolRoomDatabase getDatabase(final Context context) {
        if (INSTANCE == null) {
            synchronized (TemiPatrolRoomDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            TemiPatrolRoomDatabase.class, "temiPatrolDatabase")
                            .build();
                }
            }
        }
        return INSTANCE;
    }
}

TemiPatrolDAO.java

@Dao
public interface TemiPatrolDAO {

    @Query("SELECT * from AudioFile")
    List<AudioFile> getAll();

    @Insert(entity = AudioFile.class,onConflict = OnConflictStrategy.IGNORE)
    void insertAll(AudioFile... audioFiles);

    @Insert(entity = AudioFile.class,onConflict = OnConflictStrategy.IGNORE)
    void insert(AudioFile audioFile);

    @Delete
    void delete(AudioFile audioFile);
}

SettingsFragment.java:

public void onCreate(Bundle savedInstanceState) {
     ....
        addAudioFileResultLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(),
                result -> {
                    Intent resultingIntent = result.getData();
                    assert resultingIntent != null;
                    var uri = resultingIntent.getData();
                    var cursor = requireActivity()
                            .getContentResolver()
                            .query(uri, null, null,
                                    null, null);
                    int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
                    cursor.moveToFirst();
                    var fileName = cursor.getString(nameIndex);
                    Toast.makeText(getActivity(),
                            "audio added:" + fileName,
                            Toast.LENGTH_LONG)
                            .show();
                    var audioFile = new AudioFile(uri.getPath(), fileName);
                    var future = TemiPatrolRoomDatabase.databaseWriteExecutor.submit(() -> {
                        Log.d(TAG, "audio name to be inserted:"+audioFile.getName());
                        temiPatrolDAO.insert(audioFile);
                        var a = (ArrayList<AudioFile>) temiPatrolDAO.getAll();
                        Log.d(TAG, "after insertion");
                        for (var a1 : a) {
                            Log.d(TAG, "file name:" + a1.getName());
                        }
                    });
                    while (!future.isDone()){}
                        Log.d(TAG, "after future of inserting data is done");
                    audioFiles.add(audioFile);
                    customAdapter.notifyDataSetChanged();
                    cursor.close();
                }
        );
        var context = requireActivity().getApplicationContext();
        var database = TemiPatrolRoomDatabase.getDatabase(context);
        temiPatrolDAO = database.temiPatrolDAO();
    }

AudioFile.java


@SuppressWarnings("ALL")
@Entity
public class AudioFile {
    @PrimaryKey
    private int audioFileID;

    private String uriPath;
    private String name;

    public AudioFile(String uriPath, String name) {
        this.setUriPath(uriPath);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAudioFileID() {
        return audioFileID;
    }

    public void setAudioFileID(int audioFileID) {
        this.audioFileID = audioFileID;
    }

    public String getUriPath() {
        return uriPath;
    }

    public void setUriPath(String uriPath) {
        this.uriPath = uriPath;
    }
}

【问题讨论】:

  • 如果将insert 函数的@Insert(entity = AudioFile.class,onConflict = OnConflictStrategy.IGNORE) 更改为@Insert(entity = AudioFile.class),会得到什么结果?然后它会发出异常吗?也可以将 AudioFile 类添加到您的问题中。
  • 添加了 AudioFIle.java。删除 onConflict = OnConflictStrategy.IGNORE 后没有错误消息。编辑:也许我误解了 Room 自动添加 id,让我更改主键...
  • 感谢您的帮助,将主键从 id 更改为我的 uriPath 有效。

标签: java android android-room


【解决方案1】:

您遇到的一个问题是private int audioFileID;,并且您在使用时没有为 audioFileID 指定值:-

var audioFile = new AudioFile(uri.getPath(), fileName);

然后

temiPatrolDAO.insert(audioFile);

由于 int 默认为 0,因此不设置 audioFileID,除了第一个插入之外的任何内容都将发生 UNIQUE 冲突,因为主键必须是表中的唯一值。 IGNORE 的 onConflictStrategy 将简单地忽略冲突 BUT 并继续执行而不插入行。

我建议更改为使用任何一个:-

@Entity
public class AudioFile {
    @PrimaryKey
    private Long audioFileID; //<<<<< CHANGED

    private String uriPath;
    private String name;

    public AudioFile(String uriPath, String name) {
        this.setUriPath(uriPath);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getAudioFileID() { //<<<<< CHANGED
        return audioFileID;
    }

    public void setAudioFileID(long audioFileID) { //<<<<< CHANGED
        this.audioFileID = audioFileID;
    }

    public String getUriPath() {
        return uriPath;
    }

    public void setUriPath(String uriPath) {
        this.uriPath = uriPath;
    }
}

原因是 Object (Long) 将默认为 null,在这种情况下,Room 将(如果使用上述)解释为未指定的值,因此列及其值从 INSERT 中省略。

  • 我建议Long,因为值可以是Long。但是,可以使用 Integer,但如果行数大于 int 可以容纳的行数,则可能会出现问题(因此,我将始终为 ID 列编码 Long/long)。

或者,由于 uriPath 可能是唯一的,您可以将其作为主键并删除 audioFileID 列,例如:-

@Entity
public class AudioFile {
    @PrimaryKey
    private String uriPath;
    private String name;

    public AudioFile(String uriPath, String name) {
        this.setUriPath(uriPath);
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUriPath() {
        return uriPath;
    }

    public void setUriPath(String uriPath) {
        this.uriPath = uriPath;
    }
}
  • 这样做的缺点(可能不重要)是,由于该列不是 INTEGER,因此它不是 rowid 的别名(Room 中始终存在的特殊列)。通过 rowid 列的访问可以显着增加(最多快两倍)。但是,这对于较小的表来说几乎是微不足道的。

您可能会遇到的另一个问题是在获取 Cursor 之后(如果从 SQLiteDatabase(因此 SupportSQLiteDatabase)方法返回,则它永远不会为空)。如果 Cursor 为空并且您不检查 moveToFirst 的结果(如果移动为 true,否则为 false(也就是没有行)),那么您将得到一个异常。所以你应该有类似的东西:-

            if (cursor.moveToFirst()) {
                var fileName = cursor.getString(nameIndex);
                Toast.makeText(getActivity(),
                        "audio added:" + fileName,
                        Toast.LENGTH_LONG)
                        .show();
                var audioFile = new AudioFile(uri.getPath(), fileName);
                var future = TemiPatrolRoomDatabase.databaseWriteExecutor.submit(() -> {
                    Log.d(TAG, "audio name to be inserted:"+audioFile.getName());
                    temiPatrolDAO.insert(audioFile);
                    var a = (ArrayList<AudioFile>) temiPatrolDAO.getAll();
                    Log.d(TAG, "after insertion");
                    for (var a1 : a) {
                        Log.d(TAG, "file name:" + a1.getName());
                    }
                });
                while (!future.isDone()){}
                    Log.d(TAG, "after future of inserting data is done");
                audioFiles.add(audioFile);
                customAdapter.notifyDataSetChanged();
            }
            cursor.close();
  • 注意我没有检查上面的代码,所以可能会有一些错误,重要的是原理。

【讨论】:

    【解决方案2】:

    我已将我的@PrimaryKey 从audioFileID 更改为uriPath,

    然后我从 Temi Robot 中删除了我的应用

    adb shell pm list packages
    
    adb uninstall <my-package>
    

    最后我重新安装了我的应用,它可以工作了。

    @SuppressWarnings("ALL")
    @Entity
    public class AudioFile {
        @PrimaryKey
        private int audioFileID;
    
        private String uriPath;
        private String name;
    
        public AudioFile(String uriPath, String name) {
            this.setUriPath(uriPath);
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAudioFileID() {
            return audioFileID;
        }
    
        public void setAudioFileID(int audioFileID) {
            this.audioFileID = audioFileID;
        }
    
        public String getUriPath() {
            return uriPath;
        }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      相关资源
      最近更新 更多