#StackBounty: #android #kotlin #android-room #database-migration Room db migration fallbackToDestructiveMigration() not working

Bounty: 50

I am using Room with a prepopulated database in the assets folder. For an app update, I would like to alter this database by adding a new column and prepopulating this column with new data.

The database was auto-migrated from version 1 to 2 (a table was added). From version 2 to 3, I would now like to apply abovementioned changes by providing a different ‘database.db’ file in the assets folder and allowing for destructive migration.

@Database(entities = [Object1::class, Object2::class], version = 3, autoMigrations = [
    AutoMigration (from = 1, to = 2)], exportSchema = true)
abstract class AppDatabase : RoomDatabase() {

    abstract fun dao(): Dao

    companion object {

        private const val DB_NAME = "database.db"

        @Volatile
        private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(
                context,
                AppDatabase::class.java, "AppDB.db")
                .fallbackToDestructiveMigration()
                .createFromAsset(DB_NAME)
                .build()
        }
    }
}

The problem is that I still get the following exception:

   java.lang.IllegalStateException: A migration from 1 to 3 was required but not found. Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) or allow for destructive migrations via one of the RoomDatabase.Builder.fallbackToDestructiveMigration* methods.

I am unsure why this would still happen. I thought it was either providing a migration script or allowing for destructive migration that makes the migration work.

Added Comment:-

I have tried an implemented migration, but the same exception as above happened again. When I try starting over with versionCode 1, I am getting "java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you’ve changed schema but forgot to update the version number. You can simply fix this by increasing the version number." I have also changed the database name and added android:allowBackup="false" in the manifest.

Any ideas?


Get this bounty!!!

#StackBounty: #android #kotlin #android-videoview Android VideoView jumps back in time

Bounty: 50

I have implemented videoView with custom seek bar. When changing seekbar position the video is playing correctly but the time display is wrong. It happens because the videoView position goes back for some reason. It doesn not happens always but very often.

SeekBar change:

binding.progressBarVideo.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
        override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {


            if (underSeek) {
                binding.textViewTime.text = durationToFormat(binding.videoViewF.currentPosition)
                binding.videoViewF.seekTo(seekBar.progress)

                RLog.d("------------------")
                RLog.d("Seekbar progress: ${seekBar.progress}")
                RLog.d("videoView position: ${binding.videoViewF.currentPosition}")
                RLog.d("Time display string: ${durationToFormat(binding.videoViewF.currentPosition)}")
            }
        }

        override fun onStartTrackingTouch(seekBar: SeekBar?) {
            mainHandler.removeCallbacks(updateTextTask)
            underSeek = true
        }

        override fun onStopTrackingTouch(seekBar: SeekBar?) {
            mainHandler.post(updateTextTask)
            underSeek = false
            hideTimer = 0
        }

    })

updateTextTask:

private val updateTextTask = object : Runnable {
    override fun run() {

        RLog.d("----------------------------")
        RLog.d("videoView position: ${binding.videoViewF.currentPosition}")
        RLog.d("Time display string: ${durationToFormat(binding.videoViewF.currentPosition)}")

        binding.textViewTime.text = durationToFormat(binding.videoViewF.currentPosition)
        binding.progressBarVideo.progress = binding.videoViewF.currentPosition
        mainHandler.postDelayed(this, 1000)
                }
}

Duration to Format:

@SuppressLint("DefaultLocale")
private fun durationToFormat(duration: Int): String {

    return java.lang.String.format(
        "%02d:%02d",
        TimeUnit.MILLISECONDS.toMinutes(duration.toLong()),
        TimeUnit.MILLISECONDS.toSeconds(duration.toLong()) -
                TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration.toLong()))
    )
}

Logs:

#onProgressChanged: ------------------
#onProgressChanged: Seekbar progress: 257875
#onProgressChanged: videoView position: 257875
#onProgressChanged: Time display string: 04:17
#run: ----------------------------
#run: videoView position: 257875
#run: Time display string: 04:17
#run: ----------------------------
#run: videoView position: 256957
#run: Time display string: 04:16
#run: ----------------------------

At you can see, after seek the time is 257875, the first timer iteration is also 257875. Then it jumps to 256957 and I dont get why…


Get this bounty!!!

#StackBounty: #android #kotlin #bottomnavigationview #android-icons Bottom Navigation view icon change not working

Bounty: 50

I want to change to icons of the bottom navigation view as we switch items.

enter image description here

I have light blue icons and dark blue icons for selected items.
I am using selector drawable for each navigation item but I see the images like below in grey as inactive and blue as active

enter image description here

Here is my code

bottom_nav_menu

    <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/navigation_home"
        android:icon="@drawable/home_icon_selector"
        android:title="@string/title_home" />

    <item
        android:id="@+id/navigation_scheduler"
        android:icon="@drawable/schelduler_icon_selector"
        android:title="@string/title_scheduler" />

    <item
        android:id="@+id/navigation_favourites"
        android:icon="@drawable/favourites_icon_selector"
        android:title="@string/title_favourites" />


    <item
        android:id="@+id/navigation_settings"
        android:icon="@drawable/settings_icon_selector"
        android:title="@string/title_settings" />
</menu>

home

    <com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/nav_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="@dimen/margin_20"
    android:layout_marginLeft="@dimen/margin_20"
    android:layout_marginRight="@dimen/margin_20"
    android:layout_marginEnd="@dimen/margin_20"
    android:layout_marginBottom="@dimen/margin_8"
    android:background="@drawable/bottom_navigation_background"
    android:elevation="8dp"
    app:itemIconTint="@drawable/bottom_navigation_color_selector"
    app:labelVisibilityMode="unlabeled"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:menu="@menu/bottom_nav_menu" />

And selectors

scheduler selector

    <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/qa_scheduler_inactive" android:state_checked="false"/>
    <item android:drawable="@drawable/ic_scheduler_blue" android:state_checked="true"/>
</selector>

Settings selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/qa_settings_inactive" android:state_checked="false"/>
    <item android:drawable="@drawable/ic_settings_blue" android:state_checked="true"/>
</selector>

Favorites selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/qa_favorites_inactive" android:state_checked="false"/>
    <item android:drawable="@drawable/ic_favourites_blue" android:state_checked="true"/>
</selector>

Home Selector

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/qa_home_inactive" android:state_checked="false"/>
    <item android:drawable="@drawable/ic_home" android:state_checked="true"/>
</selector>

Activity code

    val navView: BottomNavigationView = findViewById(R.id.nav_view)
    val navController = findNavController(R.id.nav_host_fragment)
    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    val appBarConfiguration = AppBarConfiguration(setOf(
            R.id.navigation_home, R.id.navigation_scheduler, R.id.navigation_favourites, R.id.navigation_settings))
    //  setupActionBarWithNavController(navController, appBarConfiguration)
    navView.setupWithNavController(navController)

What am I doing wrong here? Please help…


Get this bounty!!!

#StackBounty: #java #android #android-studio #kotlin #android-mediaplayer MediaSessionCompat:Targeting S+ (version 31 and above) requir…

Bounty: 500

I’m trying to update my application to Android SDK 31 but I’m having an issue with MediaSessionCompat.

I have a MediaService that extends the MediaBrowserServiceCompat() and in method onCreate of that service I initialise the MediaSessionCompat.

override fun onCreate() {
  super.onCreate()
  mediaSession = MediaSessionCompat(this, TAG).apply {
    setCallback(mediaSessionCallback)
    isActive = true
  }
...

But I’m having the following error

java.lang.RuntimeException: Unable to create service com.radio.core.service.MediaService: java.lang.IllegalArgumentException: com.xxx.xxx: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
        at android.app.ActivityThread.handleCreateService(ActivityThread.java:4498)
        at android.app.ActivityThread.access$1500(ActivityThread.java:250)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2064)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7829)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:982)
     Caused by: java.lang.IllegalArgumentException: com.xxx.xxx: Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
    Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.
        at android.app.PendingIntent.checkFlags(PendingIntent.java:375)
        at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:645)
        at android.app.PendingIntent.getBroadcast(PendingIntent.java:632)
        at android.support.v4.media.session.MediaSessionCompat.<init>(MediaSessionCompat.java:567)
        at android.support.v4.media.session.MediaSessionCompat.<init>(MediaSessionCompat.java:537)
        at android.support.v4.media.session.MediaSessionCompat.<init>(MediaSessionCompat.java:501)
        at android.support.v4.media.session.MediaSessionCompat.<init>(MediaSessionCompat.java:475)
        at com.radio.core.service.MediaService.onCreate(MediaService.kt:63)
        at android.app.ActivityThread.handleCreateService(ActivityThread.java:4485)
            ... 9 more

I’m using the most recent version of media library ("androidx.media:media:1.4.0") that is able to handle the this requirement from the Andriod "S"". As it’s possible to see in the MediaSessionCompact.java class.


// TODO(b/182513352): Use PendingIntent.FLAG_MUTABLE instead from S.
/**
 * @hide
 */
@RestrictTo(LIBRARY)
public static final int PENDING_INTENT_FLAG_MUTABLE = 
  Build.VERSION.CODENAME.equals("S") ? 0x02000000 : 0;

...

if (mbrComponent != null && mbrIntent == null) {
  // construct a PendingIntent for the media button
  Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
  // the associated intent will be handled by the component being registered
  mediaButtonIntent.setComponent(mbrComponent);
  mbrIntent = PendingIntent.getBroadcast(context,
    0/* requestCode, ignored */, mediaButtonIntent,
    PENDING_INTENT_FLAG_MUTABLE);
}

Source code demonstrating the problem – https://github.com/adelinolobao/issue-media-session-compat

Do you guys have any idea how can I fix the error?


Get this bounty!!!

#StackBounty: #kotlin #dependency-injection #dagger-hilt What are different between "Inject dependencies into Android classes&quot…

Bounty: 200

I’m learning dependency injection by the article.

I’m very confused between "Inject dependencies into Android classes" and "Generated components for Android classes" ? What are different?

For example:

Code A has generated components for Android classes with @InstallIn(ActivityComponent::class), should Code B still add the annotation @AndroidEntryPoint?

Code A

@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .client(okHttpClient)
               .build()
               .create(AnalyticsService::class.java)
  }
}

Code B

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var mAnalyticsService: AnalyticsService
  ...
}

Added Content

If I havn’t any @Module in my project and add only such as @AndroidEntryPoint before Acitiviy, Hilt automagically creates predetermined Component for me, is it right?

If I have some @Module such as AnalyticsModule in my project and add such as @AndroidEntryPoint before Acitiviy, Hilt automagically creates predetermined Component and my dependency injection provideAnalyticsService for me, is it right?


Get this bounty!!!

#StackBounty: #kotlin #type-safety #immutability #visitor-pattern Replacing type-check with Visitor in Immutable Event-Sourced Aggregate

Bounty: 50

In my previous question, one of the answers mentioned that I shouldn’t be changing behavior based on the Event class

The whole point of classing is that you can get result without having to decide based on instance.

I don’t disagree with this sentiment, and figured it was more in the acceptable realm due to Kotlin’s documentation on the usage pattern with sealed classes.

What I’m really looking for is a way to coordinate an interaction between two different types of classes.

I haven’t used the Visitor pattern much before, but from what I’ve read this may be an okay use-case.


A Brazier is an Event-Sourced DDD Aggregate. Its state is reconstituted from Events. Extinguished Braziers can be lit, Lit Braziers can be extinguished. The Brazier encapsulates a finite-state transition, between lit, and extinguished. No change happens if we try to light a Lit Brazier, just as no change happens if we try to extinguish an Extinguished Brazier.

When a command is executed, a List of Events is returned, rather than changing the State of the Brazier. The Events are then eventually persisted in an Event Store, and during reconstitution, the new State is initialized.

There are two commands a Brazier supports, light and extinguish. There are two Events that result from these commands, Lit and Extinguished.

There are two sections of code I’m going to present.

The first demonstrates the code using a type-check with when to decide what the new State should be, based on the Event that is being processed.

The second demonstrates the code using a (possibly naive) Visitor pattern to decide what the new State should be, based on the Event that is being processed. Here, the Event is the Visitor, calling the correct method on the State, depending on the concrete type of the State.

Both implementations have nearly identical tests, with the only difference being the type of the Brazier that’s used.

The primary difference between the two is the interface of the Event hierarchy, and the afterApplying method in the State classes.

This is a pretty slimmed down example of where and how I’d like to use this; in other places where I’ve ended up in this position, the Events are much more involved, and more State types may be used (6 Events and 5 States in one case).

I don’t have any plans to allow the State or Event hierarchies to be extended outside of the core I write, so we can assume that there will be a fairly fixed number of Events and States (less than 10 undoubtedly).

BrazierWithWhen

// === Point of Interest ===
sealed class BrazierWithWhenEvent
class WhenLitEvent : BrazierWithWhenEvent()
class WhenExtinguishedEvent : BrazierWithWhenEvent()

sealed class BrazierWithWhenState {
    abstract fun light(): List<BrazierWithWhenEvent>
    abstract fun extinguish(): List<BrazierWithWhenEvent>
    abstract fun lit(event: WhenLitEvent): BrazierWithWhenState
    abstract fun extinguished(event: WhenExtinguishedEvent): BrazierWithWhenState
    abstract fun afterApplying(event: BrazierWithWhenEvent): BrazierWithWhenState
}

class WhenLitState : BrazierWithWhenState() {
    override fun light(): List<BrazierWithWhenEvent> =
        emptyList()

    override fun extinguish(): List<BrazierWithWhenEvent> =
        listOf(WhenExtinguishedEvent())

    override fun lit(event: WhenLitEvent): BrazierWithWhenState =
        this

    override fun extinguished(event: WhenExtinguishedEvent): BrazierWithWhenState =
        WhenExtinguishedState()

    // === Point of Interest ===
    override fun afterApplying(event: BrazierWithWhenEvent): BrazierWithWhenState =
        when (event) {
            is WhenLitEvent -> lit(event)
            is WhenExtinguishedEvent -> extinguished(event)
        }
}

class WhenExtinguishedState : BrazierWithWhenState() {
    override fun light(): List<BrazierWithWhenEvent> =
        listOf(WhenLitEvent())

    override fun extinguish(): List<BrazierWithWhenEvent> =
        emptyList()

    override fun lit(event: WhenLitEvent): BrazierWithWhenState =
        WhenLitState()

    override fun extinguished(event: WhenExtinguishedEvent): BrazierWithWhenState =
        this

    // === Point of Interest ===
    override fun afterApplying(event: BrazierWithWhenEvent): BrazierWithWhenState =
        when (event) {
            is WhenLitEvent -> lit(event)
            is WhenExtinguishedEvent -> extinguished(event)
        }
}

class BrazierWithWhen(
    private val state: BrazierWithWhenState
) {

    companion object {
        fun fromEvents(events: List<BrazierWithWhenEvent> = emptyList()) =
            events.fold(
                BrazierWithWhen(WhenExtinguishedState()),
                BrazierWithWhen::afterApplying)
    }

    fun light(): List<BrazierWithWhenEvent> =
        state.light()

    fun extinguish(): List<BrazierWithWhenEvent> =
        state.extinguish()

    private fun afterApplying(event: BrazierWithWhenEvent): BrazierWithWhen =
        BrazierWithWhen(state.afterApplying(event))
}

BrazierWithWhenTests

import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class BrazierWithWhenTests {

    @Test
    fun `light extinguished brazier`() {
        val brazier = BrazierWithWhen.fromEvents()
        val events = brazier.light()

        assertTrue(events.single() is WhenLitEvent)
    }

    @Test
    fun `extinguish lit brazier`() {
        val brazier = BrazierWithWhen.fromEvents(listOf(
            WhenLitEvent()
        ))
        val events = brazier.extinguish()

        assertTrue(events.single() is WhenExtinguishedEvent)
    }

    @Test
    fun `light lit brazier`() {
        val brazier = BrazierWithWhen.fromEvents(listOf(
            WhenLitEvent()
        ))
        val events = brazier.light()

        assertTrue(events.isEmpty())
    }

    @Test
    fun `extinguish extinguished brazier`() {
        val brazier = BrazierWithWhen.fromEvents()
        val events = brazier.extinguish()

        assertTrue(events.isEmpty())
    }
}

BrazierWithVisitor

// === Point of Interest ===
sealed class BrazierWithVisitorEvent {
    abstract fun visit(state: VisitorLitState): BrazierWithVisitorState
    abstract fun visit(state: VisitorExtinguishedState): BrazierWithVisitorState
}

// === Point of Interest ===
class VisitorLitEvent : BrazierWithVisitorEvent() {
    override fun visit(state: VisitorLitState): BrazierWithVisitorState =
        state.lit(this)

    override fun visit(state: VisitorExtinguishedState): BrazierWithVisitorState =
        state.lit(this)
}

// === Point of Interest ===
class VisitorExtinguishedEvent : BrazierWithVisitorEvent() {
    override fun visit(state: VisitorLitState): BrazierWithVisitorState =
        state.extinguished(this)

    override fun visit(state: VisitorExtinguishedState): BrazierWithVisitorState =
        state.extinguished(this)
}

sealed class BrazierWithVisitorState {
    abstract fun light(): List<BrazierWithVisitorEvent>
    abstract fun extinguish(): List<BrazierWithVisitorEvent>
    abstract fun lit(event: VisitorLitEvent): BrazierWithVisitorState
    abstract fun extinguished(event: VisitorExtinguishedEvent): BrazierWithVisitorState
    abstract fun afterApplying(event: BrazierWithVisitorEvent): BrazierWithVisitorState
}

class VisitorLitState : BrazierWithVisitorState() {
    override fun light(): List<BrazierWithVisitorEvent> =
        emptyList()

    override fun extinguish(): List<BrazierWithVisitorEvent> =
        listOf(VisitorExtinguishedEvent())

    override fun lit(event: VisitorLitEvent): BrazierWithVisitorState =
        this

    override fun extinguished(event: VisitorExtinguishedEvent): BrazierWithVisitorState =
        VisitorExtinguishedState()

    // === Point of Interest ===
    override fun afterApplying(event: BrazierWithVisitorEvent): BrazierWithVisitorState =
        event.visit(this)
}

class VisitorExtinguishedState : BrazierWithVisitorState() {
    override fun light(): List<BrazierWithVisitorEvent> =
        listOf(VisitorLitEvent())

    override fun extinguish(): List<BrazierWithVisitorEvent> =
        emptyList()

    override fun lit(event: VisitorLitEvent): BrazierWithVisitorState =
        VisitorLitState()

    override fun extinguished(event: VisitorExtinguishedEvent): BrazierWithVisitorState =
        this

    // === Point of Interest ===
    override fun afterApplying(event: BrazierWithVisitorEvent): BrazierWithVisitorState =
        event.visit(this)

}

class BrazierWithVisitor(
    private val state: BrazierWithVisitorState
) {
    companion object {
        fun fromEvents(events: List<BrazierWithVisitorEvent> = emptyList()): BrazierWithVisitor =
            events.fold(
                BrazierWithVisitor(VisitorExtinguishedState()),
                BrazierWithVisitor::afterApplying)
    }

    fun light(): List<BrazierWithVisitorEvent> =
        state.light()

    fun extinguish(): List<BrazierWithVisitorEvent> =
        state.extinguish()

    private fun afterApplying(event: BrazierWithVisitorEvent): BrazierWithVisitor =
        BrazierWithVisitor(state.afterApplying(event))
}

BrazierWithVisitorTests

import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class BrazierWithVisitorTests {

    @Test
    fun `light extinguished brazier`() {
        val brazier = BrazierWithVisitor.fromEvents()
        val events = brazier.light()

        assertTrue(events.single() is VisitorLitEvent)
    }

    @Test
    fun `extinguish lit brazier`() {
        val brazier = BrazierWithVisitor.fromEvents(listOf(
            VisitorLitEvent()
        ))
        val events = brazier.extinguish()

        assertTrue(events.single() is VisitorExtinguishedEvent)
    }

    @Test
    fun `light lit brazier`() {
        val brazier = BrazierWithVisitor.fromEvents(listOf(
            VisitorLitEvent()
        ))
        val events = brazier.light()

        assertTrue(events.isEmpty())
    }

    @Test
    fun `extinguish extinguished brazier`() {
        val brazier = BrazierWithVisitor.fromEvents()
        val events = brazier.extinguish()

        assertTrue(events.isEmpty())
    }
}

Both implementations perform well enough (1ms for each test), but what I’m most interested in is if this is the best way to avoid type-checks for something like this.

Writing out all of the possible combinations, there are only a couple interesting Event-State transitions (Lit -> Extinguished, Extinguished -> Lit), and some others aren’t terribly interesting (Lit -> Lit, Extinguished -> Extinguished). With a couple of commands and Events, it’s not so bad, but with 5 and 6, the interface is going to get more verbose with the Visitor pattern (1 method per command, 1 method per Event, per State), whereas we can use when+else to only describe the interesting cases, and ignore the uninteresting ones.


Get this bounty!!!

#StackBounty: #kotlin #dependency-injection #dagger-hilt What are there different when I replace object DatabaseModule with class Datab…

Bounty: 50

I’m learning dependency injection, the following Code A is from https://developer.android.com/codelabs/android-hilt#6

It seems that Code B can also work well.

What are there different when I replace object DatabaseModule with class DatabaseModule?

Code A

@Module
object DatabaseModule {

    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext appContext: Context): AppDatabase {
        return Room.databaseBuilder(
            appContext,
            AppDatabase::class.java,
            "logging.db"
        ).build()
    }

    @Provides
    fun provideLogDao(database: AppDatabase): LogDao {
        return database.logDao()
    }
}

Code B

@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {
    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext appContext: Context): AppDatabase {
        return Room.databaseBuilder(
            appContext,
            AppDatabase::class.java,
            "logging.db"
        ).build()
    }

    @Provides
    fun provideLogDao(database: AppDatabase): LogDao {
        return database.logDao()
    }
}


Get this bounty!!!

#StackBounty: #android #kotlin #android-permissions #android-architecture-components #registerforactivityresult How to Manage the permi…

Bounty: 50

How to Manage the permission request code using Navigation Component?

I referred too many website & stack links, none of it worked, still showing deprecated Waring
enter image description here

Google Ref link:
https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

Code: :Using below code in fragment

  private fun checkMultiplePermissions() {
        // check permission first
        if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // request the permission
            requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)
        } else {
            proceedAfterPermission()  // has the permission.
        }
    }
    override fun onRequestPermissionsResult(requestCode: Int,
                                            permissions: Array<String>, grantResults: IntArray) {
        myLog("log", "location code : $requestCode")
        when (requestCode) {
            100 -> {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted.
                    proceedAfterPermission() // permission was granted.
                    myLog("log", "location granted")
                } else {
                    // permission denied.
                    myLog("log", "location denied")
                }
                return
            }
        }
    }

Fragment.kt : full code

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment

class FragmentPermission : Fragment() {
    private var binding: FragmentPermisionBinding ?= null

    // Kotlin
    //implementation "androidx.fragment:fragment-ktx:1.3.4"

    //https://developer.android.com/training/permissions/requesting#manage-request-code-yourself

    //    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View {
        binding = FragmentPermisionBinding.inflate(inflater, container, false)


        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // request the permission
            requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 100)
        } else {
            //proceedAfterPermission()  // has the permission.
        }
        
        
        return binding!!.root
    }


    override fun onRequestPermissionsResult(requestCode: Int,
                                            permissions: Array<String>, grantResults: IntArray) {
        myLog("location3", "location code : $requestCode")
        when (requestCode) {
            100 -> {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted.
                    //proceedAfterPermission() // permission was granted.
                    myLog("location3", "location granted")
                } else {
                    // permission denied.
                    myLog("location3", "location denied")
                }
                return
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding=null
    }
}


Get this bounty!!!