Shu*_*ham 18 android mvvm android-databinding
我目前正在使用databinding和MVVM architectureAndroid.在ViewModel中获取字符串资源的最佳方法是什么.
我没有使用新AndroidViewModel组件,eventbus或RxJava
我正在经历接触的方式,其中Activity将负责提供资源.但最近我在这个答案中找到了一个类似的问题,其中使用应用程序上下文的单个类提供了所有资源.
哪种方法更好?或者还有其他我可以尝试的东西吗?
Age*_*t_L 29
资源字符串操作属于 View 层,而不是 ViewModel 层。
ViewModel 层应该不依赖于Context资源。定义 ViewModel 将发出的数据类型(类或枚举)。DataBinding 可以访问 Context 和资源,并可以在那里解析它。您所需要的只是一个简单的静态方法,它接受枚举和Context并返回String:
fun someEnumToString(type: MyEnum?, context: Context): String? {
return when (type) {
null -> null
MyEnum.EENY -> context.getString(R.string.some_label_eeny)
MyEnum.MEENY -> context.getString(R.string.some_label_meeny)
MyEnum.MINY -> context.getString(R.string.some_label_miny)
MyEnum.MOE -> context.getString(R.string.some_label_moe)
}
}
Run Code Online (Sandbox Code Playgroud)
(文件名为MyStaticConverter.kt,因此在 Java 和 XML 内联 Java 中,它被称为“MyStaticConverterKt”)。
XML 中的用法 -context是一个合成参数,可在每个绑定表达式中使用:
<data>
<import type="com.example.MyStaticConverterKt" />
</data>
...
<TextView
android:text="@{MyStaticConverterKt.someEnumToString(viewModel.someEnum, context)}".
Run Code Online (Sandbox Code Playgroud)
这可能看起来像“XML 中的代码太多”,但 XML 和绑定是视图层。视图逻辑的唯一位置 - 如果您拒绝上帝对象:活动和片段。
在大多数情况下,String.format将资源字符串格式与 ViewModel 发出的其他数据结合起来就足够了。对于更复杂的情况(例如将资源标签与 API 中的文本混合),请使用密封类而不是枚举,该密封类会将动态String从 ViewModel 传递到将进行组合的转换器。
对于最简单的情况,例如问题,根本不需要Context显式调用。内置适配器已经将 int 到 text 的绑定解释为字符串资源 id。微小的不便之处在于,当使用null转换器调用时仍然必须返回有效的 ID,因此您需要定义某种占位符,例如<string name="empty" translatable="false"/>.
@StringRes
fun someEnumToString(type: MyEnum?): Int {
return when (type) {
MyEnum.EENY -> R.string.some_label_eeny
MyEnum.MEENY -> R.string.some_label_meeny
MyEnum.MINY -> R.string.some_label_miny
MyEnum.MOE -> R.string.some_label_moe
null -> R.string.empty
}
}
Run Code Online (Sandbox Code Playgroud)
是的,从技术上讲,您可以直接从 ViewModel 发出 a @StringRes Int,但这会使您的 ViewModel 依赖于资源,因此我强烈建议不要这样做。
“转换器”(不相关的静态和无状态函数的集合)是我经常使用的模式。它允许使所有 AndroidView相关类型远离 ViewModel,并在整个应用程序中重用小型重复部分(例如将 bool 或各种状态转换为 VISIBILITY 或格式化数字、日期、距离、百分比等)。这消除了许多重叠的需要,@BindingAdapter恕我直言,增加了 XML 内联 Java 的可读性。
Exp*_* be 23
您可以通过实现AndroidViewModel而不是ViewModel来访问上下文.
class MainViewModel(application: Application) : AndroidViewModel(application) {
fun getSomeString(): String? {
return getApplication<Application>().resources.getString(R.string.some_string)
}
}
Run Code Online (Sandbox Code Playgroud)
Ana*_*K R 17
使用 Hilt 的 Bozbi 答案的更新版本
ViewModel.kt
@HiltViewModel
class MyViewModel @Inject constructor(
private val resourcesProvider: ResourcesProvider
) : ViewModel() {
...
fun foo() {
val helloWorld: String = resourcesProvider.getString(R.string.hello_world)
}
...
}
Run Code Online (Sandbox Code Playgroud)
资源提供者.kt
@Singleton
class ResourcesProvider @Inject constructor(
@ApplicationContext private val context: Context
) {
fun getString(@StringRes stringResId: Int): String {
return context.getString(stringResId)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 9
只需创建一个使用应用程序上下文获取资源的 ResourceProvider 类。在您的 ViewModelFactory 中,使用 App 上下文实例化资源提供者。您的 Viewmodel 是无上下文的,并且可以通过模拟 ResourceProvider 轻松进行测试。
应用
public class App extends Application {
private static Application sApplication;
@Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
public static Application getApplication() {
return sApplication;
}
Run Code Online (Sandbox Code Playgroud)
资源提供者
public class ResourcesProvider {
private Context mContext;
public ResourcesProvider(Context context){
mContext = context;
}
public String getString(){
return mContext.getString(R.string.some_string);
}
Run Code Online (Sandbox Code Playgroud)
视图模型
public class MyViewModel extends ViewModel {
private ResourcesProvider mResourcesProvider;
public MyViewModel(ResourcesProvider resourcesProvider){
mResourcesProvider = resourcesProvider;
}
public String doSomething (){
return mResourcesProvider.getString();
}
Run Code Online (Sandbox Code Playgroud)
视图模型工厂
public class ViewModelFactory implements ViewModelProvider.Factory {
private static ViewModelFactory sFactory;
private ViewModelFactory() {
}
public static ViewModelFactory getInstance() {
if (sFactory == null) {
synchronized (ViewModelFactory.class) {
if (sFactory == null) {
sFactory = new ViewModelFactory();
}
}
}
return sFactory;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(MainActivityViewModel.class)) {
return (T) new MainActivityViewModel(
new ResourcesProvider(App.getApplication())
);
}
throw new IllegalArgumentException("Unknown ViewModel class");
}
Run Code Online (Sandbox Code Playgroud)
}
您也可以使用Resource Id和ObservableInt来完成这项工作。
ViewModel:
val contentString = ObservableInt()
contentString.set(R.string.YOUR_STRING)
Run Code Online (Sandbox Code Playgroud)
然后,您的视图可以获取如下文本:
android:text="@{viewModel.contentString}"
Run Code Online (Sandbox Code Playgroud)
这样,您可以将上下文保留在ViewModel中
小智 6
您可以使用资源 ID 来完成此操作。
val messageLiveData= MutableLiveData<Any>()
messageLiveData.value = "your text ..."
Run Code Online (Sandbox Code Playgroud)
或者
messageLiveData.value = R.string.text
Run Code Online (Sandbox Code Playgroud)
然后在片段或活动中使用它,如下所示:
messageLiveData.observe(this, Observer {
when (it) {
is Int -> {
Toast.makeText(context, getString(it), Toast.LENGTH_LONG).show()
}
is String -> {
Toast.makeText(context, it, Toast.LENGTH_LONG).show()
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10844 次 |
| 最近记录: |