1

I am querying POJO which is NOT being Observed / Non-Live data from an IntentService that was started in a PreferenceFragment. However a second my application crashes and log displays:

java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
    at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204)
    at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:232)
    at vault.dao.xxxDao_Impl.getAllNonLivePojoItems(xxxDao_Impl.java:231)

I want to know why is my program throwing this exception. as per https://stackoverflow.com/a/23935791/8623507

my database query[s] are inside an IntentService that runs In its own thread so i should be in the green. here is my code:

Inside IntentService
--------------------

// ERROR OCCURS HERE
List<POJO> pojoList = localRepo.getAllNonLivePojoItems(); // <= ERROR POINTS HERE
    if (pojoList != null && pojoList.size() > 0) {
        for (Pojo pojo : pojoList ){
           // Do Long Running Task Here ....
    }

Also I instantiate The Objects Being Used and call the above methods from those Objects Throughout the IntentService in OnHandleIntent like so:

@Override
protected void onHandleIntent(Intent intent) {
    if (intent != null) {
        final String action = intent.getAction();
        LocalRepo localRepo = new LocalRepo(this.getApplication());
        PojoHelper pojoHelper = new PojoHelper(this, localRepo);

        if (LOGOUT.equals(action) && type != null) {
            Log.d(TAG, "onHandleIntent: LOGOUT");
            pojoHelper.logoutPojo();
        } 
        else if(DELETE.equals(action) && type != null){
            Log.d(TAG, "onHandleIntent: DELETE_POJO");
            pojoHelper.deletePojo(true);
        }
    }
}
  • Let `getAllNonLivePojoItems` return a `LiveData`. or call it on separate thread . – ADM Feb 13 '19 at 06:25
  • @ADM I was explicit on stating that i am querying `getAllNonLivePojoItems` from a separate thread via **IntentService** – Alyosha_Karamazov Feb 13 '19 at 06:30
  • Are you calling it inside `onHandleIntent`? – Kishore Jethava Feb 13 '19 at 06:52
  • @KishoreJethava Yes, The Methods Are Called Through The PojoHelper Inside The `onHandleIntent` of the __IntentService__ – Alyosha_Karamazov Feb 13 '19 at 07:42
  • I have tested and it's working fine, can you post whole IntentService class – Kishore Jethava Feb 13 '19 at 08:44
  • @KishoreJethava SOLVED! I placed the DB Query inside an async's result method `// ERROR OCCURS HERE List pojoList = localRepo.getAllNonLivePojoItems(); // <= ERROR POINTS HERE if (pojoList != null && pojoList.size() > 0) { for (Pojo pojo : pojoList ){ // Do Long Running Task Here .... }` So I Placed The DB Query Before The async and it executed just fine – Alyosha_Karamazov Feb 13 '19 at 09:37

2 Answers2

1

I assume you get callback from AsyncTask onPostExecute() method which runs on UI thread. It is prohibited to use database or network calls inside UI thread because it can block UI.

Execute your code where you access database inside new thread.

Example:

        Executors.newSingleThreadExecutor().execute(()->{
             //TODO access Database
         });
Vygintas B
  • 1,624
  • 13
  • 31
  • Yes, sometimes these things are casually overlooked when your running on <=4 hours of sleep – Alyosha_Karamazov Feb 20 '19 at 08:57
  • @Vygintas B I have a similar use case. Do you know how I can create a singleton instance of the executor so that a new executor is not created for every CRUD operation? – AJW May 09 '19 at 01:52
  • @AJW You can make thread pool and reuse them, so they are not recreated `Executors.newFixedThreadPool(number_of_threads)` – Vygintas B May 09 '19 at 05:04
  • @Vygintas B So would that Executors method have an advantage over Executors.newSingleThreadExecutor()? – AJW May 09 '19 at 14:41
  • With `Executors.newSingleThreadExecutor()` you create new thread every time and creation is quite expensive. With `Executors.newFixedThreadPool(number_of_threads)` you get ExecutorService which you can reuse without creating new thread instances – Vygintas B May 10 '19 at 04:50
0

One thing i failed to mention was that the method was being executed within an async's response callback method

PojoWarehouse.processPojoItems(new AsyncPojoCallback() {
    @Override
    public void done(Exception e) {
        if (e == null) {
            // ERROR OCCURS HERE
            List<POJO> pojoList = localRepo.getAllNonLivePojoItems(); // <= ERROR POINTS HERE
            if (pojoList != null && pojoList.size() > 0) {
                for (Pojo pojo : pojoList ){
                // Do Long Running Task Here ....
            }
        } else
                Log.d(TAG, "done: Error Logging Out: " + e.getLocalizedMessage());
        }
    });

I cannot explain on a technical level why this fixed the issue, however suggestions are welcomed.