Categories
discuss

android ViewModelFactory with hilt

I am first trying android ViewModel and Hilt DI

As i understand from below link, to initialize ViewModel with a value on run-time i should use ViewModelFactory

Use a ViewModelFactory

//ViewModel
class ScoreViewModel(finalScore: Int) : ViewModel() {
   // The final score
   var score = finalScore
   init {
       Log.i("ScoreViewModel", "Final score is $finalScore")
   }
}

//ViewModelFactory
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
   if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
       return ScoreViewModel(finalScore) as T
   }
   throw IllegalArgumentException("Unknown ViewModel class")
}


//Fragment
viewModelFactory = ScoreViewModelFactory(ScoreFragmentArgs.fromBundle(arguments!!).score)

And to use ViewModel with hilt i should use @ViewModelInject as explained in below link

Hilt and Jetpack integrations

//ViewModel
class ExampleViewModel @ViewModelInject constructor(
  private val repository: ExampleRepository,
  @Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
  ...
}

//Activity / Fragment
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
  private val exampleViewModel: ExampleViewModel by viewModels()
  ...
}

But how to use Hilt with ViewModelFactory?

It seems the answer is in the @Assisted but i can’t figure out how

How to tell hilt i like it to inject repository interfaces to ViewModel while still allowing ViewModelFactory to initialize the ViewModel with parameters on run-time?

Answer

courtesy of @Elye, next articles helped a lot. I recommend a read.

Passing Activity Intent Data to ViewModel through Injection

Injecting ViewModel with Dagger Hilt

It seems that mostly Factory is not needed since mostly viewmodel initial parameters are taken from previous fragment and can be accessed via SavedStateHandle which is automatically injected if marked as @Assisted

To set-up hilt i used the following code-labs tutorial

Using Hilt in your Android app

Then, viewModel injection is done automatically using only the next code

Note that as noted by fabioCollini here, it seems savedStateHandle can also get values from safe args by simply placing argument name as the key. In fact, that is what i did in the following example. ps: In an attempt to make the safe args be more “safe”, i did try to replace the SavedStateHandle with ItemsFragmentArgs hoping it will work but the app did not compile. I do hope it will be implemented in the future (and if already, please let me know)

//ItemFragment file
@AndroidEntryPoint
class ItemsFragment : Fragment() {

    private val viewModel: ItemsViewModel by viewModels()

    //use viewModel as you would. No need to initialize.
}

//Module file - if you have any repository, remember to bind it 
//or provide the exact implementation as noted in code-labs
@InstallIn(ApplicationComponent::class)
@Module
abstract class DatabaseModuleBinder {

    @Binds
    abstract fun bindGlistRepository(impl: FirestoreGlistRepository): GlistRepository

}


//ItemsViewModel file - lastly, anotate as follows and take your arguments 
//from savedStateHandle (for safe args, use variable name as key)
class ItemsViewModel @ViewModelInject constructor(private val glistRepo: GlistRepository,
                     @Assisted private val savedStateHandle: SavedStateHandle) : ViewModel() {

    private val glistLiveDate = glistRepo.getGlistLiveData(
        savedStateHandle.get<String>("listId")!!
    )

..
}

Hope it helps anyone and if any mistake, please let me know

Categories
discuss

How to access assets-pack data in Android (kotlin)

I packed some assets in my Android kotlin app using the asset-pack library: https://developer.android.com/guide/app-bundle/asset-delivery/build-native-java

Not I should be able to access the assets using the AssetManager via context.assets. However, I have no clue what the correct path is.

My assets pack is called models and correctly created in the root folder of the .aab file, so I guess it is also installed correctly. enter image description here

Now according to the documentation (https://developer.android.com/guide/playcore/asset-delivery/integrate-java) I can access the assets like this:

import android.content.res.AssetManager;
...
Context context = createPackageContext("com.example.app", 0);
AssetManager assetManager = context.getAssets();
InputStream is = assetManager.open("asset-name");

where I chane the package name to my package name. But what is the asset name?!? It’s not the name of the files in my models asset folder. I tried assetManager.list(p) with p as anything I could think of, but I could not find where my assets are stored.

For p='' the result of assetManager.list(p) is

 hw_pc_white_apps.xml
    hw_pc_white_apps_pad.xml
    images
    permission_grant_policy.xml
    permission_grant_policy_oversea.xml
    pfw
    sfpconfig.json
    ukeyapp.xml
    water.frag
    water.vert
    webkit
    wifi_policy.xml
    wifipro_regexlist.xml

which also makes no sense to me. How can I access assets from asset packs?

Answer

Ok, I found the solution: the Android Studio does not deliver the asset packs by default, the configuration needs to be adjusted under Run -> Edit configuration -> Deliver APK from app bundle (https://developer.android.com/guide/app-bundle/test) to deliver assets and the app.

Now the assets are accessible as if they were assets of the main app.

Categories
discuss

Android – How to compare data of a key with other keys data in firebase

enter image description here

This is just a demo data. I am using JAVA. So, I know how to fetch data from firebase but, what I want to know is how can I compare all the data of KEY i.e. user 1 with user 2 and user 3 and show it in percentage.

For example – If I compare user 1 data with user 2 data then it should show 50% similar or dissimilar. Similarly, for user1 and user3, it should show 0% similarity.

So, how can I compare and show the similar or dissimilar in percentage? Any Idea?

Answer

Try this one

    private static float checkSimilarity(String u1, String u2) {
        String s[] = u1.split(",");
        int count = 0;
        
        for(String v : s) {
            if(u2.contains(v.trim())) count++;
        }

        return ((float)count/s.length)*100; 
    }
Categories
discuss

Could not get unknown property ‘roomVersion’ for root project ‘RoomWordSample’ of type org.gradle.api.Project

I am trying to learn about Android room from https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#3

Fourth part is about updating Gradle files. It gives several code snippets to include in

build.gradle (Module: app)

I have included all the implementations, plugins etc mentioned on the page.

   apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.testing.roomwordsample"
        minSdkVersion 18
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {
        exclude 'META-INF/atomicfu.kotlin_module'
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.core:core-ktx:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'

    // Room components
    implementation "androidx.room:room-runtime:$rootProject.roomVersion"
    kapt "androidx.room:room-compiler:$rootProject.roomVersion"
    implementation "androidx.room:room-ktx:$rootProject.roomVersion"
    androidTestImplementation "androidx.room:room-testing:$rootProject.roomVersion"

// Lifecycle components
    implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.archLifecycleVersion"
    kapt "androidx.lifecycle:lifecycle-compiler:$rootProject.archLifecycleVersion"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.archLifecycleVersion"

// Kotlin components
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$rootProject.coroutines"
    api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.coroutines"

// Material design
    implementation "com.google.android.material:material:$rootProject.materialVersion"

// Testing
    testImplementation 'junit:junit:4.12'
    androidTestImplementation "androidx.arch.core:core-testing:$rootProject.coreTestingVersion"
}

ext {
    roomVersion = '2.2.5'
    archLifecycleVersion = '2.2.0'
    coreTestingVersion = '2.1.0'
    materialVersion = '1.1.0'
    coroutines = '1.3.4'
}

But build has failed and gives this error.

Could not get unknown property ‘roomVersion’ for root project ‘RoomWordSample’ of type org.gradle.api.Project.

This is what build window is showing. Error window

Answer

Step 5 of the Codelab instructions indicate you should add the ext-block containing the version strings to the Project build.gradle. You added it to the app module build.gradle.

Cut this text from the app module build.gradle and paste it into the project build.gradle:

ext {
    roomVersion = '2.2.5'
    archLifecycleVersion = '2.2.0'
    coreTestingVersion = '2.1.0'
    materialVersion = '1.1.0'
    coroutines = '1.3.4'
}
Categories
discuss

Enable landscape mode for iPad/tablet using react-native

I am working on a requirement where the mobile device would support only portrait mode while the tablet/iPad supports both portrait and landscape mode, I am not sure how to achieve the requirement using react-native

Answer

For iOS, including the following lines in the ios/Info.plist file should do it:

<key>UISupportedInterfaceOrientations</key>
<array>
    <string>UIInterfaceOrientationPortrait</string>
</array>

<key>UISupportedInterfaceOrientations~ipad</key>
<array>
    <string>UIInterfaceOrientationLandscapeRight</string>
    <string>UIInterfaceOrientationLandscapeLeft</string>
    <string>UIInterfaceOrientationPortrait</string>
    <string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..