Tips
About 2 min
Tips 관련
Background Service Launch
class GodActivity : AppCompatActivity {
override fun onStart() {
with(ProcessLifecycleOwner.get()) {
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
startService()
}
}
}
}
priavte suspend fun startService() {
try {
exponentialRetry {
context.startService(
Intent(
context,
WebSocketService::class.java,
)
)
}
} catch (e1: CancellationException) {
// user has gone to the background before service was suceessflly started
// the scope has beeen closed along with the process hence we cannot start a background service
} catch (e2: IllegalStateException) {
log(e2)
}
}
}
- Start the service inside the process lifecycle scope — resumed or started state.
- Wrap the call itself in try-catch to convert a fatal crash into non-fatal.
- Put the call itself inside a loop or exponential retry logic.
- Make sure to handle scope cancelation exception so that no false-positive crashes are spamming your log server.
Foreground Service
class MyForeroundService: Service() {
override fun onBind(p0: Intent?): IBinder? { return null }
override fun onStartCommand(intent: Intent?, flag: Int, startId: Int): Int {
when (intent?.action) {
ACTION_START_SERVICE -> {
isRunning = true
startAsForegroundService()
}
ACTION_STOP_SERVICE -> {
isRunning = false
stopForeground(true)
stopSelf()
}
}
return START_STICKY
}
companion object {
var isRunning = false
const val ACTION_START_SERVICE = "ACTION_START_SERVICE"
const val ACTION_STOP_SERVICE = "ACTION_STOP_SERVICE"
}
private fun startAsForegroundService() {
val activityPendingIntent = Intent(this, MainActivity::class.java).let {
it.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
PendingIntent.getActivity(this, 0, it, 0)
}
val notification: Notification =
NotificatoinCompat.Builder(this, NotificationConstants.SOUND_SERVICE_CHANNEL_ID)
.setContentIntent(activityPendingIntent)
.setOngoing(true)
.setSmallIcon(R.drawable.ic_service)
.setContentTitle("Foreground Service")
.setContentText("Foreground service is running")
.build()
startForeground(1, notification)
}
}
Preferences
Preferences
app/build.gradle
dependencies {
implementation 'androidx.preference:preference:1.1.1'
}
res/xml/
preference.xml
<PreferenceScreen
xmlns:app="https://schemas.android.com/apk/res-auto">
<SwitchPreferenceCompat
app:key="notifications"
app:title="Enable message notifications">
<Preference
app:key="feedback"
app:title="Send Feedback"
app:summary="Report technical issues or suggest new features"/>
</SwitchPreferenceCompat>
</PreferenceScreen>
MySettingsFragment.kt
class MySettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
MySettingsActivity.kt
class MySettingsActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, MySettingsFragment())
.commit()
}
}
Crossfade Animation
Crossfade Animation
fun crossfade(
viewToShow: View,
viewToHide: View
) {
viewToHide.animate()
.alpha(0f)
.setDuration(500)
.setListener(object: AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
// change the visibility
viewToHide.isVisible = false
}
})
}
How to Detect Shake
How to Detect Shake
build.gradle
dependencies {
implementation "com.squareup:seismic:1.0.2"
}
MainActivity.kt
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main)
sensorManager
= getSystemService(Context.SENSOR_SERVICE) as SensorManager
shakeDetector
= ShakeDetector(ShakeDetector.Listener {
Toast.makeText(this, "Shake detected!", Toast.LENGTH_SHORT).show()
})
}
override fun onResume() {
super.onResume()
shakeDetector.start(sensorManager)
}
override fun onPause() {
super.onPause()
shakeDetector.stop()
}
}
Extension
Animate values w/ ValueAnimator
Animate values w/ `ValueAnimator`
ValueAnimator.ofInt(0, 100).apply {
duration = 3000
start()
addUpdateListener { updatedAnimation ->
textView.text = updatedAnimation.animatedView.toString()
}
}