【Kotlin】by lazy关键字的实现原理

本文深入探讨了Kotlin中`by lazy`关键字的实现机制,通过字节码和Java代码的角度揭示其延时初始化的原理。在ViewModel和ViewBinding的例子中,`by lazy`确保了变量在首次使用时才进行初始化,避免了因依赖未准备好而导致的错误。分析了字节码后,发现`by lazy`将变量转换为`Lazy`类型,通过`Lazy`的`getValue`方法判断并执行初始化。此外,还展示了`by lazy`的Java实现,证实了字节码反编译后的等价性。

前言

kotlin的by lazy关键字是很常用的,它表示延时初始化变量,只在第一次使用时才给它初始化。那么它是如何实现这种功能的呢?这篇文章从字节码和Java语言的角度揭密它的实现原理。

ViewModel和ViewBinding变量初始化过程

先举两个项目中最常见的例子:ViewModel和ViewBinding,了解一下为什么需要延时初始化。

看一段代码:

class MainActivity : AppCompatActivity() {
   
   

    private val viewModel: MainViewModel by lazy {
   
   
        ViewModelProviders.of(this).get(MainViewModel::class.java)
    }

    private val binding: ActivityMainBinding by lazy {
   
   
        ActivityMainBinding.inflate(layoutInflater)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
   
   
        super.onCreate(savedInstanceState)
        Log.i("MainActivity", "onCreate")
     }
}

Jetpack库中的ViewModel和ViewBinding的使用是非常常见的,ViewModel和ViewBinding类型的变量都是需要延时初始化,不能在声明时初始化。ViewModel是因为内部需要依赖Activity的成员变量mApplication,而mApplication是在attach时给赋值的。ViewBinding的初始化需要依赖Window的layoutInflater变量,而Window变量也是在attach时赋值的。

先看ViewModel是如何初始化的,在以下ViewModelProviders.of方法里会调用checkApplication判断application是否为空,为空则抛出异常:

public class ViewModelProviders {
   
   

    /**
     * @deprecated This class should not be directly instantiated
     */
    @Deprecated
    public ViewModelProviders() {
   
   
    }

    private static Application checkApplication(Activity activity) {
   
   
        Application application = activity.getApplication();
        if (application == null) {
   
   
            throw new IllegalStateException("Your activity/fragment is not yet attached to "
                    + "Application. You can't request ViewModel before onCreate call.");
        }
        return application;
    }
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
   
   
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
   
   
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(fragment.getViewModelStore(), factory);
    }

mApplication是Activity的成员变量,它是在attach时赋值的:

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
         
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值