在android中替代和快速替换findViewById

时间:2017-05-25 10:36:17

标签: android android-layout

如何避免在我的应用中使用findViewById。布局非常复杂,findViewById遍历其树以查找需要时间并且多次使用的视图。

6 个答案:

答案 0 :(得分:3)

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



android {
    …
    dataBinding.enabled = true
}




接下来是通过制作外部标记而不是您使用的任何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>
&#13;
&#13;
&#13;

布局标签告诉Android Studio这个布局应该在编译期间进行额外的处理,以找到所有有趣的视图并记下它们以供下一步使用。没有外部布局标签的所有布局都不会得到额外的处理步骤,因此您可以将这些布局分散到新项目中,而无需更改应用程序的其余部分。 接下来要做的就是告诉它在运行时以不同的方式加载布局文件。因为这一直可以回溯到Eclaire版本,所以不需要依赖新的框架更改来加载这些预处理的布局文件。因此,您必须对加载过程稍作更改。 来自活动,而不是:

&#13;
&#13;
setContentView(R.layout.hello_world);
TextView hello = (TextView) findViewById(R.id.hello);
hello.setText("Hello World"); // for example, but you'd use
                              // resources, right?
You load it like this:

HelloWorldBinding binding = 
    DataBindingUtil.setContentView(this, R.layout.hello_world);
binding.hello.setText("Hello World"); // you should use resources!
&#13;
&#13;
&#13;

在这里,您可以看到为hello_world.xml布局文件生成了一个类HelloWorldBinding,并且将ID为“@ + id / hello”的视图分配给您可以使用的最终字段hello。没有强制转换,没有findViewById。 事实证明,这种访问视图的机制不仅比findViewById容易得多,而且还可以更快!绑定过程对布局中的所有视图进行单次传递,以将视图分配给字段。运行findViewById时,每次都会查看视图层次结构以查找它。 你会看到的一件事是它将你的变量名称变为casl(就像hello_world.xml成为类HelloWorldBinding一样),所以如果给它ID“@ + id / hello_text”,那么字段名称将是helloText。 当您为RecyclerView,ViewPager或其他未设置活动内容的内容扩充布局时,您将需要在生成的类上使用生成的类型安全方法。有几个版本与LayoutInflater匹配,因此请使用最适合您使用的版本。例如:

&#13;
&#13;
HelloWorldBinding binding = HelloWorldBinding.inflate(
    getLayoutInflater(), container, attachToContainer);
&#13;
&#13;
&#13;

如果未将膨胀的视图附加到包含的ViewGroup,则必须访问膨胀的View层次结构。您可以从绑定的getRoot()方法执行此操作:

&#13;
&#13;
linearLayout.addView(binding.getRoot());
&#13;
&#13;
&#13;

答案 1 :(得分:3)

另一个选择是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!")
    }
}

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

答案 2 :(得分:2)

你可以直接从xml导入视图:-

app.gradle

中添加 kotlin 扩展
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'

见下面的例子。

enter image description here

enter image description here

答案 3 :(得分:1)

您有几个选择,两个主要选项是:

Android数据绑定: https://developer.android.com/topic/libraries/data-binding/index.html

OR

Butterknife: http://jakewharton.github.io/butterknife/

就我个人而言,我是Butterknife的忠实粉丝,尽可能在任何地方使用它,值得注意的是,这只会让你的代码更好看。我发现Androids数据绑定比Butter Knifes复杂得多(虽然更多的人认为......)

据我所知,您可以使用视图绑定或findViewByID。这里明确的是他们做同样的事情。数据/视图绑定将在编译时编写findViewByID。

查看绑定只会让您的代码更易于阅读。我不知道android的任何变化,除了很快你将不再需要强制转换findViewByIDs。

答案 4 :(得分:1)

您可以使用视图绑定替换 findviewbyid。它将帮助您避免空指针异常和类型转换异常。您只需要在模块 gradle 文件中启用视图绑定。然后为绑定类创建实例。然后使用该实例来引用代码中的视图。 您将从这些链接中获得非常清晰的信息。

观看绑定视频教程:https://youtu.be/ILUf3Zf0ocI

查看绑定文档:https://developer.android.com/topic/libraries/view-binding

答案 5 :(得分:0)

  

如何避免在我的应用中使用findViewById

您可以使用getChildAt代替findViewById ViewGroup 及其衍生版本(例如 RelativeLayout LinearLayout 等)。它非常快,因为它仅尝试按其索引(link to the source code)从views数组中查找视图:

// Child views of this ViewGroup
private View[] mChildren;

// Number of valid children in the mChildren array, the rest should be null or not
// considered as children
private int mChildrenCount;

...

public View getChildAt(int index) {
    if (index < 0 || index >= mChildrenCount) {
        return null;
    }
    return mChildren[index];
}

以下是使用getChildAt的示例。假设您具有以下布局:

<RelativeLayout>
   <TextView/>
   <Button/>
   <EditText/>
</RelativeLayout>

您可以通过以下操作获得所有视图:

// assume we have inflate the layout
TextView textView = (TextView) getChildAt(0);
Button button = (Button) getChildAt(1);
EditText editText = (EditText) getChildAt(2);

但是,如果您具有如下所示的复杂布局,则开始变得乏味:

<RelativeLayout>
   <TextView/>
   <Button/>

   <LinearLayout>
       <TextView/>
       <Button/>
       <EditText/>
   </LinearLayout>

   <LinearLayout>
       <TextView/>
       <Button/>
       <EditText/>
   </LinearLayout>

</RelativeLayout>

使用getChildAt的主要问题是,如果不对代码进行更改就无法轻松更改布局位置。