Kotlin委托了属性,这是一个非常好的功能.但有时get()
和set()
方法是不够的.假设我想Closeable
懒惰地创建一个对象并稍后关闭它.以下是如何实现此类委托属性的示例:
fun <T : Closeable> closeableLazy(initializer: () -> T) =
CloseableLazyVal(initializer)
class CloseableLazyVal<T : Closeable>(
private val initializer: () -> T
) : ReadOnlyProperty<Any?, T> {
private var value: T? = null
override fun get(thisRef: Any?, desc: PropertyMetadata): T {
if (value == null) {
value = initializer()
}
return value
}
fun close() {
value?.close()
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我想用它的方式:
private val stream by closeableLazy { FileOutputStream("/path/to/file") }
fun writeBytes(bytes: ByteArray) {
stream.write(bytes)
}
override …
Run Code Online (Sandbox Code Playgroud) 我正在努力将这个改造类翻译成 Kotlin。它基本上是一个作为客户端工作的单例,我不确定我的 Kotlin 实现。UserAPI 和 ProfileAPI 只是接口。
public class RetrofitService {
private static final String BASE_URL = "https://test.api.com/";
private ProfileAPI profileAPI;
private UserAPI userAPI;
private static RetrofitService INSTANCE;
/**
* Method that returns the instance
* @return
*/
public static RetrofitService getInstance() {
if (INSTANCE == null) {
INSTANCE = new RetrofitService();
}
return INSTANCE;
}
private RetrofitService() {
Retrofit mRetrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(BASE_URL)
.build();
profileAPI = mRetrofit.create(ProfileAPI.class);
UserAPI = mRetrofit.create(UserAPI.class);
}
/**
* Method that returns …
Run Code Online (Sandbox Code Playgroud) 该代码A是从项目play-billing-samples
,你可以看到它。
不知道为什么作者设计localCacheBillingClient
成这样lateinit
,导致代码有点复杂,if (::localCacheBillingClient.isInitialized == false) {...}
被调用了很多次。
我认为代码 B可以很好地工作,对吗?
代码 A
class BillingRepository private constructor(private val application: Application) :
PurchasesUpdatedListener, BillingClientStateListener {
lateinit private var localCacheBillingClient: LocalBillingDb
val subsSkuDetailsListLiveData: LiveData<List<AugmentedSkuDetails>> by lazy {
if (::localCacheBillingClient.isInitialized == false) {
localCacheBillingClient = LocalBillingDb.getInstance(application)
}
localCacheBillingClient.skuDetailsDao().getSubscriptionSkuDetails()
}
val inappSkuDetailsListLiveData: LiveData<List<AugmentedSkuDetails>> by lazy {
if (::localCacheBillingClient.isInitialized == false) {
localCacheBillingClient = LocalBillingDb.getInstance(application)
}
localCacheBillingClient.skuDetailsDao().getInappSkuDetails()
}
fun startDataSourceConnections() {
Log.d(LOG_TAG, "startDataSourceConnections")
instantiateAndConnectToPlayBillingService() …
Run Code Online (Sandbox Code Playgroud) 在某些情况下,不需要我的广播接收器,因此需要检查接收器是否为空,但不知何故该对象不为空,即使不使用它并导致崩溃。
Run Code Online (Sandbox Code Playgroud)private val myBroadCastReceiver by lazy { MyBroadcastReceiver() } if(myBroadCastReceiver != null) unregisterReceiver(myBroadCastReceiver)
在Java中,可以使用null初始化引用变量,例如,可以像这样初始化String变量:
String str = null;
Run Code Online (Sandbox Code Playgroud)
但在Kotlin中,重点是避免尽可能多地使用null.那么如何在不使用null的情况下初始化属性
var str: String = ...
Run Code Online (Sandbox Code Playgroud) 应该在哪些地方by lazy
使用?
为什么要使用它?
如何让代码变得更好
例如:
val currentResult: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
Run Code Online (Sandbox Code Playgroud) 这是一个简单的问题。在 Java 中,您可以在不添加任何值的情况下创建 String 变量或几个变量。这用于在 Activity 中调用 onCreate() 之前的类的开始。我已经lateinit
在 Kotlin 中使用了属性来实现这一点,但是现在我在更改 RecyclerView 的可见性方面遇到了问题。它会抛出异常"lateinit property recyclerView has not been initialized"
。
有什么方法可以知道属性是否已初始化?这在 Fragment 中的父活动开始时调用(隐藏 recyclerView 并显示 ProgressBar,直到数据绑定到 recyclerView)。