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.