AndroidStudio ViewBinding詳解


前言

  在Android開發,代碼里獲取View一般是使用findViewById()獲取目標布局文件里的指定View。但是這樣使用會有大量代碼重復工作並且有空指針危險。為了減少重復工作有很多大神都八仙過海各顯神通,但是這些神通多多少少都有缺點。

  • 大名鼎鼎的黃油刀bufferknife,缺點增加了編譯速度(因為原理是它需要生成一份對應查找View的代碼),並且需要時刻更新最新版本否則AndroidStudio更新后可能會出現無法編譯的問題。(另外bufferknife與ViewBinding是沖突的)
  • DataBinding,缺點更明顯,需要更多的xml編寫工作量,並且一不小心會延伸到一些邪惡的用法,那就是在xml寫邏輯判斷,甚至在xml增加一些業務功能。這對代碼維護是恐怖的,因為xml邏輯的可讀性可比純Java代碼差多了。並且如果混亂到2頭都寫邏輯判斷,維護起來十分痛苦。
  • AndroidStudio的插件功能自動生成代碼,比如LayoutCreator,減少了工作量但是並沒有減少代碼的冗余,代碼看起來一樣是不簡潔的。

google在AndroidStudio 3.6 版本后推出了ViewBinding,一方面可以讓代碼更加簡潔並且提高編譯速度防止空指針。另一方面AndroidStudio是支持ViewBinding進行關聯互動的,所以讓你在Java代碼與xml之間的跳轉更方便。

前提條件

  AndroidStudio 需要更新到3.6版本以上。

在build.gradle文件里增加下面的代碼,開啟viewBinding

 

android {
    //略...

    buildFeatures{
        viewBinding = true
    }

}

 

 

 

各處簡單的使用Demo

首先你需要知道一個關鍵點,在啟用ViewBinding后。每一個layout文件都會自動生成一份Java類。它會自動根據下划線進行駝峰命名。比如一個叫 activity_mian_demo.xml 的布局文件,它對應自動生成的類叫ActivityMianDemoBinding。這就意味着我們可以在任何需要導入布局的地方都使用ViewBinding。

Activity里:

public class MainActivity extends AppCompatActivity {
    private ActivityMianDemoBinding mBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = ActivityMianDemoBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        mBinding.btn1.setText("這是按鍵1");
        mBinding.btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

            }
        });
    }
}

Fragment里:

public class FragmentDemo extends Fragment {
    private FragmentDemoBinding mBinding;
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBinding = FragmentDemoBinding.inflate(getLayoutInflater());
        return mBinding.getRoot();
    }
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mBinding.textView.setText("textView");
    }
}

在Dialog里:

public class DemoDialog extends Dialog {
    private DialogDemoBinding mBinding;
    public DemoDialog(@NonNull Context context) {
        super(context);
        mBinding = DialogDemoBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        mBinding.textView.setText("hello");
    }
}

Adapter里:

public class DemoAdapter extends RecyclerView.Adapter<DemoAdapter.ViewHolder> {
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new ViewHolder(ItemDemoBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
    }
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.binding.textView2.setText("demo");

    }
    @Override
    public int getItemCount() {
        return 0;
    }
    public static class ViewHolder extends RecyclerView.ViewHolder {
        ItemDemoBinding binding;
        public ViewHolder(@NonNull ItemDemoBinding itemDemoBinding) {
            super(itemDemoBinding.getRoot());
            this.binding = itemDemoBinding;
        }
    }
}

xml屬性include

在之前其他人的博客里有說ViewBinding還不支持include屬性。但是在這篇博客發布的時間,最新版本AndroidStudio4.0的已經支持使用了include屬性。

使用include的布局:

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <include
        android:id="@+id/title"
        layout="@layout/title_layout"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <Button
        android:id="@+id/btn_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="A1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/title" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

activity里:

public class MainActivity extends AppCompatActivity {
    private ActivityMianDemoBinding mBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = ActivityMianDemoBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        mBinding.title.titleContent.setText("內容");
        mBinding.title.titleContent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "點擊", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

假如你有需求要分離include的布局,單獨使用這個include布局的類,可以參考如下實現:

public class MainActivity extends AppCompatActivity {
    private ActivityMianDemoBinding mBinding;
    private TitleLayoutBinding mTitleLayoutBinding;
    @Override

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBinding = ActivityMianDemoBinding.inflate(getLayoutInflater());
        setContentView(mBinding.getRoot());
        mTitleLayoutBinding = TitleLayoutBinding.bind(mBinding.getRoot());
        mTitleLayoutBinding.titleContent.setText("內容11");
    }
}

指定布局不被ViewBinding識別

  有些時候,我們希望某些布局不需要被ViewBinding識別,我只需要在這個布局的根布局上添加tools:viewBindingIgnore="true"

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:viewBindingIgnore="true">

ViewBInding泛型封裝

public class BaseActivity<T extends ViewBinding> extends AppCompatActivity {
    protected T binding;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Type superclass = getClass().getGenericSuperclass();
        Class<?> aClass = (Class<?>) ((ParameterizedType) superclass).getActualTypeArguments()[0];
        try {
            Method method = aClass.getDeclaredMethod("inflate", LayoutInflater.class);
            binding = (T) method.invoke(null, getLayoutInflater());
            setContentView(binding.getRoot());
        } catch (NoSuchMethodException | IllegalAccessException| InvocationTargetException e) {
            e.printStackTrace();
        }
    }

 

 

 

 

 

 

 

 

End


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM