1.builder设计模式简介
builder的实际应用的典型案例有AlertDialog和OKHttp
例如
// AlertDialog
AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this)
.setTitle("标题")
.setNegativeButton("取消", (dialog, which) -> {
dialog.dismiss();
Toast.makeText(MainActivity.this, "点击了取消", Toast.LENGTH_SHORT).show();
})
.setPositiveButton("确定", (dialog, which) -> Toast.makeText(MainActivity.this, "点击了确定", Toast.LENGTH_SHORT).show())
.setCancelable(false)
.setIcon(R.drawable.ic_launcher_background)
.setMessage("这是消息这是消息这是消息这是消息")
.setView(button)
.create();
alertDialog.show();
// OKhttp
private void doOKHttpGet() {
Runnable runnable = () -> {
String response = "";
try {
response = getRequest("https://raw.github.com/square/okhttp/master/README.md");
} catch (IOException e) {
Log.d(TAG, e.getMessage());
e.printStackTrace();
}
Log.d(TAG, "doOKHttpGet: " + response);
};
Thread thread = new Thread(runnable);
thread.start();
}
String getRequest(String url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return response.body().string();
}
}
建造者模式通常用于创建较复杂对象,例如上面两种情况 都是参数有很多 且有参数是可有可无的情况
之前写过一些类似的文章
下面这篇是利用builder设计模式模仿Android AlertDialog写的自己自定义的Dialog
https://blog.csdn.net/u011109881/article/details/114336196
下面这篇是利用builder设计模式 进一步写导航条
https://blog.csdn.net/u011109881/article/details/114548479
上面的两篇类结构比较简单 还有稍微复杂的建造者demo
https://blog.csdn.net/u011109881/article/details/57182402
2.导航栏升级版
利用builder设计模式写导航栏
2.1 接口类INavigation
public interface INavigation {
void createNavigationBar();
void attachNavigationParams();
//TextView findViewById(int viewId);
void attachParent(View navigationBar, ViewGroup parent);
//AbsNavigationBar.Builder getBuilder();
}
2.2 抽象类AbsNavigationBar
public abstract class AbsNavigationBar <B extends AbsNavigationBar.Builder> implements INavigation {
private final B mBuilder;
private View mNavigationBar;
protected AbsNavigationBar(B builder) {
this.mBuilder = builder;
createNavigationBar();
}
@Override
public void createNavigationBar() {
mNavigationBar = LayoutInflater.from(mBuilder.mContext)
.inflate(mBuilder.mLayoutId, mBuilder.mParent, false);// 实际上false改成true可以不用调用下面attachParent的方法
// 将布局添加到父容器
attachParent(mNavigationBar, mBuilder.mParent);
// 绑定参数到Builder内部
attachNavigationParams();
}
// 利用AbsNavigationBar引用绑定参数到AbsNavigationBar内部类Builder
@Override
public void attachNavigationParams() {
// 设置文本
Map<Integer, CharSequence> textMaps = mBuilder.mTextMaps;
for (Map.Entry<Integer, CharSequence> entry : textMaps.entrySet()) {
TextView textView = findViewById(entry.getKey());
if (textView == null) {
throw new IllegalArgumentException("TextView should not be null");
}
textView.setText(entry.getValue());
}
// 设置点击事件
Map<Integer, View.OnClickListener> clickListenerMaps = mBuilder.mClickListenerMaps;
for (Map.Entry<Integer, View.OnClickListener> entry : clickListenerMaps.entrySet()) {
View view = findViewById(entry.getKey());
if (view == null) {
throw new IllegalArgumentException("view should not be null");
}
view.setOnClickListener(entry.getValue());
}
}
@Override
public void attachParent(View navigationBar, ViewGroup parent) {
parent.addView(navigationBar, 0);
}
// 返回泛型类型 前面的T是泛型声明 后面的T是返回类型
protected <T extends View> T findViewById(int viewId) {
return mNavigationBar.findViewById(viewId);
}
protected B getBuilder() {
return mBuilder;
}
/**
* 构建类 主要任务是存储参数
*/
public static abstract class Builder<B extends Builder> {// 类泛型 里面用到泛型B 继承自当前的内部类builder
public Context mContext;
public int mLayoutId;
public ViewGroup mParent;
public Map<Integer, CharSequence> mTextMaps;
public Map<Integer, View.OnClickListener> mClickListenerMaps;
public Builder(Context context, int layoutId, ViewGroup parent) {
this.mContext = context;
this.mLayoutId = layoutId;
this.mParent = parent;
this.mTextMaps = new HashMap<>();
this.mClickListenerMaps = new HashMap<>();
}
// 创建NavigationBar
public abstract AbsNavigationBar create();
// 利用builder设置文本
public B setText(int viewId, String text) {
mTextMaps.put(viewId, text);
return (B) this;
}
// 利用builder设置点击事件
public B setOnClickListener(int viewId, View.OnClickListener clickListener) {
mClickListenerMaps.put(viewId, clickListener);
return (B) this;
}
}
}
2.3 具体实现类1 NavigationBar
public class NavigationBar extends AbsNavigationBar{
protected NavigationBar(Builder builder) {
super(builder);
}
public static class Builder extends AbsNavigationBar.Builder<NavigationBar.Builder> {// 这里的泛型覆盖父类中的泛型(父类中泛化 子类中具现) 使得setText setOnClickListener返回的B为NavigationBar.Builder
public Builder(Context context, int layoutId, ViewGroup parent) {
super(context, layoutId, parent);
}
@Override
public NavigationBar create() {
return new NavigationBar(this);
}
}
}
2.4 具体实现类2 DefaultNavigationBar
public class DefaultNavigationBar extends AbsNavigationBar<DefaultNavigationBar.Builder>{
protected DefaultNavigationBar(Builder builder) {
super(builder);
}
@Override
public void attachNavigationParams() {
super.attachNavigationParams();
TextView leftView = findViewById(R.id.back_tv);
leftView.setVisibility(getBuilder().mLeftVisible);
// 这里能够访问到mLeftVisible 因为getBuilder返回的是泛型类型
// DefaultNavigationBar extends AbsNavigationBar<DefaultNavigationBar.Builder> 具现化了B为DefaultNavigationBar.Builder
// 因此 getBuilder()返回的是DefaultNavigationBar.Builder 能够调用mLeftVisible变量
}
public static class Builder extends AbsNavigationBar.Builder<DefaultNavigationBar.Builder>{
public int mLeftVisible = View.VISIBLE;
public Builder(Context context, ViewGroup parent) {
super(context, R.layout.defualt_navigation_bar, parent);
}
public Builder setLeftText(String text){
setText(R.id.back_tv,text);
return this;
}
public Builder setLeftClickListener(View.OnClickListener clickListener){
setOnClickListener(R.id.back_tv,clickListener);
return this;
}
public Builder hideLeftText() {
mLeftVisible = View.INVISIBLE;
return this;
}
@Override
public DefaultNavigationBar create() {
return new DefaultNavigationBar(this);
}
}
}
2.5 使用到的布局
//activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/view_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"/>
</RelativeLayout>
//defualt_navigation_bar
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar 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:id="@+id/view_root"
android:background="#ccc"
android:layout_height="wrap_content">
<TextView
android:id="@+id/back_tv"
android:textColor="@android:color/white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="default bar" />
</androidx.appcompat.widget.Toolbar>
//navigationbar
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content"
android:background="@color/design_default_color_secondary"
android:paddingTop="10dp"
android:paddingBottom="10dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/left_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textColor="@color/white" />
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Hello World!"
android:textColor="@color/white" />
<ImageView
android:id="@+id/right_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentEnd="true"
android:src="@drawable/ic_launcher_background" />
</RelativeLayout>
另外注意需要将application的主题设置为android:theme="@style/Theme.Design.Light.NoActionBar"
课程里面说是导航栏的升级版,但个人感觉不出哪里升级了- -! 要说有变化的化 主要是用到了一些泛型在继承上面的一些高级用法,需要多花时间琢磨琢磨