Skip to content

Instantly share code, notes, and snippets.

@LouisCAD
Created January 23, 2017 10:08
Show Gist options
  • Save LouisCAD/8a7739b0edfae2877017086c339f560f to your computer and use it in GitHub Desktop.
Save LouisCAD/8a7739b0edfae2877017086c339f560f to your computer and use it in GitHub Desktop.
Use ContentProvider to init your application. This example sets up Timber logging and a "crash shield" that can do what you want 5 seconds after an uncaught exception.
import android.app.AlarmManager
import android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP
import android.app.PendingIntent
import android.content.Context
import android.os.SystemClock
import android.support.annotation.IntRange
import com.google.firebase.provider.FirebaseInitProvider
import org.jetbrains.anko.alarmManager
import timber.log.Timber
private var internalCtx: Context? = null
val appCtx: Context
get() = internalCtx!!
/**
* Initializes app-wide components, before [FirebaseInitProvider] initialization.
*/
class AppInitProvider : InitProvider() {
override fun onCreate() = consume {
internalCtx = context // At this point, context is an instance of your Application class on which onCreate() has not been called
setupCrashShield()
setupLogging()
}
private fun setupLogging() {
Timber.plant(if (BuildConfig.DEBUG) Timber.DebugTree() else ProductionTree())
}
private fun setupCrashShield() {
Thread.setDefaultUncaughtExceptionHandler { thread, throwable -> restartApp() }
}
/**
* Schedules an app restart with [AlarmManager] and exits the process.
* @param restartDelayInMillis Min 3s to let the user get in settings force
* close the app manually if needed.
*/
private fun restartApp(@IntRange(from = 3000) restartDelayInMillis: Long = 5000L) {
require(restartDelayInMillis >= 3000)
val restartReceiver = StartReceiver.createIntent(context)
.setAction(StartReceiver.ACTION_RESTART_AFTER_CRASH)
val restartApp = PendingIntent.getBroadcast(
context,
RESTART_APP_REQUEST,
restartReceiver,
PendingIntent.FLAG_ONE_SHOT
)
val now = SystemClock.elapsedRealtime()
// Line below schedules an app restart 5s from now.
context.alarmManager.set(ELAPSED_REALTIME_WAKEUP, now + restartDelayInMillis, restartApp)
Timber.i("just requested app restart, killing process")
System.exit(2)
}
companion object {
private const val RESTART_APP_REQUEST = 2
}
}
<manifest>
...
<application>
...
<provider
android:name=".provider.AppInitProvider"
android:authorities="${applicationId}.appinitprovider"
android:exported="false"
android:initOrder="900"/>
...
</application>
</manifest>
fun unsupported(errorMessage: String? = null): Nothing = throw UnsupportedOperationException(errorMessage)
import android.content.ContentProvider
import android.content.ContentValues
import android.net.Uri
/**
* Base class for [ContentProvider]s used for initialization purposes.
*/
abstract class InitProvider : ContentProvider() {
override final fun insert(uri: Uri?, values: ContentValues?) = unsupported()
override final fun query(uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?) = unsupported()
override final fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?) = unsupported()
override final fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String>?) = unsupported()
override final fun getType(uri: Uri?) = unsupported()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment