【问题标题】:Room query that returns List<Object> freezes application返回 List<Object> 的房间查询冻结应用程序
【发布时间】:2020-04-15 08:09:44
【问题描述】:

我尝试使用以下代码从我的数据库中加载一些数据并在活动中显示它们:

PhoneNumberViewModel phoneNumberViewModel =
        new ViewModelProvider(WorksideContactCard.this).get(PhoneNumberViewModel.class);

phoneNumberViewModel
    .getPhoneNumbersById(contactID)
    .observe(this,
             numbers -> {
                 phoneNumberList = numbers;
             });

确切地说,我不需要观察数据的变化,因为如果活动恢复,数据将被刷新。但是上面的代码冻结了我的应用程序,尽管我在其他类中使用AsyncTask 访问数据库。

为什么会这样?

编辑:

PhoneNumberViewModel.class:

public class PhoneNumberViewModel extends AndroidViewModel {
    private PhoneNumberRepository phoneNumberRepository;
    private LiveData<List<PhoneNumber>> allPhoneNumbers;

    public PhoneNumberViewModel(@NonNull Application application) {
        super(application);
        phoneNumberRepository = new PhoneNumberRepository(application);
        allPhoneNumbers = phoneNumberRepository.getAllPhoneNumbersLive();
    }

    public void insert(PhoneNumber phoneNumber) {
        System.out.println("[PhoneNumberRepository] Adding new phoneNumber");
        phoneNumberRepository.insert(phoneNumber);
    }

    public void update(PhoneNumber phoneNumber) {
        phoneNumberRepository.update(phoneNumber);
    }

    public void delete(PhoneNumber phoneNumber) {
        phoneNumberRepository.delete(phoneNumber);
    }

    public LiveData<List<PhoneNumber>> getAllPhoneNumbers() {
        return allPhoneNumbers;
    }

    public LiveData<List<PhoneNumber>> getPhoneNumbersById(long contactId)
            throws ExecutionException, InterruptedException {
        return phoneNumberRepository.getPhoneNumbersByContactId(contactId);
    }

PhoneNumberRepository.class

public class PhoneNumberRepository {
    private PhoneNumberDao phoneNumberDao;
    private LiveData<List<PhoneNumber>> allPhoneNumbers;
    private LiveData<List<PhoneNumber>> phoneNumbersByIdList;

    public PhoneNumberRepository(Application application) {

        WorksideDatabase database = WorksideDatabase.getInstance(application);
        phoneNumberDao = database.phoneNumberDao();
        allPhoneNumbers = phoneNumberDao.getAllPhoneNumbers();
    }

    ...

    public LiveData<List<PhoneNumber>> getAllPhoneNumbersLive() {
        return allPhoneNumbers;
    }

    public void deleteAllPhoneNumbers() {
        new DeleteAllPhoneNumbersAsyncTask(phoneNumberDao).execute();
    }

    public LiveData<List<PhoneNumber>> getPhoneNumbersByContactId(long id)
            throws ExecutionException, InterruptedException {
        return new SelectPhoneNumberByIdAsyncTask(phoneNumberDao, id).get();
    }

    private static class SelectPhoneNumberByIdAsyncTask
            extends AsyncTask<Long, Void, LiveData<List<PhoneNumber>>> {

        private PhoneNumberDao phoneNumberDao;
        private Long ID;

        private SelectPhoneNumberByIdAsyncTask(PhoneNumberDao phoneNumberDao, Long contactId) {
            this.phoneNumberDao = phoneNumberDao;
            ID = contactId;
        }

        @Override
        protected LiveData<List<PhoneNumber>> doInBackground(Long... contactId) {

            ID = contactId[0];

            return phoneNumberDao.getPhoneNumbersById(ID);
        }
    }

    ...
}

PhoneNumberDao.class:

@Dao
public interface PhoneNumberDao {

    @Insert
    void insert(PhoneNumber phoneNumber);

    @Update
    void update(PhoneNumber phoneNumber);

    @Delete
    void delete(PhoneNumber phoneNumber);

    // Probably uneeded method
    @Query("DELETE FROM phone_numbers_table")
    void deleteAllPhoneNumbers();

    // Delete entry/entries by ID
    @Query("DELETE FROM phone_numbers_table WHERE id = :phoneNumberId")
    void deleteByPhoneNumberId(long phoneNumberId);

    // Retrieve entry/entries by contact ID
    //    @Query("SELECT * FROM phone_numbers_table WHERE contact_id = :contactId")
    //    List<PhoneNumber> getPhoneNumbersById(long contactId);

    // Retrieve all saved phone numbers in LiveData format
    @Query("SELECT * FROM phone_numbers_table")
    LiveData<List<PhoneNumber>> getAllPhoneNumbers();

    @Query("SELECT * FROM phone_numbers_table WHERE contact_id = :contactId")
    LiveData<List<PhoneNumber>> getPhoneNumbersById(long contactId);

    @Query("SELECT * FROM phone_numbers_table")
    List<PhoneNumber> getAll();
}

【问题讨论】:

  • 你能把数据库初始化和异步任务的代码也贴出来吗...
  • @FaizanMir 嗨,我刚刚注意到我没有在这个特定片段中初始化数据库,也没有从中初始化PhoneNumberDao 对象。也许这是我的错误的根源?
  • 如果您使用 MVVM 模型并初始化存储库中的数据库,这不应该是一个问题,无论如何,如果这是应用程序将因 NullPointerException 而崩溃的问题,您可以添加一个 lil 位更准确的代码
  • @FaizanMir 相关课程添加到编辑后的答案中,如果您有任何想法,请告诉我。
  • 我建议切换到 Kotlin 并使用协程,或者在这里你可以使用回调而不是使用阻塞主线程的 AsyncTask.get() 来处理这个问题

标签: java android android-asynctask android-room


【解决方案1】:
return new SelectPhoneNumberByIdAsyncTask(phoneNumberDao, id).get(); 

这是你的问题,.get() 调用阻塞了主线程 我建议切换到 Kotlin 并使用 Coroutines 或者在这里你可以使用回调而不是使用阻塞主线程的 AsyncTask.get() 来处理这个问题。顺便说一句,我上次听说 Async Task 将被弃用,所以也要记住这一点. 这是解决问题的一种方法

public class Repository implements 
SelectPhoneNumberByIdAsyncTask.OnPhoneNumberFound {


@Override
public void onPhoneNumberFound(LiveData<List<Object>> list) {
   //you can get the data you want here
}



} 


 class SelectPhoneNumberByIdAsyncTask extends AsyncTask<Long, Void, 
  LiveData<List<PhoneNumber//Correct this>>> {

interface OnPhoneNumberFound{
    void onPhoneNumberFound(LiveData<List<PhoneNumberDao>> list);
}
OnPhoneNumberFound mListener;


private PhoneNumberDao phoneNumberDao;
private Long ID;

private SelectPhoneNumberByIdAsyncTask(Object phoneNumberDao, Long contactId) {
    this.phoneNumberDao = phoneNumberDao;
    ID = contactId;
}

@Override
protected LiveData<List<Object>> doInBackground(Long... contactId) {
    ID = contactId[0];
    mListener.onPhoneNumberFound(phoneNumberDao.getPhoneNumbersById(ID));
    return null;
}

}

现在使用 .execute() 调用而不是 .get()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-18
    • 2019-10-19
    • 2021-09-01
    • 1970-01-01
    • 2023-01-21
    • 1970-01-01
    • 2020-02-12
    相关资源
    最近更新 更多