Skip to content

Commit

Permalink
Merge pull request #67 from AlanCheen/feature/1.5.2
Browse files Browse the repository at this point in the history
Feature/1.5.2
  • Loading branch information
AlanCheen authored May 6, 2020
2 parents 5711d73 + a5ccfc1 commit c1c6444
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
2. 新增 IComponentModel(Differ)
1. 尝试 Kotlin 化
2. 迁移 androidx
3. FlapRecyclerView 完善

### 1.5.1

Expand Down
1 change: 1 addition & 0 deletions PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
What's the PR for?
这个 PR 的目的是什么?
26 changes: 4 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ recyclerView.setAdapter(adapter);



`FlapComponent` 的属性与方法
`FlapComponent` 的更多属性与方法,具体请以实际代码为准

```java
protected final Context context;
Expand All @@ -170,57 +170,38 @@ protected final <V extends View> V findViewById(@IdRes int viewId)



#### 感知生命周期

#### FlapComponent 感知生命周期


在一些业务场景下我们需要在 `ViewHolder` 中需要感知生命周期,在 `FlapComponent` 你可以重写`onResume``onPause``onStop``onDestroy` 方法,得到回调,**让你轻松面对类似 暂停/重播视频 这种依赖于生命周期的需求**



如果觉得不够,你也加更多的方法。



`FlapAdapter` 会帮你自动绑定 `LifecycleOwner` ,生命周期问题从此不再出现。

相关的方法:

1. `FlapAdapter.setLifecycleEnable(boolean lifecycleEnable) ` 默认开启
2. `FlapAdapter.setLifecycleOwner(@NonNull final LifecycleOwner lifecycleOwner)`



### AsyncListDiffer 完全支持



`AsyncListDiffer` 能够非常高效的刷新数据的能力, `Flap` 内部提供一个 `DifferFlapAdapter` ,支持了 `AsyncListDiffer` ,你只需要继承 `DifferFlapAdapter` 就可以同时享受 `Flap`` AsyncListDiffer` 带来的强大的能力。



## Flap 的优点



可以说 `Flap` 的每一行代码都是我经过我深思熟虑而写下的,它拥有**精心设计的架构**,它遵守 SOLID 设计原则,与设计模式完美融合,做到**高内聚低耦合,易扩展易维护**;并且**最大程度上帮助开发者避免编写样板代码**,让开发者关注绑定逻辑即可;同时提供了**非常多的实用特性**,难能可贵的是它还做到了**简单易用、无门槛**;我相信你一定能够做到「一分钟入门」,并且我也相信 `Flap` 一定会是你的得力助手。



1. `Flap` 优化了 `FlapComponent``ItemViewType` 的绑定逻辑,**默认使用 ViewHolder 的 布局Id(也即 layoutId)作为它的 ItemViewType**,并做自动关联,你再也不需要自定义多余且烦人的常量!!;
2. **使用工厂模式为 FlapComponent 的创建提供支持**:而且,你可以**** `new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.xxx, parent, false)));` **这种没营养但是又烦人的样板代码说再见!**
3. **优化 FlapComponent 的创建过程**:FlapComponent 的创建过程不像传统的 ViewHolder 那样混乱,真正做到了「开闭原则」,让你**不再迷失于混乱的 if else 、switch 堆中**,轻松面对各种加类型的需求;
4. **绑定 ViewHolder 的最佳实践**:遵从**关注点分离****完全解耦 FlapComponent 的创建以及绑定过程**,你不需要关注 FlapComponent 是怎么创建的,而只需要关注 `onBind()` 方法来处理你的数据绑定逻辑即可;



## 变更日志



版本变更详情请看: [CHANGELOG](./CHANGELOG.md)


## FAQ

#### 1. 如何设置 FlapComponent 的点击事件?
Expand All @@ -236,7 +217,6 @@ protected final <V extends View> V findViewById(@IdRes int viewId)
答:没有,Flap 的目标不在此,可以自行扩展。



## 谁在使用 Flap ?

如果你在你的 App 使用了 Flap 开发,请一定要联系我,将会在这里展示哟。
Expand All @@ -253,6 +233,8 @@ protected final <V extends View> V findViewById(@IdRes int viewId)
- [x] 支持组件全局缓存;
- [x] 支持组件监听生命周期事件,Lifecycle 接入;
- [x] 支持 AsyncListDiffer;
- [x] 优化布局实例化样板代码;
- [x] 支持组件与 layoutId 绑定;


## 贡献
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ private void initFlap() {

Log.e("Flap", "Init Flap time cost :" + (t2 - t1));

Flap.getDefault().registerFlowListener(new ComponentMonitor());

// Flap.getDefault().getFlapItemPool().setMaxRecycledViews(new SimpleImageItem.Factory().getItemViewType(null), 8);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import android.view.View;
import android.view.ViewGroup;

import org.jetbrains.annotations.NotNull;

import me.yifeiyuan.flap.FlapComponent;
import me.yifeiyuan.flap.internal.ComponentProxy;
import me.yifeiyuan.flapdev.R;
Expand Down Expand Up @@ -38,6 +40,7 @@ public int getItemViewType(final CustomModel model) {
return CUSTOM_ITEM_VIEW_TYPE;
}

@NotNull
@Override
public Class<CustomModel> getComponentModelClass() {
return CustomModel.class;
Expand Down
2 changes: 1 addition & 1 deletion flap/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies {

apply plugin: "guru.stefma.bintrayrelease"

version = "1.5.1"
version = "1.5.2"
group = "me.yifeiyuan.flap"
androidArtifact {
artifactId = "flap"
Expand Down
36 changes: 22 additions & 14 deletions flap/src/main/java/me/yifeiyuan/flap/Flap.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@

import me.yifeiyuan.flap.exceptions.ComponentProxyNotFoundException;
import me.yifeiyuan.flap.extensions.ComponentFlowListener;
import me.yifeiyuan.flap.extensions.ComponentPerformanceMonitor;
import me.yifeiyuan.flap.extensions.ComponentPool;
import me.yifeiyuan.flap.internal.ComponentProxy;
import me.yifeiyuan.flap.internal.DefaultComponent;
import me.yifeiyuan.flap.internal.DefaultComponent.Proxy;

/**
* Flap Github: <a>https://github.com/AlanCheen/Flap</a>
Expand All @@ -32,14 +33,20 @@ public final class Flap implements IFlap {
private static final String TAG = "Flap";

static final int DEFAULT_ITEM_TYPE_COUNT = 32;
/**
* Model class 与 ComponentProxy 的映射关系
*/
private final Map<Class<?>, ComponentProxy<?, ?>> componentProxyMap;
/**
* itemViewType 与 ComponentProxy 的映射关系
*/
private final SparseArray<ComponentProxy<?, ?>> viewTypeProxyMapping;

private final Map<Class<?>, ComponentProxy<?, ?>> itemFactories;
private final SparseArray<ComponentProxy<?, ?>> factoryMapping;
private final List<ComponentFlowListener> flowListeners = Collections.synchronizedList(new ArrayList<ComponentFlowListener>());

private static final ComponentPool GLOBAL_POOL = new ComponentPool();

private static final DefaultComponent.Factory DEFAULT_FACTORY = new DefaultComponent.Factory();
private static final ComponentProxy DEFAULT_FACTORY = new Proxy();

private static volatile Flap sInstance;

Expand All @@ -59,12 +66,13 @@ private Flap() {
}

private Flap(int typeCount) {
itemFactories = new HashMap<>(typeCount);
factoryMapping = new SparseArray<>(typeCount);
componentProxyMap = new HashMap<>(typeCount);
viewTypeProxyMapping = new SparseArray<>(typeCount);
registerFlowListener(new ComponentPerformanceMonitor());
injectFactories(this);
}

private void injectFactories(final Flap flap) {
private void injectFactories(@NonNull final Flap flap) {
try {
Class<?> flapItemFactoryManager = Class.forName("me.yifeiyuan.flap.apt.manager.ComponentAutoRegister");
Method method = flapItemFactoryManager.getMethod("inject", Flap.class);
Expand All @@ -83,31 +91,31 @@ private void injectFactories(final Flap flap) {

@Override
public ComponentRegistry register(@NonNull final ComponentProxy itemFactory) {
itemFactories.put(itemFactory.getComponentModelClass(), itemFactory);
componentProxyMap.put(itemFactory.getComponentModelClass(), itemFactory);
return this;
}

@Override
public ComponentRegistry unregister(@NonNull final ComponentProxy itemFactory) {
itemFactories.remove(itemFactory.getComponentModelClass());
componentProxyMap.remove(itemFactory.getComponentModelClass());
return this;
}

@Override
public ComponentRegistry clearAll() {
itemFactories.clear();
factoryMapping.clear();
componentProxyMap.clear();
viewTypeProxyMapping.clear();
return this;
}

@Override
public int getItemViewType(@NonNull final Object model) {
Class<?> modelClazz = model.getClass();

ComponentProxy factory = itemFactories.get(modelClazz);
ComponentProxy factory = componentProxyMap.get(modelClazz);
if (null != factory) {
int itemViewType = factory.getItemViewType(model);
factoryMapping.put(itemViewType, factory);
viewTypeProxyMapping.put(itemViewType, factory);
return itemViewType;
} else {
FlapDebug.throwIfDebugging(new ComponentProxyNotFoundException("Can't find the ComponentProxy for : " + modelClazz + " , please register first!"));
Expand All @@ -119,7 +127,7 @@ public int getItemViewType(@NonNull final Object model) {
@Override
public FlapComponent onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent, final int viewType) {
FlapComponent vh = null;
ComponentProxy<?, ?> factory = factoryMapping.get(viewType);
ComponentProxy<?, ?> factory = viewTypeProxyMapping.get(viewType);
dispatchBeforeCreateComponentEvent(factory, viewType);
if (factory != null) {
try {
Expand Down
1 change: 1 addition & 0 deletions flap/src/main/java/me/yifeiyuan/flap/FlapDebug.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ static void throwIfDebugging(Exception e) {
Log.e(TAG, "FlapDebug : ", e);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
package me.yifeiyuan.flapdev;
package me.yifeiyuan.flap.extensions;

import android.os.SystemClock;
import android.util.Log;

import me.yifeiyuan.flap.FlapComponent;
import me.yifeiyuan.flap.extensions.ComponentFlowListener;
import me.yifeiyuan.flap.internal.ComponentProxy;

/**
* 组件性能监控
*
* Flap Github: <a>https://github.com/AlanCheen/Flap</a>
*
* @author 程序亦非猿 [Follow me](<a> https://github.com/AlanCheen</a>)
* @since 2020/3/24 11:14 PM
* @since 1.1
* @since 1.5.2
*/
public class ComponentMonitor implements ComponentFlowListener {
public class ComponentPerformanceMonitor implements ComponentFlowListener {

private static final String TAG = "ComponentMonitor";
private static final String TAG = "PerformanceMonitor";

private long createTime;
private long bindTime;
Expand All @@ -30,6 +32,9 @@ public void onStartCreateComponent(final ComponentProxy factory) {
public void onComponentCreated(final ComponentProxy factory, final FlapComponent component) {
long timeCost = SystemClock.uptimeMillis() - createTime;
Log.d(TAG, "组件 " + component.getClass().getSimpleName() + " 创建完毕,耗时 " + timeCost + " 毫秒");
if (timeCost > getCreateCostThreshold()) {
Log.w(TAG, "请注意:" + component.getClass().getSimpleName() + " 组件创建超过阈值,请优化!!! ");
}
}

@Override
Expand All @@ -40,6 +45,30 @@ public void onStartBindComponent(final FlapComponent component, final int positi

@Override
public void onComponentBound(final FlapComponent component, final int position, final Object model) {
Log.d(TAG, "组件绑定完毕,耗时 " + (SystemClock.uptimeMillis() - bindTime) + " 毫秒");
long timeCost = SystemClock.uptimeMillis() - bindTime;
Log.d(TAG, "组件绑定完毕,耗时 " + timeCost + " 毫秒");
if (timeCost > getBindCostThreshold()) {
Log.w(TAG, "请注意:" + component.getClass().getSimpleName() + " 组件绑定超时,请优化! ");
}
}

/**
* 创建组件的耗时阈值,超过阈值会有警告。
* 默认 20 毫秒
*
* @return 毫秒
*/
protected long getCreateCostThreshold() {
return 20;
}

/**
* 绑定组件的耗时阈值,超过阈值会有警告。
* 默认 5 毫秒
*
* @return 毫秒
*/
protected long getBindCostThreshold() {
return 5;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@

import me.yifeiyuan.flap.FlapAdapter;
/**
* 封装了 Flap 的 RecyclerView,未测试,暂时请不要使用。
* todo
*
* Flap Github: <a>https://github.com/AlanCheen/Flap</a>
*
* @author 程序亦非猿 [Follow me](<a> https://github.com/AlanCheen</a>)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package me.yifeiyuan.flap.internal;

import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RestrictTo;
import android.view.LayoutInflater;
import android.view.ViewGroup;
Expand Down Expand Up @@ -31,11 +32,12 @@ public interface ComponentProxy<T, VH extends FlapComponent<T>> {
VH createComponent(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent, int viewType);

/**
* 组件的 itemViewType,一般使用 layoutId
* @param model your model to bind with the component.
*
* @return the itemViewType of the component you are gonna create.
*/
int getItemViewType(T model);
int getItemViewType(@Nullable T model);

/**
* 指明 Component 将会绑定的模型的类
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ protected void onBind(@NonNull final Object model) {

}

public static class Factory implements ComponentProxy {
public static class Proxy implements ComponentProxy {

@NonNull
@Override
Expand Down

0 comments on commit c1c6444

Please sign in to comment.