【问题标题】:How to avoid these tedious findViewById() calls?如何避免这些乏味的 findViewById() 调用?
【发布时间】:2020-08-25 19:05:08
【问题描述】:

我有一个带有两个 TextView 的简单布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_tile_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sample text"
        android:textSize="18dp"
        android:layout_gravity="center_horizontal"/>

    <TextView
        android:id="@+id/tv_tile_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:text="20.0"
        android:textSize="26dp"
        android:textStyle="bold" />
</LinearLayout>

我在我的应用程序的某些地方包含此布局。在我的最后一个案例中,我必须包含 4 次。要在单个包含的布局中为这两个文本视图查找和设置文本,我必须找到一个布局的 id,然后从那里找到两个文本视图的 id。并对所有包含的布局重复 3 次。这会导致一些丑陋和可怕的代码维护:

@Override
public void setStatsValues(String today, String week, String month, String total) {
    // this is so tedious.
    View layoutDay = findViewById(R.id.layout_stats_day);
    View layoutWeek = findViewById(R.id.layout_stats_week);
    View layoutMonth = findViewById(R.id.layout_stats_month);
    View layoutTotal = findViewById(R.id.layout_stats_total);
    TextView tvDayTitle = layoutDay.findViewById(R.id.tv_tile_title);
    TextView tvWeekTitle = layoutWeek.findViewById(R.id.tv_tile_title);
    TextView tvMonthTitle = layoutMonth.findViewById(R.id.tv_tile_title);
    TextView tvTotalTitle = layoutTotal.findViewById(R.id.tv_tile_title);
    TextView tvDayValue = layoutDay.findViewById(R.id.tv_tile_value);
    TextView tvWeekValue = layoutWeek.findViewById(R.id.tv_tile_value);
    TextView tvMonthValue = layoutMonth.findViewById(R.id.tv_tile_value);
    TextView tvTotalValue = layoutTotal.findViewById(R.id.tv_tile_value);
    tvDayTitle.setText("Today");
    tvWeekTitle.setText("Week");
    tvMonthTitle.setText("Month");
    tvTotalTitle.setText("Total");
    tvDayValue.setText(today);
    tvWeekValue.setText(week);
    tvMonthValue.setText(month);
    tvTotalValue.setText(total);
}

我怎样才能避免这种怪物?

【问题讨论】:

  • 解决办法是viewBinding
  • viewBinding 并非在每个 IDE 中都可用,所以这是个坏主意

标签: android findviewbyid android-viewbinding


【解决方案1】:

您可以使用View Binding:

在你的 build.gradle 中添加:

android {
    ...
    buildFeatures {
        viewBinding true
    }
}

创建布局activity_test.xml

<androidx.constraintlayout.widget.ConstraintLayout>

    <TextView
        android:id="@+id/text1"/>

    <TextView
        android:id="@+id/text2"/>

</androidx.constraintlayout.widget.ConstraintLayout>

然后在你的Activity:

科特林

private lateinit var binding: ActivityTestBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    binding = ActivityTestBinding.inflate(layoutInflater)
    val view = binding.root
    setContentView(view)

    binding.text1.text = "Hello"
    binding.text2.text = "....."

}

Java

private ActivityTestBinding binding;

@Override
public void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    binding = ActivityTestBinding.inflate(getLayoutInflater());
    View view = binding.getRoot();
    setContentView(view);

    binding.text1.setText("hello");

}

【讨论】:

  • 我在你的 kotlin 答案中添加了一个 java 版本,因为 OP 的问题是用 Java 提出的,不过我同意你的回答 :)
  • @a_local_nobody 感谢您的反馈。我没注意到。
【解决方案2】:

您可以使用View Binding 自动执行所有findViewById 的工作 - 它会生成一个以您的布局命名的“绑定”类,并且布局中每个带有idView 都会获得一个引用。

所以在你的情况下,你就可以做到dayBinding.tv_tile_value.setText("today")

如果你不想这样做,你可以将所有重复的代码重构为一个函数,比如

private void setTheThings(int layoutResId, String title, String value) {
    View layout = findViewById(layoutResId)
    layout.findViewById<TextView>(R.id.tv_tile_title).setText(title)
    layout.findViewById<TextView>(R.id.tv_tile_value).setText(value)
}

(或要转换为 TextView 的任何内容),然后为每个布局 ID 调用它

【讨论】:

  • 你提出了一个夜间点 bruh,这样也更容易。我同意
【解决方案3】:

实际上,您正在使自己的代码变得乏味。无需先找到父节点再访问子节点,以此类推。

代替:

    View layoutDay = findViewById(R.id.layout_stats_day);
    View layoutWeek = findViewById(R.id.layout_stats_week);
    View layoutMonth = findViewById(R.id.layout_stats_month);
    View layoutTotal = findViewById(R.id.layout_stats_total);
    TextView tvDayTitle = layoutDay.findViewById(R.id.tv_tile_title);
    TextView tvWeekTitle = layoutWeek.findViewById(R.id.tv_tile_title);
    TextView tvMonthTitle = layoutMonth.findViewById(R.id.tv_tile_title);
    TextView tvTotalTitle = layoutTotal.findViewById(R.id.tv_tile_title);
    TextView tvDayValue = layoutDay.findViewById(R.id.tv_tile_value);
    TextView tvWeekValue = layoutWeek.findViewById(R.id.tv_tile_value);
    TextView tvMonthValue = layoutMonth.findViewById(R.id.tv_tile_value);
    TextView tvTotalValue = layoutTotal.findViewById(R.id.tv_tile_value);

你可以这样做(只是不同的 id,我的意思是为每个视图使用不同的 id):

    TextView tvDayTitle = findViewById(R.id.tv_day_title);
    TextView tvWeekTitle = findViewById(R.id.tv_week_title);
    TextView tvMonthTitle = findViewById(R.id.tv_month_title);
    TextView tvTotalTitle = findViewById(R.id.tv_total_title);
    

【讨论】:

  • 您提出了一个有效的观点,尽管您示例中的最后一行并不完全有效,似乎复制不正确
猜你喜欢
  • 1970-01-01
  • 2019-05-03
  • 2013-02-03
  • 1970-01-01
  • 2017-01-07
  • 1970-01-01
  • 2016-07-07
  • 1970-01-01
  • 2011-03-26
相关资源
最近更新 更多