Migrate Fragment from Java to Kotlin

Use Kotlin View Binding to access view at onViewCreated callback

---- which is called immediately after onCreateView() has returned.

Otherwise crash IllegalStateException: view must not be null will be happen if we use kotlin view binding before onViewCreated.

Also, if Fragment is hosted in another fragment layout, then this fragment will be available at onViewCreated.

<TextView
    android:id="@+id/titleView"

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.detail_fragment, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // kotlin view binding allows us to assess the view by view id defined in the layout directly,
    // instead of findViewById(R.id.xxx) or ButterKnife @BindView(R.id.xxx)
    titleView.text = "title"
}

See Kotlin Android Extensions - View Binding: https://kotlinlang.org/docs/tutorials/android-plugin.html#view-binding

newInstance Pattern to create Fragment in Kotlin

Java static method in Fragment class:

    public static ArticleDetailFragment newInstance(int articleId) {
        Bundle args = new Bundle();
        args.putInt(EXTRA_ARTICLE_ID, articleId);

        ArticleDetailFragment fragment = new ArticleDetailFragment();
        fragment.setArguments(args);
        return fragment;
    }

Kotlin static method:

可以使用 Companion object:

Companion objects inside the class: a place for factory methods and static members, which can be accessed via class name.

companion object {
    val EXTRA_ARTICLE_ID = "article_id"

    fun newInstance(articleId: Int): ArticleDetailFragment {
        val args = Bundle()
        args.putInt(EXTRA_ARTICLE_ID, articleId)

        val fragment = ArticleDetailFragment()
        fragment.arguments = args
        return fragment
    }
}

也可以使用 Top level function:

In most cases, it’s recommended that you use package-level functions. Top-level functions are compiled to static methods in the byte code. Link

从 Java 自动转 Kotlin 时,转换器很喜欢把Java里的get方法转成Kotlin里的val

Java:

    private int getArticleId() {
        if (getArguments() != null) {
            return getArguments().getInt(EXTRA_ARTICLE_ID);
        }
        return -1;
    }

Kotlin有2种形式,看似一样,实则不同:

// 调用时才被执行:
val articleId: Int
    get() {
        return if (arguments != null) arguments!!.getInt(EXTRA_ARTICLE_ID) else -1
    }

// 类初始化时被执行,永远是-1:
val articleId: Int = if (arguments != null) arguments!!.getInt(EXTRA_ARTICLE_ID) else -1

但如果我们就是要通过get初始化一个值,运行时不会变化,Kotlin val显得更合适:

-    public abstract int getLayout();
+    abstract val layout: Int

-    override fun getLayout(): Int {
-        return R.layout.article_detail_fragment
-    }
+    override val layout: Int = R.layout.article_detail_fragment

2018-08-27 Weiyi Li