An example of Android StrictMode output (with improper database access)

I was just working with an example of how to use Android’s new Room Persistence Library, and the example I was working with ran some of its code on the main Android thread, also known as its “UI thread.” I knew this was bad, but I wanted to start with someone’s example, and then figure out a good way to get the Room method calls to run on a background thread, such as using an AsyncTask. (The Android docs don’t specify a “best practice” for this atm.)

One way to make sure you don’t accidentally run code like this on the main Android thread is to enable Android’s StrictMode. Per the StrictMode documentation, you can enable StrictMode in the onCreate method of an Activity like this:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // detects things you might be doing by accident and brings them to your attention so you can fix them
    // https://developer.android.com/reference/android/os/StrictMode.html
    StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
            .detectDiskReads()
            .detectDiskWrites()
            .detectNetwork()   // or .detectAll() for all detectable problems
            .penaltyLog()
            .build());
    StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
            .detectLeakedSqlLiteObjects()
            .detectLeakedClosableObjects()
            .penaltyLog()
            .penaltyDeath()
            .build());
...
...
...

After I enabled StrictMode in this example application and ran it again, I saw A LOT of logcat output that looks like this:

07-20 10:19:19.775 18278-18278/com.foo.roomdemo D/StrictMode: StrictMode policy violation; 
~duration=17 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=65543 violation=2
      at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1293)
      at android.database.sqlite.SQLiteConnection.applyBlockGuardPolicy(SQLiteConnection.java:1041)
      at android.database.sqlite.SQLiteConnection.executeForLong(SQLiteConnection.java:595)
      at android.database.sqlite.SQLiteConnection.setPageSize(SQLiteConnection.java:251)
      at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:213)
      at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:193)
      at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
      at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
      at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:808)
      at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:793)
      at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:696)
      at android.app.ContextImpl.openOrCreateDatabase(ContextImpl.java:652)
      at android.content.ContextWrapper.openOrCreateDatabase(ContextWrapper.java:289)
      at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:223)
      at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:163)
      at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:107)
      at android.arch.persistence.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:83)
      at android.arch.persistence.room.RoomDatabase.query(RoomDatabase.java:166)
      at com.foo.persistence.UserDao_Impl.getAll(UserDao_Impl.java:84)
      at com.foo.persistence.MainActivity.lambda$-com_nagarro_persistence_MainActivity_lambda$1(MainActivity.java:46)
      at com.foo.persistence.-$Lambda$0.$m$0(Unknown Source)
      at com.foo.persistence.-$Lambda$0.onClick(Unknown Source)
      at android.view.View.performClick(View.java:5637)
      at android.view.View$PerformClick.run(View.java:22429)
      at android.os.Handler.handleCallback(Handler.java:751)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:154)
      at android.app.ActivityThread.main(ActivityThread.java:6119)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)

That’s what StrictMode does: it shows you when you have long-running tasks such as database, network, and file I/O methods running on the main thread, which again is a no-no.

In summary, if you wanted to see how to enable StrictMode, and what the StrictMode output looks like, I hope this is helpful.