สร้าง ViewModel ที่มีทรัพยากร Dependency (View) ส่วนหนึ่งของ Android Jetpack
แนวคิดและการใช้งาน Jetpack Compose
ViewModel สามารถใช้ทรัพยากร Dependency เป็นพารามิเตอร์ในตัวสร้างได้ตามแนวทางปฏิบัติแนะนำของการแทรก Dependency ซึ่งส่วนใหญ่จะเป็นประเภท
จากชั้นโดเมนหรือข้อมูล เนื่องจากเฟรมเวิร์กมี ViewModel จึงต้องใช้กลไกพิเศษในการสร้างอินสแตนซ์ของ ViewModel กลไกดังกล่าวคืออินเทอร์เฟซ ViewModelProvider.Factory มีเพียงการใช้งาน
ของอินเทอร์เฟซนี้เท่านั้นที่สามารถสร้างอินสแตนซ์ ViewModel ในขอบเขตที่ถูกต้องได้
ViewModel ที่มี CreationExtras
หากViewModelคลาสได้รับทรัพยากร Dependency ในตัวสร้าง ให้ระบุ Factory ที่ใช้อินเทอร์เฟซ ViewModelProvider.Factory
ลบล้างฟังก์ชัน create(Class<T>, CreationExtras) เพื่อระบุอินสแตนซ์ใหม่ของ ViewModel
CreationExtras ที่มี APPLICATION_KEY
ตัวอย่างต่อไปนี้แสดงวิธีระบุอินสแตนซ์ของ ViewModel ที่ใช้ repository ที่กำหนดขอบเขตไว้ที่คลาส Application และ SavedStateHandle เป็นทรัพยากร Dependency
import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
MyViewModel.class,
creationExtras -> {
MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
assert app != null;
SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);
return new MyViewModel(app.getMyRepository(), savedStateHandle);
}
);
}
จากนั้นคุณจะใช้ Factory นี้เมื่อเรียกข้อมูลอินสแตนซ์ของ ViewModel ได้
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
ส่งพารามิเตอร์ที่กำหนดเองเป็น CreationExtras
คุณส่งการอ้างอิงไปยัง ViewModel ผ่าน CreationExtras ได้โดยการสร้างคีย์ที่กำหนดเอง
ซึ่งจะเป็นประโยชน์หาก ViewModel ขึ้นอยู่กับออบเจ็กต์ที่เข้าถึงไม่ได้ผ่านคลาส Application และ APPLICATION_KEY ตัวอย่างของ
กรณีนี้คือเมื่อสร้าง ViewModel ภายในโมดูล Kotlin
Multiplatform และจึงไม่มีสิทธิ์เข้าถึงการอ้างอิงของ Android
ในตัวอย่างนี้ ViewModel จะกำหนดคีย์ที่กำหนดเองและใช้คีย์ดังกล่าวใน
ViewModelProvider.Factory
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
class MyViewModel(
private val myRepository: MyRepository,
) : ViewModel() {
// ViewModel logic
// Define ViewModel factory in a companion object
companion object {
// Define a custom key for your dependency
val MY_REPOSITORY_KEY = object : CreationExtras.Key<MyRepository> {}
val Factory: ViewModelProvider.Factory = viewModelFactory {
initializer {
// Get the dependency in your factory
val myRepository = this[MY_REPOSITORY_KEY] as MyRepository
MyViewModel(
myRepository = myRepository,
)
}
}
}
}
คุณสามารถสร้างอินสแตนซ์ ViewModel ด้วย CreationExtras.Key จาก
ViewModelStoreOwner เช่น
ComponentActivity, Fragment หรือ NavBackStackEntry
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
// ...
// Use from ComponentActivity, Fragment, NavBackStackEntry,
// or another ViewModelStoreOwner.
val viewModelStoreOwner: ViewModelStoreOwner = this
val myViewModel: MyViewModel = ViewModelProvider.create(
viewModelStoreOwner,
factory = MyViewModel.Factory,
extras = MutableCreationExtras().apply {
set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
},
)[MyViewModel::class]
Factory สำหรับ ViewModel เวอร์ชันเก่ากว่า 2.5.0
หากคุณใช้ ViewModel เวอร์ชันเก่ากว่า 2.5.0 คุณต้องระบุ
Factory จากชุดคลาสย่อยที่ขยาย ViewModelProvider.Factory
และใช้ฟังก์ชัน create(Class<T>) คุณต้องขยายคลาสอื่นจากคลาสต่อไปนี้ ทั้งนี้ขึ้นอยู่กับว่าViewModelต้องการทรัพยากร Dependency ใด
AndroidViewModelFactoryหากต้องการใช้คลาสApplicationAbstractSavedStateViewModelFactoryหากต้องส่งSavedStateHandleเป็นทรัพยากร Dependency
หากไม่จำเป็นต้องใช้ Application หรือ SavedStateHandle ให้ขยายจาก ViewModelProvider.Factory
ตัวอย่างต่อไปนี้ใช้ AbstractSavedStateViewModelFactory สำหรับ ViewModel ที่ใช้ที่เก็บและประเภท SavedStateHandle เป็นทรัพยากร Dependency
Kotlin
class MyViewModel(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// ViewModel logic ...
// Define ViewModel factory in a companion object
companion object {
fun provideFactory(
myRepository: MyRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null,
): AbstractSavedStateViewModelFactory =
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return MyViewModel(myRepository, handle) as T
}
}
}
}
Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
}
public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {
private final MyRepository myRepository;
public MyViewModelFactory(
MyRepository myRepository
) {
this.myRepository = myRepository;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
protected <T extends ViewModel> T create(
@NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
) {
return (T) new MyViewModel(myRepository, handle);
}
}
จากนั้นคุณจะใช้ Factory เพื่อดึงข้อมูล ViewModel ได้ดังนี้
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels {
MyViewModel.provideFactory((application as MyApplication).myRepository, this)
}
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- โมดูลสถานะที่บันทึกไว้สำหรับ ViewModel
- บันทึกสถานะ UI
- ภาพรวม LiveData