【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,
         
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值