SlideShare uma empresa Scribd logo
1 de 88
Baixar para ler offline
Epoxy 介紹
黃千碩 (Kros)
oSolve, Ltd./打⼯工趣
Mobile App Developer
Outline
• What is Epoxy
• When to use
• How to use
• Detail
• Future
• Summary
What is Epoxy
• Airbnb 開源專案
• ⽤用來來取代傳統 Adapter
• 可建立複雜的 RecyclerView Adapter
• 內建儲存 view state, ⾃自動 diff
Airbnb 的使⽤用情境
When to use
When to use
• 有三種⽅方法實作
• ScrollView
• Adapter with view type
• Epoxy Controller
ScrollView
• 需在 XML 裡⾯面設定
• Slow
• 如果要動態改變/增減欄欄位,情況複雜
• Animation 困難
Adapter with view type
@Override

public int getItemViewType(int position) {

if (0 == position) {

return TYPE_1;

} else if (1 == position) {

return TYPE_2;

} else {

return TYPE_3;

}

}
@Override

public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

switch (viewType) {

case TYPE_1:
case TYPE_2:
case TYPE_3:
}
}
Epoxy Controller
• The EpoxyController encourages usage similar to the popular
Model-View-ViewModel and Model-View-Intent patterns.
• 類似現在的 Model-View-ViewMode 改念念,把建立 RecyclerView
Items 的邏輯放在 Controller 裡⾯面
Epoxy Controller
• 所⾒見見即所得
Epoxy Controller
• 所⾒見見即所得
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
在 EpoxyController 中使⽤用的⽅方式
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());
add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new BannerItemViewModel_());
add(new AvatarItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}
加入順序 == 顯⽰示順序
Epoxy Controller
• 所⾒見見即所得
@Override

protected void buildModels() {

add(new BannerItemViewModel_());
add(new AvatarItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
add(new SettingsItemViewModel_());

add(new AdItemViewModel_());
}
新增 Item 非常容易易
How to use
• 使⽤用三步驟
• 建立 EpoxyController
• 建立 EpoxyModel
• 設定 RecyclerView 的 Adapter
How
EpoxyController
⼿手動建立
How
EpoxyControllerAdapter
⾃自動產⽣生
⼿手動建立
How
RecyclerView EpoxyControllerAdapter
⾃自動產⽣生使⽤用
⼿手動建立
EpoxyModel
EpoxyModel
EpoxyModel
EpoxyModel
View
EpoxyModel 中
指定需顯⽰示的 View
EpoxyModel
EpoxyModel
View
Data
View 可以設定
需顯⽰示的資料
EpoxyModel
EpoxyModel
View
Data Data
Data Data
可設定多個資料
EpoxyModel
EpoxyController
EpoxyModel
EpoxyControllerEpoxyModel
View
Data Data
Data Data
EpoxyModel
EpoxyController
在 EpoxyController 中
建立所需的 EpoxyModel
How
RecyclerView Adapter
⾃自動產⽣生使⽤用
⼿手動建立
EpoxyControl
Detail
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// ...

setUpController();

setUpRecyclerView();

}
Detail
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// ...

setUpController();

setUpRecyclerView();

}
Detail


private void setUpController() {
// ...

controller = new MyEpoxyController();
// ...
}
// 繼承 EpoxyController
public class MyEpoxyController extends EpoxyController {
}
Detail
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

// ...

setUpController();

setUpRecyclerView();

}
Detail


private void setUpRecyclerView() {
// ...

recyclerView.setAdapter(controller.getAdapter());
// ...

}
Detail
• 如何更更新資料?
Detail


private void updateController(Data data) {
// ...

controller.setData(data);
// ...

}
Detail
• Controller 裡⾯面要做什什麼?
• 加入 EpoxyModel
Epoxy Model
• Epoxy uses EpoxyModel objects to know which views to display
and how to bind data to them. This is similar to the popular
ViewModel pattern. You should subclass EpoxyModel to specify
what layout your model uses and how to bind data to that view.
• EpoxyModel 裡設定 View 為何,需顯⽰示的 Data 為何,有點像現在的
ViewModel 概念念
Create EpoxyModel
• 定義 Model
• 定義 View
• 定義 Property (Data)
Create EpoxyModel
• ⼿手動建立
• ⾃自動建立 (透過 Annotation)
Create EpoxyModel
• ⼿手動建立
• ⾃自動建立 (透過 Annotation)
View Annotations
• 建立 View
• 設定 Annotation
• 設定 Property (為了了 equals and hashCode)
View Annotations
• 建立 View
• 設定 Annotation
• 設定 Property (為了了 equals and hashCode)
• 就會⾃自動產⽣生 EpoxyModel 了了!
SettingsItemViewModel
@Override

protected void buildModels() {

add(new AvatarItemViewModel_());

add(new BannerItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());

add(new SettingsItemViewModel_());
}


public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}





}
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}





}
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}





}
指定 Model 要 Inflate 的 View 為何
R.layout.model_settings_item_view:
R.layout.model_settings_item_view:
<?xml version="1.0" encoding="utf-8"?>

<com.example.epoxydemo.view.SettingsItemView

xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height=“wrap_content"/>
在 model_settings_item_view 中指定要使⽤用
SettingsItemView
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}





}
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}



@ModelProp

public void setTitle(@StringRes int resId) {

titleTextView.setText(resId);

}



@ModelProp(options = Option.DoNotHash)

public void setClickListener(@Nullable OnClickListener clickListener) {

this.setOnClickListener(clickListener);

}

}
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}



@ModelProp

public void setTitle(@StringRes int resId) {

titleTextView.setText(resId);

}



@ModelProp(options = Option.DoNotHash)

public void setClickListener(@Nullable OnClickListener clickListener) {

this.setOnClickListener(clickListener);

}

}
設定 Property
讓 View 顯⽰示對應的資料
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}



@ModelProp

public void setTitle(@StringRes int resId) {

titleTextView.setText(resId);

}



@ModelProp(options = Option.DoNotHash)

public void setClickListener(@Nullable OnClickListener clickListener) {

this.setOnClickListener(clickListener);

}

}
設定 ClickListener
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}



@ModelProp

public void setTitle(@StringRes int resId) {

titleTextView.setText(resId);

}



@ModelProp(options = Option.DoNotHash)

public void setClickListener(@Nullable OnClickListener clickListener) {

this.setOnClickListener(clickListener);

}

} Interface 沒有 equal and hash
所以使⽤用 Option.DoNotHash 標記
@ModelView(defaultLayout = R.layout.model_settings_item_view)

public class SettingsItemView extends LinearLayout {

@BindView(R.id.titleTextView) TextView titleTextView;



public SettingsItemView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

init();

}



private void init() {

inflate(getContext(), R.layout.view_settings_item, this);

ButterKnife.bind(this);

}



@ModelProp

public void setTitle(@StringRes int resId) {

titleTextView.setText(resId);

}



@ModelProp(options = Option.DoNotHash)

public void setClickListener(@Nullable OnClickListener clickListener) {

this.setOnClickListener(clickListener);

}

}
Integration
• 在 EpoxyController 中設定需要哪些 EpoxyModels
• 有兩兩種⽅方式可以建立 EpoxyModel
• ⼿手動建立
• ⾃自動建立 (AutoModel Annotation)
Integration
• 在 EpoxyController 中設定需要哪些 EpoxyModels
• 有兩兩種⽅方式可以建立 EpoxyModel
• ⼿手動建立
• ⾃自動建立 (AutoModel Annotation)
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
⼿手動 new ⼀一個 EpoxyModel
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
⾃自動產⽣生的 EpoxyModel
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
透過 EpoxyController 的 method
加入到 Controller 裡
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
若若是⼿手動建立
要設定 Unique ID
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {

add(new SettingsItemViewModel_()

.id(3)

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

);

}
}
剛剛設定的 Properties
Integration
• 在 EpoxyController 中設定需要哪些 EpoxyModels
• 有兩兩種⽅方式可以建立 EpoxyModel
• ⼿手動建立
• ⾃自動建立 (AutoModel Annotation)
Using EpoxyModel
public class SimpleController extends EpoxyController {


@Override

protected void buildModels() {



}

}
Using EpoxyModel
public class SimpleController extends EpoxyController {
@AutoModel SettingsItemViewModel_ settingsItemViewModel1;


@Override

protected void buildModels() {



}

}
使⽤用 Annotation
Using EpoxyModel
public class SimpleController extends EpoxyController {
@AutoModel SettingsItemViewModel_ settingsItemViewModel1;


@Override

protected void buildModels() {

settingsItemViewModel1

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

.addTo(this);

}

}
Using EpoxyModel
public class SimpleController extends EpoxyController {
@AutoModel SettingsItemViewModel_ settingsItemViewModel1;


@Override

protected void buildModels() {

settingsItemViewModel1

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

.addTo(this);

}

}
透過 Annotation 建立的 EpoxyModel
會⾃自動設定 Unique ID
Using EpoxyModel
public class SimpleController extends EpoxyController {
@AutoModel SettingsItemViewModel_ settingsItemViewModel1;


@Override

protected void buildModels() {

settingsItemViewModel1

.title(R.string.settings_1)

.clickListener(new OnClickListener() {

@Override

public void onClick(View v) {



}

})

.addTo(this);

}

}
加入到 Controller 裡
EpoxyViewHolder
• 如果是單純重複的 list?
EpoxyViewHolder
• 如果是單純重複的 list?
• 可使⽤用 EpoxyViewHolder
public class ListController extends TypedEpoxyController<List<Comment>> {









@Override

protected void buildModels(List<Comment> data) {





}

}
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;



@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);







footerItemViewModel

.title(R.string.footer_1)

.addTo(this);

}

}
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;



@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);



for (Comment comment : data) {

new CommentItemModel_()

.id(comment.getId())

.comment(comment.getComment())

.clickListener(//...)

})

.addTo(this);

}



footerItemViewModel

.title(R.string.footer_1)

.addTo(this);

}

}
Using EpoxyHolder
@EpoxyModelClass(layout = R.layout.model_comment_item_view)

public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {

@EpoxyAttribute String comment;

@EpoxyAttribute(DoNotHash) OnClickListener clickListener;



@Override

public void bind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(clickListener);

holder.commentTextView.setText(comment);

}



@Override

public void unbind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(null);

}



public static class CommentItemHolder extends BaseEpoxyHolder {

@BindView(R.id.itemView) View itemView;

@BindView(R.id.commentTextView) TextView commentTextView;

}

}
Using EpoxyHolder
@EpoxyModelClass(layout = R.layout.model_comment_item_view)

public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {

@EpoxyAttribute String comment;

@EpoxyAttribute(DoNotHash) OnClickListener clickListener;



@Override

public void bind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(clickListener);

holder.commentTextView.setText(comment);

}



@Override

public void unbind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(null);

}



public static class CommentItemHolder extends BaseEpoxyHolder {

@BindView(R.id.itemView) View itemView;

@BindView(R.id.commentTextView) TextView commentTextView;

}

}
繼承 EpoxyModelWithHolder
繼承 BaseEpoxyHolder
https://github.com/airbnb/epoxy/wiki/Epoxy-Models#view-holders
Using EpoxyHolder
@EpoxyModelClass(layout = R.layout.model_comment_item_view)

public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {

@EpoxyAttribute String comment;

@EpoxyAttribute(DoNotHash) OnClickListener clickListener;



@Override

public void bind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(clickListener);

holder.commentTextView.setText(comment);

}



@Override

public void unbind(CommentItemHolder holder) {

holder.itemView.setOnClickListener(null);

}



public static class CommentItemHolder extends BaseEpoxyHolder {

@BindView(R.id.itemView) View itemView;

@BindView(R.id.commentTextView) TextView commentTextView;

}

}
類似 ViewHolder 的 lifecycle
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;



@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);



for (Comment comment : data) {

new CommentItemModel_()

.id(comment.getId())

.comment(comment.getComment())

.clickListener(//...)

})

.addTo(this);

}



footerItemViewModel

.title(R.string.footer_1)

.addTo(this);

}

}
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;


@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);



for (Comment comment : data) {

new CommentItemModel_()

.id(comment.getId())

.comment(comment.getComment())

.clickListener(//...)

})

.addTo(this);

}



loadMoreViewModel

.addTo(true, this);

}

}
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;


@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);



for (Comment comment : data) {

new CommentItemModel_()

.id(comment.getId())

.comment(comment.getComment())

.clickListener(//...)

})

.addTo(this);

}



loadMoreViewModel

.addTo(true, this);

}

}
Add with condition,
可以設定條件(true/false)
決定是否要加入到 Controller
public class ListController extends TypedEpoxyController<List<Comment>> {



@AutoModel HeaderItemViewModel_ headerItemViewModel;

@AutoModel FooterItemViewModel_ footerItemViewModel;


@Override

protected void buildModels(List<Comment> data) {



headerItemViewModel

.title(R.string.header_1)

.addTo(this);



for (Comment comment : data) {

new CommentItemModel_()

.id(comment.getId())

.comment(comment.getComment())

.clickListener(//...)

})

.addTo(this);

}



loadMoreViewModel

.addTo(false, this);

}

}
Other Features
• EpoxyModelGroup
• Saving View state
• Payloads
• Data binding layouts
• Litho Components
• Kotlin Support
• Grid Suport
Future
• Sticky Header, Footer, Decoration
Summary
• 若若 RecyclerView 有兩兩種以上的 view type,可以考慮⽤用 Epoxy
• 想要動態增減 RecyclerView 內容,可以考慮⽤用 Epoxy
• ScrollView 太長,可以考慮⽤用 Epoxy
• 需要 Header, Footer,可以考慮⽤用 Epoxy
• 不想⾃自⼰己實作 diff, save state,可以考慮⽤用 Epoxy
Demo Project
• https://github.com/ch8908/EpoxyDemo
Reference
• Epoxy: Airbnb’s View Architecture on Android

https://medium.com/airbnb-engineering/epoxy-airbnbs-view-
architecture-on-android-c3e1af150394
• Epoxy Github Wiki

https://github.com/airbnb/epoxy/wiki

Mais conteúdo relacionado

Mais procurados

Mais procurados (20)

Flutter beyond hello world
Flutter beyond hello worldFlutter beyond hello world
Flutter beyond hello world
 
Yocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution MakerYocto - Embedded Linux Distribution Maker
Yocto - Embedded Linux Distribution Maker
 
Installing and running Postfix within a docker container from the command line
Installing and running Postfix within a docker container from the command lineInstalling and running Postfix within a docker container from the command line
Installing and running Postfix within a docker container from the command line
 
Google flutter and why does it matter
Google flutter and why does it matterGoogle flutter and why does it matter
Google flutter and why does it matter
 
QNX Software Systems
QNX Software SystemsQNX Software Systems
QNX Software Systems
 
Docker, LinuX Container
Docker, LinuX ContainerDocker, LinuX Container
Docker, LinuX Container
 
Understaing Android EGL
Understaing Android EGLUnderstaing Android EGL
Understaing Android EGL
 
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
IMPLEMENTING VOICE CONTROL WITH THE ANDROID MEDIA SESSION API ON AMAZON FIRE ...
 
Android Binder IPC for Linux
Android Binder IPC for LinuxAndroid Binder IPC for Linux
Android Binder IPC for Linux
 
Arm device tree and linux device drivers
Arm device tree and linux device driversArm device tree and linux device drivers
Arm device tree and linux device drivers
 
Hardware Probing in the Linux Kernel
Hardware Probing in the Linux KernelHardware Probing in the Linux Kernel
Hardware Probing in the Linux Kernel
 
Introduction to Qt Creator
Introduction to Qt CreatorIntroduction to Qt Creator
Introduction to Qt Creator
 
Learning AOSP - Android Booting Process
Learning AOSP - Android Booting ProcessLearning AOSP - Android Booting Process
Learning AOSP - Android Booting Process
 
Linux Networking Explained
Linux Networking ExplainedLinux Networking Explained
Linux Networking Explained
 
Getting Started - Ansible Galaxy NG
Getting Started - Ansible Galaxy NGGetting Started - Ansible Galaxy NG
Getting Started - Ansible Galaxy NG
 
Flutter Festivals GDSC ASEB | Introduction to Dart
Flutter Festivals GDSC ASEB | Introduction to DartFlutter Festivals GDSC ASEB | Introduction to Dart
Flutter Festivals GDSC ASEB | Introduction to Dart
 
Project meeting: Android Graphics Architecture Overview
Project meeting: Android Graphics Architecture OverviewProject meeting: Android Graphics Architecture Overview
Project meeting: Android Graphics Architecture Overview
 
Android Booting Sequence
Android Booting SequenceAndroid Booting Sequence
Android Booting Sequence
 
Quickboot on i.MX6
Quickboot on i.MX6Quickboot on i.MX6
Quickboot on i.MX6
 
Podman, Buildah, and Quarkus - The Latest in Linux Containers Technologies
Podman, Buildah, and Quarkus - The Latest in Linux Containers Technologies Podman, Buildah, and Quarkus - The Latest in Linux Containers Technologies
Podman, Buildah, and Quarkus - The Latest in Linux Containers Technologies
 

Semelhante a Epoxy 介紹

[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
洪 鹏发
 
Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5
Tuna Tore
 
springmvc-150923124312-lva1-app6892
springmvc-150923124312-lva1-app6892springmvc-150923124312-lva1-app6892
springmvc-150923124312-lva1-app6892
Tuna Tore
 

Semelhante a Epoxy 介紹 (20)

Advanced #6 clean architecture
Advanced #6  clean architectureAdvanced #6  clean architecture
Advanced #6 clean architecture
 
Patterns Are Good For Managers
Patterns Are Good For ManagersPatterns Are Good For Managers
Patterns Are Good For Managers
 
Arquitecturas de microservicios - Medianet Software
Arquitecturas de microservicios   -  Medianet SoftwareArquitecturas de microservicios   -  Medianet Software
Arquitecturas de microservicios - Medianet Software
 
React Native & NativeScript
React Native & NativeScriptReact Native & NativeScript
React Native & NativeScript
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
 
Simple React Todo List
Simple React Todo ListSimple React Todo List
Simple React Todo List
 
[Final] ReactJS presentation
[Final] ReactJS presentation[Final] ReactJS presentation
[Final] ReactJS presentation
 
Rules SDK IBM WW BPM Forum March 2013
Rules SDK IBM WW BPM Forum March 2013Rules SDK IBM WW BPM Forum March 2013
Rules SDK IBM WW BPM Forum March 2013
 
MVC 1.0 als alternative Webtechnologie
MVC 1.0 als alternative WebtechnologieMVC 1.0 als alternative Webtechnologie
MVC 1.0 als alternative Webtechnologie
 
Modern android development
Modern android developmentModern android development
Modern android development
 
A Minimalist’s Attempt at Building a Distributed Application
A Minimalist’s Attempt at Building a Distributed ApplicationA Minimalist’s Attempt at Building a Distributed Application
A Minimalist’s Attempt at Building a Distributed Application
 
2-0. Spring ecosytem.pdf
2-0. Spring ecosytem.pdf2-0. Spring ecosytem.pdf
2-0. Spring ecosytem.pdf
 
Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5Java Spring MVC Framework with AngularJS by Google and HTML5
Java Spring MVC Framework with AngularJS by Google and HTML5
 
springmvc-150923124312-lva1-app6892
springmvc-150923124312-lva1-app6892springmvc-150923124312-lva1-app6892
springmvc-150923124312-lva1-app6892
 
Effective Java. By materials of Josch Bloch's book
Effective Java. By materials of Josch Bloch's bookEffective Java. By materials of Josch Bloch's book
Effective Java. By materials of Josch Bloch's book
 
Angular.js Primer in Aalto University
Angular.js Primer in Aalto UniversityAngular.js Primer in Aalto University
Angular.js Primer in Aalto University
 
React & Redux for noobs
React & Redux for noobsReact & Redux for noobs
React & Redux for noobs
 
Say bye to Fragments with Conductor & Kotlin
Say bye to Fragments with Conductor & KotlinSay bye to Fragments with Conductor & Kotlin
Say bye to Fragments with Conductor & Kotlin
 
Jetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO ExtendedJetpack, with new features in 2021 GDG Georgetown IO Extended
Jetpack, with new features in 2021 GDG Georgetown IO Extended
 
Android development
Android developmentAndroid development
Android development
 

Mais de Kros Huang (6)

Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹Kotlin Receiver Types 介紹
Kotlin Receiver Types 介紹
 
Kotlin Data Model
Kotlin Data ModelKotlin Data Model
Kotlin Data Model
 
Fastlane on Android 介紹
Fastlane on Android 介紹Fastlane on Android 介紹
Fastlane on Android 介紹
 
RxJava 2.0 介紹
RxJava 2.0 介紹RxJava 2.0 介紹
RxJava 2.0 介紹
 
Rxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJavaRxjava 介紹與 Android 中的 RxJava
Rxjava 介紹與 Android 中的 RxJava
 
Android with dagger_2
Android with dagger_2Android with dagger_2
Android with dagger_2
 

Último

"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
mphochane1998
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
Epec Engineered Technologies
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
jaanualu31
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Kandungan 087776558899
 
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
Health
 

Último (20)

HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKARHAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
HAND TOOLS USED AT ELECTRONICS WORK PRESENTED BY KOUSTAV SARKAR
 
Block diagram reduction techniques in control systems.ppt
Block diagram reduction techniques in control systems.pptBlock diagram reduction techniques in control systems.ppt
Block diagram reduction techniques in control systems.ppt
 
Unleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leapUnleashing the Power of the SORA AI lastest leap
Unleashing the Power of the SORA AI lastest leap
 
Design For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the startDesign For Accessibility: Getting it right from the start
Design For Accessibility: Getting it right from the start
 
Computer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to ComputersComputer Lecture 01.pptxIntroduction to Computers
Computer Lecture 01.pptxIntroduction to Computers
 
AIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech studentsAIRCANVAS[1].pdf mini project for btech students
AIRCANVAS[1].pdf mini project for btech students
 
Online electricity billing project report..pdf
Online electricity billing project report..pdfOnline electricity billing project report..pdf
Online electricity billing project report..pdf
 
data_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdfdata_management_and _data_science_cheat_sheet.pdf
data_management_and _data_science_cheat_sheet.pdf
 
Hostel management system project report..pdf
Hostel management system project report..pdfHostel management system project report..pdf
Hostel management system project report..pdf
 
Learn the concepts of Thermodynamics on Magic Marks
Learn the concepts of Thermodynamics on Magic MarksLearn the concepts of Thermodynamics on Magic Marks
Learn the concepts of Thermodynamics on Magic Marks
 
Online food ordering system project report.pdf
Online food ordering system project report.pdfOnline food ordering system project report.pdf
Online food ordering system project report.pdf
 
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments""Lesotho Leaps Forward: A Chronicle of Transformative Developments"
"Lesotho Leaps Forward: A Chronicle of Transformative Developments"
 
Standard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power PlayStandard vs Custom Battery Packs - Decoding the Power Play
Standard vs Custom Battery Packs - Decoding the Power Play
 
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills KuwaitKuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
Kuwait City MTP kit ((+919101817206)) Buy Abortion Pills Kuwait
 
DC MACHINE-Motoring and generation, Armature circuit equation
DC MACHINE-Motoring and generation, Armature circuit equationDC MACHINE-Motoring and generation, Armature circuit equation
DC MACHINE-Motoring and generation, Armature circuit equation
 
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptxS1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
S1S2 B.Arch MGU - HOA1&2 Module 3 -Temple Architecture of Kerala.pptx
 
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak HamilCara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
Cara Menggugurkan Sperma Yang Masuk Rahim Biyar Tidak Hamil
 
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
+97470301568>> buy weed in qatar,buy thc oil qatar,buy weed and vape oil in d...
 
kiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal loadkiln thermal load.pptx kiln tgermal load
kiln thermal load.pptx kiln tgermal load
 
Computer Networks Basics of Network Devices
Computer Networks  Basics of Network DevicesComputer Networks  Basics of Network Devices
Computer Networks Basics of Network Devices
 

Epoxy 介紹

  • 1. Epoxy 介紹 黃千碩 (Kros) oSolve, Ltd./打⼯工趣 Mobile App Developer
  • 2. Outline • What is Epoxy • When to use • How to use • Detail • Future • Summary
  • 3. What is Epoxy • Airbnb 開源專案 • ⽤用來來取代傳統 Adapter • 可建立複雜的 RecyclerView Adapter • 內建儲存 view state, ⾃自動 diff
  • 6. When to use • 有三種⽅方法實作 • ScrollView • Adapter with view type • Epoxy Controller
  • 7. ScrollView • 需在 XML 裡⾯面設定 • Slow • 如果要動態改變/增減欄欄位,情況複雜 • Animation 困難
  • 8. Adapter with view type @Override
 public int getItemViewType(int position) {
 if (0 == position) {
 return TYPE_1;
 } else if (1 == position) {
 return TYPE_2;
 } else {
 return TYPE_3;
 }
 } @Override
 public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
 switch (viewType) {
 case TYPE_1: case TYPE_2: case TYPE_3: } }
  • 9. Epoxy Controller • The EpoxyController encourages usage similar to the popular Model-View-ViewModel and Model-View-Intent patterns. • 類似現在的 Model-View-ViewMode 改念念,把建立 RecyclerView Items 的邏輯放在 Controller 裡⾯面
  • 12. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); } 在 EpoxyController 中使⽤用的⽅方式
  • 13. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 14. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_()); add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 15. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 16. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 17. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 18. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new BannerItemViewModel_()); add(new AvatarItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); } 加入順序 == 顯⽰示順序
  • 19. Epoxy Controller • 所⾒見見即所得 @Override
 protected void buildModels() {
 add(new BannerItemViewModel_()); add(new AvatarItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); add(new SettingsItemViewModel_());
 add(new AdItemViewModel_()); } 新增 Item 非常容易易
  • 20. How to use • 使⽤用三步驟 • 建立 EpoxyController • 建立 EpoxyModel • 設定 RecyclerView 的 Adapter
  • 32. Detail @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 // ...
 setUpController();
 setUpRecyclerView();
 }
  • 33. Detail @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 // ...
 setUpController();
 setUpRecyclerView();
 }
  • 34. Detail 
 private void setUpController() { // ...
 controller = new MyEpoxyController(); // ... } // 繼承 EpoxyController public class MyEpoxyController extends EpoxyController { }
  • 35. Detail @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 // ...
 setUpController();
 setUpRecyclerView();
 }
  • 36. Detail 
 private void setUpRecyclerView() { // ...
 recyclerView.setAdapter(controller.getAdapter()); // ...
 }
  • 38. Detail 
 private void updateController(Data data) { // ...
 controller.setData(data); // ...
 }
  • 40. Epoxy Model • Epoxy uses EpoxyModel objects to know which views to display and how to bind data to them. This is similar to the popular ViewModel pattern. You should subclass EpoxyModel to specify what layout your model uses and how to bind data to that view. • EpoxyModel 裡設定 View 為何,需顯⽰示的 Data 為何,有點像現在的 ViewModel 概念念
  • 41. Create EpoxyModel • 定義 Model • 定義 View • 定義 Property (Data)
  • 42. Create EpoxyModel • ⼿手動建立 • ⾃自動建立 (透過 Annotation)
  • 43. Create EpoxyModel • ⼿手動建立 • ⾃自動建立 (透過 Annotation)
  • 44. View Annotations • 建立 View • 設定 Annotation • 設定 Property (為了了 equals and hashCode)
  • 45. View Annotations • 建立 View • 設定 Annotation • 設定 Property (為了了 equals and hashCode) • 就會⾃自動產⽣生 EpoxyModel 了了!
  • 46. SettingsItemViewModel @Override
 protected void buildModels() {
 add(new AvatarItemViewModel_());
 add(new BannerItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_());
 add(new SettingsItemViewModel_()); }
  • 47. 
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 
 }
  • 48. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 
 }
  • 49. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 
 } 指定 Model 要 Inflate 的 View 為何
  • 52. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 
 }
  • 53. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 @ModelProp
 public void setTitle(@StringRes int resId) {
 titleTextView.setText(resId);
 }
 
 @ModelProp(options = Option.DoNotHash)
 public void setClickListener(@Nullable OnClickListener clickListener) {
 this.setOnClickListener(clickListener);
 }
 }
  • 54. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 @ModelProp
 public void setTitle(@StringRes int resId) {
 titleTextView.setText(resId);
 }
 
 @ModelProp(options = Option.DoNotHash)
 public void setClickListener(@Nullable OnClickListener clickListener) {
 this.setOnClickListener(clickListener);
 }
 } 設定 Property 讓 View 顯⽰示對應的資料
  • 55. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 @ModelProp
 public void setTitle(@StringRes int resId) {
 titleTextView.setText(resId);
 }
 
 @ModelProp(options = Option.DoNotHash)
 public void setClickListener(@Nullable OnClickListener clickListener) {
 this.setOnClickListener(clickListener);
 }
 } 設定 ClickListener
  • 56. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 @ModelProp
 public void setTitle(@StringRes int resId) {
 titleTextView.setText(resId);
 }
 
 @ModelProp(options = Option.DoNotHash)
 public void setClickListener(@Nullable OnClickListener clickListener) {
 this.setOnClickListener(clickListener);
 }
 } Interface 沒有 equal and hash 所以使⽤用 Option.DoNotHash 標記
  • 57. @ModelView(defaultLayout = R.layout.model_settings_item_view)
 public class SettingsItemView extends LinearLayout {
 @BindView(R.id.titleTextView) TextView titleTextView;
 
 public SettingsItemView(Context context, @Nullable AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 private void init() {
 inflate(getContext(), R.layout.view_settings_item, this);
 ButterKnife.bind(this);
 }
 
 @ModelProp
 public void setTitle(@StringRes int resId) {
 titleTextView.setText(resId);
 }
 
 @ModelProp(options = Option.DoNotHash)
 public void setClickListener(@Nullable OnClickListener clickListener) {
 this.setOnClickListener(clickListener);
 }
 }
  • 58. Integration • 在 EpoxyController 中設定需要哪些 EpoxyModels • 有兩兩種⽅方式可以建立 EpoxyModel • ⼿手動建立 • ⾃自動建立 (AutoModel Annotation)
  • 59. Integration • 在 EpoxyController 中設定需要哪些 EpoxyModels • 有兩兩種⽅方式可以建立 EpoxyModel • ⼿手動建立 • ⾃自動建立 (AutoModel Annotation)
  • 60. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } }
  • 61. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } } ⼿手動 new ⼀一個 EpoxyModel
  • 62. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } } ⾃自動產⽣生的 EpoxyModel
  • 63. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } } 透過 EpoxyController 的 method 加入到 Controller 裡
  • 64. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } } 若若是⼿手動建立 要設定 Unique ID
  • 65. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 add(new SettingsItemViewModel_()
 .id(3)
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 );
 } } 剛剛設定的 Properties
  • 66. Integration • 在 EpoxyController 中設定需要哪些 EpoxyModels • 有兩兩種⽅方式可以建立 EpoxyModel • ⼿手動建立 • ⾃自動建立 (AutoModel Annotation)
  • 67. Using EpoxyModel public class SimpleController extends EpoxyController { 
 @Override
 protected void buildModels() {
 
 }
 }
  • 68. Using EpoxyModel public class SimpleController extends EpoxyController { @AutoModel SettingsItemViewModel_ settingsItemViewModel1; 
 @Override
 protected void buildModels() {
 
 }
 } 使⽤用 Annotation
  • 69. Using EpoxyModel public class SimpleController extends EpoxyController { @AutoModel SettingsItemViewModel_ settingsItemViewModel1; 
 @Override
 protected void buildModels() {
 settingsItemViewModel1
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 .addTo(this);
 }
 }
  • 70. Using EpoxyModel public class SimpleController extends EpoxyController { @AutoModel SettingsItemViewModel_ settingsItemViewModel1; 
 @Override
 protected void buildModels() {
 settingsItemViewModel1
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 .addTo(this);
 }
 } 透過 Annotation 建立的 EpoxyModel 會⾃自動設定 Unique ID
  • 71. Using EpoxyModel public class SimpleController extends EpoxyController { @AutoModel SettingsItemViewModel_ settingsItemViewModel1; 
 @Override
 protected void buildModels() {
 settingsItemViewModel1
 .title(R.string.settings_1)
 .clickListener(new OnClickListener() {
 @Override
 public void onClick(View v) {
 
 }
 })
 .addTo(this);
 }
 } 加入到 Controller 裡
  • 74. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 
 
 
 @Override
 protected void buildModels(List<Comment> data) {
 
 
 }
 }
  • 75. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel;
 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 
 
 footerItemViewModel
 .title(R.string.footer_1)
 .addTo(this);
 }
 }
  • 76. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel;
 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 for (Comment comment : data) {
 new CommentItemModel_()
 .id(comment.getId())
 .comment(comment.getComment())
 .clickListener(//...)
 })
 .addTo(this);
 }
 
 footerItemViewModel
 .title(R.string.footer_1)
 .addTo(this);
 }
 }
  • 77. Using EpoxyHolder @EpoxyModelClass(layout = R.layout.model_comment_item_view)
 public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {
 @EpoxyAttribute String comment;
 @EpoxyAttribute(DoNotHash) OnClickListener clickListener;
 
 @Override
 public void bind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(clickListener);
 holder.commentTextView.setText(comment);
 }
 
 @Override
 public void unbind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(null);
 }
 
 public static class CommentItemHolder extends BaseEpoxyHolder {
 @BindView(R.id.itemView) View itemView;
 @BindView(R.id.commentTextView) TextView commentTextView;
 }
 }
  • 78. Using EpoxyHolder @EpoxyModelClass(layout = R.layout.model_comment_item_view)
 public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {
 @EpoxyAttribute String comment;
 @EpoxyAttribute(DoNotHash) OnClickListener clickListener;
 
 @Override
 public void bind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(clickListener);
 holder.commentTextView.setText(comment);
 }
 
 @Override
 public void unbind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(null);
 }
 
 public static class CommentItemHolder extends BaseEpoxyHolder {
 @BindView(R.id.itemView) View itemView;
 @BindView(R.id.commentTextView) TextView commentTextView;
 }
 } 繼承 EpoxyModelWithHolder 繼承 BaseEpoxyHolder https://github.com/airbnb/epoxy/wiki/Epoxy-Models#view-holders
  • 79. Using EpoxyHolder @EpoxyModelClass(layout = R.layout.model_comment_item_view)
 public abstract class CommentItemModel extends EpoxyModelWithHolder<CommentItemHolder> {
 @EpoxyAttribute String comment;
 @EpoxyAttribute(DoNotHash) OnClickListener clickListener;
 
 @Override
 public void bind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(clickListener);
 holder.commentTextView.setText(comment);
 }
 
 @Override
 public void unbind(CommentItemHolder holder) {
 holder.itemView.setOnClickListener(null);
 }
 
 public static class CommentItemHolder extends BaseEpoxyHolder {
 @BindView(R.id.itemView) View itemView;
 @BindView(R.id.commentTextView) TextView commentTextView;
 }
 } 類似 ViewHolder 的 lifecycle
  • 80. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel;
 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 for (Comment comment : data) {
 new CommentItemModel_()
 .id(comment.getId())
 .comment(comment.getComment())
 .clickListener(//...)
 })
 .addTo(this);
 }
 
 footerItemViewModel
 .title(R.string.footer_1)
 .addTo(this);
 }
 }
  • 81. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel; 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 for (Comment comment : data) {
 new CommentItemModel_()
 .id(comment.getId())
 .comment(comment.getComment())
 .clickListener(//...)
 })
 .addTo(this);
 }
 
 loadMoreViewModel
 .addTo(true, this);
 }
 }
  • 82. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel; 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 for (Comment comment : data) {
 new CommentItemModel_()
 .id(comment.getId())
 .comment(comment.getComment())
 .clickListener(//...)
 })
 .addTo(this);
 }
 
 loadMoreViewModel
 .addTo(true, this);
 }
 } Add with condition, 可以設定條件(true/false) 決定是否要加入到 Controller
  • 83. public class ListController extends TypedEpoxyController<List<Comment>> {
 
 @AutoModel HeaderItemViewModel_ headerItemViewModel;
 @AutoModel FooterItemViewModel_ footerItemViewModel; 
 @Override
 protected void buildModels(List<Comment> data) {
 
 headerItemViewModel
 .title(R.string.header_1)
 .addTo(this);
 
 for (Comment comment : data) {
 new CommentItemModel_()
 .id(comment.getId())
 .comment(comment.getComment())
 .clickListener(//...)
 })
 .addTo(this);
 }
 
 loadMoreViewModel
 .addTo(false, this);
 }
 }
  • 84. Other Features • EpoxyModelGroup • Saving View state • Payloads • Data binding layouts • Litho Components • Kotlin Support • Grid Suport
  • 85. Future • Sticky Header, Footer, Decoration
  • 86. Summary • 若若 RecyclerView 有兩兩種以上的 view type,可以考慮⽤用 Epoxy • 想要動態增減 RecyclerView 內容,可以考慮⽤用 Epoxy • ScrollView 太長,可以考慮⽤用 Epoxy • 需要 Header, Footer,可以考慮⽤用 Epoxy • 不想⾃自⼰己實作 diff, save state,可以考慮⽤用 Epoxy
  • 88. Reference • Epoxy: Airbnb’s View Architecture on Android
 https://medium.com/airbnb-engineering/epoxy-airbnbs-view- architecture-on-android-c3e1af150394 • Epoxy Github Wiki
 https://github.com/airbnb/epoxy/wiki