【问题标题】:How does Kotlin Android Extensions replacement for findViewById prevent null views?Kotlin Android Extensions 替换 findViewById 如何防止空视图?
【发布时间】:2019-08-19 15:58:28
【问题描述】:

我知道Kotlin的Android Extensions创建了合成属性+缓存功能来代替任何需要调用findViewById

所有这些示例都表明类似的 java 代码看起来像

private HashMap _$_findViewCache;
...
public View _$_findCachedViewById(int var1) {
   if(this._$_findViewCache == null) {
      this._$_findViewCache = new HashMap();
   }

   View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1));
   if(var2 == null) {
      var2 = this.findViewById(var1);
      this._$_findViewCache.put(Integer.valueOf(var1), var2);
   }

   return var2;
}

public void _$_clearFindViewByIdCache() {
   if(this._$_findViewCache != null) {
      this._$_findViewCache.clear();
   }
}

我不明白这如何防止潜在的 NPE? var2 = this.findViewById(var1); 仍可能返回 null。

使用最后一个链接中的示例:

<TextView
        android:id="@+id/welcomeMessage"
        ... 
        android:text="Hello World!"/>

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    welcomeMessage.text = "Hello Kotlin!"
}

welcomeMessage 是什么类型? TextViewTextView?

【问题讨论】:

    标签: android kotlin kotlin-android-extensions


    【解决方案1】:

    我不明白这如何防止潜在的 NPE?

    它没有。如果您尝试引用不存在的小部件,则会崩溃。

    只要您的 import 语句仅用于您的 Kotlin 代码的相关布局,您就不应最终引用不存在的小部件。问题出在哪里,如果您不小心从另一个布局导入了合成属性。

    例如,假设您有一个具有activity_main.xmlscrap.xml 布局的项目,并且您的活动是:

    package com.commonsware.android.myapplication
    
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import android.view.View
    import kotlinx.android.synthetic.main.scrap.*
    
    class MainActivity : AppCompatActivity() {
    
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        scrapView.visibility = View.GONE
      }
    }
    

    在这里,我们在scrap 布局中引用scrapView 视图。我们还没有夸大那个布局,所以这会导致 IllegalStateException 崩溃:

     Caused by: java.lang.IllegalStateException: scrapView must not be null
        at com.commonsware.android.myapplication.MainActivity.onCreate(MainActivity.kt:14)
    

    welcomeMessage 是什么类型的? TextView 还是 TextView?

    从技术上讲,它是TextView!,其中! 的意思是“它是一种平台类型,所以我们不知道它是否可以是null”。实际上,TextView!TextView 的使用相同,这就是为什么如果它最终成为null 会崩溃。

    【讨论】:

      【解决方案2】:

      虽然@CommonsWare 的answer 是正确的,但我也想在这个主题上节省 2 美分。

      正如@CommonsWare 所指出的,您必须导入相关布局才能使用Kotlin Extensions。这里棘手的部分是,它不仅要导入相关布局,还要在使用 Kotlin Extensions 调用之前扩展布局。

      所以,如果你有类似下面的东西

      import kotlinx.android.synthetic.main.activity_main.*
      
      class MainActivity : AppCompatActivity() {
      
        override fun onCreate(savedInstanceState: Bundle?) {
          super.onCreate(savedInstanceState)
      
          welcomeMessage.text = "Hello Kotlin!"
          setContentView(R.layout.activity_main)
      
        }
      }
      
      

      你还是会得到

      java.lang.IllegalStateException:welcomeMessage 不能为空

      你的应用会崩溃。

      【讨论】:

        【解决方案3】:

        我在监听器中也遇到了 NPE 崩溃。 我制作了 ZoomRecyclerView,它在缩放时调用 onZoom 监听器方法 onZoom。 然后将此事件传播到活动,我在其中调用合成 imagebuttonview 方法,以设置图像资源以设置缩放按钮图像(如果项目被缩放)。 它只是在合成调用时崩溃。

        例子:

        zoomRecycler.onZoom {
          // exception here : zoomButton must be not null
          zoomButton.setImageDrawable(...)
        }
        
        zoomButton.click {
          // calling zoom which raise onZoom inside zoomRecycler
          zoomRecycler.toggleZoom();
        }
        

        【讨论】:

          猜你喜欢
          • 2018-03-10
          • 2021-11-26
          • 2021-03-21
          • 2020-02-09
          • 1970-01-01
          • 2022-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多