我正在尝试将Android应用程序从Java转换为Kotlin.应用程序中有一些单身人士.我在没有构造函数参数的情况下为单例使用了伴随对象.还有另一个单例采用构造函数参数.
Java代码:
public class TasksLocalDataSource implements TasksDataSource {
private static TasksLocalDataSource INSTANCE;
private TasksDbHelper mDbHelper;
// Prevent direct instantiation.
private TasksLocalDataSource(@NonNull Context context) {
checkNotNull(context);
mDbHelper = new TasksDbHelper(context);
}
public static TasksLocalDataSource getInstance(@NonNull Context context) {
if (INSTANCE == null) {
INSTANCE = new TasksLocalDataSource(context);
}
return INSTANCE;
}
}
Run Code Online (Sandbox Code Playgroud)
我在kotlin的解决方案:
class TasksLocalDataSource private constructor(context: Context) : TasksDataSource {
private val mDbHelper: TasksDbHelper
init {
checkNotNull(context)
mDbHelper = TasksDbHelper(context)
}
companion object {
lateinit var INSTANCE: TasksLocalDataSource
private val initialized = AtomicBoolean()
fun getInstance(context: Context) : TasksLocalDataSource {
if(initialized.getAndSet(true)) {
INSTANCE = TasksLocalDataSource(context)
}
return INSTANCE
}
}
}
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?线程安全?懒惰?
有一些类似的问题,但我不喜欢答案:)
fal*_*fal 81
这是Google的架构组件示例代码的一个简洁替代方案,它使用以下also函数:
class UsersDatabase : RoomDatabase() {
companion object {
@Volatile private var INSTANCE: UsersDatabase? = null
fun getInstance(context: Context): UsersDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(context.applicationContext,
UsersDatabase::class.java, "Sample.db")
.build()
}
}
Run Code Online (Sandbox Code Playgroud)
vod*_*dan 18
我不完全确定你为什么需要这样的代码,但这是我最好的镜头:
class TasksLocalDataSource private constructor(context: Context) : TasksDataSource {
private val mDbHelper = TasksDbHelper(context)
companion object {
private var instance : TasksLocalDataSource? = null
fun getInstance(context: Context): TasksLocalDataSource {
if (instance == null) // NOT thread safe!
instance = TasksLocalDataSource(context)
return instance!!
}
}
}
Run Code Online (Sandbox Code Playgroud)
这与您编写的内容类似,并且具有相同的API.
几点说明:
不要lateinit在这里使用.它有不同的用途,可以在这里使用可空的变量.
怎么checkNotNull(context)办?context在这里永远不会是空的,这是Kotlin的保证.所有检查和断言都已由编译器实现.
如果您只需要一个懒惰的初始化类实例TasksLocalDataSource,那么只需使用一堆惰性属性(在对象内或包级别上):
val context = ....
val dataSource by lazy {
TasksLocalDataSource(context)
}
Run Code Online (Sandbox Code Playgroud)
ami*_*phy 12
Thread-Safe Solution#Write Once; Use Many;可以创建一个实现单例逻辑的类,该类也包含单例实例。它使用同步块中的Double-Check Locking实例化实例,以消除在多线程环境中出现竞争状况的可能性。
SingletonHolder.kt
open class SingletonHolder<out T, in A>(private val constructor: (A) -> T) {
@Volatile
private var instance: T? = null
fun getInstance(arg: A): T {
return when {
instance != null -> instance!!
else -> synchronized(this) {
if (instance == null) instance = constructor(arg)
instance!!
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Usage现在在每个应该为单例的类中,在类companion object之上编写一个扩展。SingletonHolder是一个通用类,它接受目标类的类型及其要求的参数作为通用参数。它还需要引用用于实例化的目标类的构造函数:
class MyManager private constructor(context: Context) {
fun doSomething() {
...
}
companion object : SingletonHolder<MyManager, Context>(::MyManager)
}
Run Code Online (Sandbox Code Playgroud)
最后:
MyManager.getInstance(context).doSomething()
Run Code Online (Sandbox Code Playgroud)
您可以声明一个 Kotlin 对象,重载 "invoke" operator。
object TasksLocalDataSource: TasksDataSource {
private lateinit var mDbHelper: TasksDbHelper
operator fun invoke(context: Context): TasksLocalDataSource {
this.mDbHelper = TasksDbHelper(context)
return this
}
}
Run Code Online (Sandbox Code Playgroud)
无论如何,我认为您应该将 TasksDbHelper 注入 TasksLocalDataSource 而不是注入 Context
如果你想以更简单的方式将参数传递给单例,我认为这更好更短
object SingletonConfig {
private var retrofit: Retrofit? = null
private const val URL_BASE = "https://jsonplaceholder.typicode.com/"
fun Service(context: Context): Retrofit? {
if (retrofit == null) {
retrofit = Retrofit.Builder().baseUrl(URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
Run Code Online (Sandbox Code Playgroud)
}
你用这种简单的方式调用它
val api = SingletonConfig.Service(this)?.create(Api::class.java)
Run Code Online (Sandbox Code Playgroud)
该方法synchronized()在通用标准库中被标记为已弃用,因此替代方法是:
class MySingleton private constructor(private val param: String) {
companion object {
@Volatile
private var INSTANCE: MySingleton? = null
@Synchronized
fun getInstance(param: String): MySingleton = INSTANCE ?: MySingleton(param).also { INSTANCE = it }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27305 次 |
| 最近记录: |