在android中替代和快速替换findViewById

Qas*_*ain 7 android android-layout

我如何避免findViewById在我的应用程序中使用。布局非常复杂,要findViewById遍历它的树才能找到需要时间并且多次使用的视图。

Joh*_*mon 13

首先,您必须编辑应用程序的build.gradle文件并将以下内容添加到 android 块中:

android {
    …
    dataBinding.enabled = true
}
Run Code Online (Sandbox Code Playgroud)

接下来是通过创建外部标记而不是您使用的任何 ViewGroup 来更改布局文件:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            android:paddingBottom="@dimen/activity_vertical_margin"
            tools:context=".MainActivity">

        <TextView
                android:id="@+id/hello"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

    </RelativeLayout>
</layout>
Run Code Online (Sandbox Code Playgroud)

layout 标签告诉 Android Studio 这个布局应该在编译期间进行额外的处理,以找到所有有趣的 Views 并在下一步中记录它们。所有没有外部布局标记的布局都不会得到额外的处理步骤,因此您可以将它们随意添加到新项目中,而无需更改应用程序其余部分的任何内容。

接下来你要做的是告诉它在运行时以不同的方式加载你的布局文件。因为这可以追溯到 Eclair 版本,所以不依赖于新的框架更改来加载这些预处理的布局文件。因此,您必须对加载程序稍作更改。

从一个活动,而不是:

setContentView(R.layout.hello_world);
TextView hello = (TextView) findViewById(R.id.hello);
hello.setText("Hello World"); // for example, but you'd use resources, right?
Run Code Online (Sandbox Code Playgroud)

你像这样加载它:

HelloWorldBinding binding = DataBindingUtil.setContentView(this, R.layout.hello_world);
binding.hello.setText("Hello World"); // you should use resources!
Run Code Online (Sandbox Code Playgroud)

在这里,您可以看到HelloWorldBindinghello_world.xml布局文件生成了一个类 ,并将带有 ID 的视图@+id/hello分配给hello您可以使用的最终字段。没有铸造,没有findViewById

事实证明,这种访问视图的机制不仅比 容易得多findViewById,而且还可以更快!绑定过程对布局中的所有视图进行一次传递,以将视图分配给字段。当您运行时findViewById,每次都会遍历视图层次结构以找到它。

您将看到的一件事是它将您的变量名称转换为驼峰式大小写(就像hello_world.xml变成 class 一样HelloWorldBinding),因此如果您给它 ID @+id/hello_text,那么字段名称将为helloText.

当您为RecyclerViewViewPager或其他未设置 Activity 内容的内容扩充布局时,您需要在生成的类上使用生成的类型安全方法。有多个版本与 匹配LayoutInflater,因此请使用最适合您使用的版本。例如:

HelloWorldBinding binding = HelloWorldBinding.inflate(
    getLayoutInflater(), container, attachToContainer);
Run Code Online (Sandbox Code Playgroud)

如果您没有将膨胀的 View 附加到 contains ,则ViewGroup必须访问膨胀的 View 层次结构。您可以getRoot()通过绑定方法执行此操作:

linearLayout.addView(binding.getRoot());
Run Code Online (Sandbox Code Playgroud)


Lis*_*ray 6

另一个选择是 Kotlin 的 Android 扩展。

// Using R.layout.activity_main from the main source set
import kotlinx.android.synthetic.main.activity_main.*

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

        // Instead of findView(R.id.textView) as TextView
        textView.setText("Hello, world!")
    }
}
Run Code Online (Sandbox Code Playgroud)

https://kotlinlang.org/docs/tutorials/android-plugin.html