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)。