Как правильно передать идентификатор из фрагмента в viewmodel, используя Dagger2 - PullRequest
0 голосов
/ 13 января 2020

Я пытаюсь «ввести» аргумент id, который имеет тип Long, в модель представления. Фрагмент получает идентификатор из навигации. Как мне добиться этого самым элегантным способом? Чего я совсем не хочу:

viewmodel.connectionId = connectionId

Поскольку фабрика моделей представления используется для разных моделей представления, ее, скорее всего, нельзя изменить.

Вот как я реализовал Dagger2:

@Module
abstract class FragmentModule {
@ContributesAndroidInjector
abstract fun contributeSelectedLogFragment(): SelectedLogFragment
}  

@Module
abstract class ViewModelFactoryModule {
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)

@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(SelectedLogViewModel::class)
internal abstract fun bindSelectedLogViewModel(viewModel: SelectedLogViewModel): ViewModel
}

Сама фабрика модели представления:

@Singleton
class ViewModelFactory @Inject constructor(private val creators: Map<Class<out ViewModel>,   @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
    val creator = creators[modelClass] ?: creators.entries.firstOrNull {
        modelClass.isAssignableFrom(it.key)
    }?.value ?: throw IllegalArgumentException("unknown model class $modelClass")
    try {
        @Suppress("UNCHECKED_CAST")
        return creator.get() as T
    } catch (e: Exception) {
        throw RuntimeException(e)
    }
}

}

Фрагмент:

class SelectedLogFragment : Fragment() {

val connectionId = arguments?.let { SelectedLogFragmentArgs.fromBundle(it).connectionId }

@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory

@Override
override fun onAttach(context: Context) {
    super.onAttach(context)
    AndroidSupportInjection.inject(this)
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    val binding: FragmentSelectedLogBinding =
            DataBindingUtil.inflate(inflater, R.layout.fragment_selected_log, container, false)
    binding.lifecycleOwner = this
    val viewmodel = ViewModelProviders.of(this, viewModelFactory)[SelectedLogViewModel::class.java]
    binding.viewmodel = viewmodel
    return binding.root
}
}

Модель представления:

class SelectedLogViewModel @Inject constructor(private val logging: Logging, private val connectionId:Long) : ViewModelBase() {
var logEntryRecyclerViewAdapter: LogEntryRecyclerViewAdapter? = null
    private set
private val logEntries: MutableList<LogEntry> = mutableListOf()

init {
    loadLogEntries()
    logEntryRecyclerViewAdapter = LogEntryRecyclerViewAdapter(logEntries)
}

private fun loadLogEntries() {
    //TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}

}

Что я пробовал до сих пор:

@Module(includes = [FragmentModule::class])
class ConnectionIdModule {
@Provides
//fun provideConnectionId(selectedLogFragment: SelectedLogFragment):Long= selectedLogFragment.connectionId!!
fun provideConnectionId():Long= 42

}

@Component(modules = [ConnectionIdModule::class])
interface ConnectionIdComponent {
fun provideConnectionId():Long
}

..., который не работает, когда я раскомментирую строку с использование фрагмента. Я предполагаю, что может быть только небольшая недостающая часть, но я не могу понять это. Есть идеи?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...