diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/README.md b/README.md index b211b4968..192dd052e 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # Flap -[ ![Download](https://api.bintray.com/packages/alancheen/maven/flap/images/download.svg?version=0.5.0) ](https://bintray.com/alancheen/maven/flap/0.5.0/link) [![Build Status](https://travis-ci.org/AlanCheen/Flap.svg?branch=master)](https://travis-ci.org/AlanCheen/Flap) +[![Download](https://api.bintray.com/packages/alancheen/maven/flap/images/download.svg?version=0.6.0)](https://bintray.com/alancheen/maven/flap/0.6.0/link) [![Build Status](https://travis-ci.org/AlanCheen/Flap.svg?branch=master)](https://travis-ci.org/AlanCheen/Flap) ![RecyclerView](https://img.shields.io/badge/RecyclerView-28.0.0-brightgreen.svg) ![API](https://img.shields.io/badge/API-14%2B-brightgreen.svg?style=flat) [![license](https://img.shields.io/github/license/AlanCheen/Flap.svg)](./LICENSE) -WARNING: Flap is still under development. +**WARNING: Flap is still under development.** -Flap is an library that makes RecyclerView.Adapter more easier to use , especially when you have to support lots of different type ViewHolders. +Flap is a library that makes `RecyclerView.Adapter` more easier to use , especially when you have to support lots of different type ViewHolders. Flap can save your day by keeping you from writing boilerplate codes. @@ -25,7 +25,7 @@ dependencies { #### Step 1 : Create a model class : -A model class can be a POJO or Java bean. +A model class can be a POJO or Java Bean. ```java public class SimpleTextModel { @@ -39,17 +39,19 @@ public class SimpleTextModel { } ``` -#### Step 2 : Create a `FlapItem` and `FlapItemFactory` : +#### Step 2 : Create a `FlapItem` and a `FlapItemFactory` : -`FlapItem` is a base `ViewHolder` that Flap is using which provides useful methods. +`FlapItem` is the base `ViewHolder` that `Flap` is used internally. -`FlapItemFactory` tells Flap the layout res id which is used when creating a `FlapItem`. +`FlapItemFactory` tells Flap how to create a `FlapItem` as you wish. Here is a sample : ```java public class SimpleTextItem extends FlapItem { + private static final String TAG = "SimpleTextItem"; + private TextView tvContent; public SimpleTextItem(final View itemView) { @@ -58,44 +60,46 @@ public class SimpleTextItem extends FlapItem { } @Override - protected void onBind(final SimpleTextModel model) { + protected void onBind(@NonNull final SimpleTextModel model, @NonNull final FlapAdapter adapter, @NonNull final List payloads) { tvContent.setText(model.content); } - public static class SimpleTextItemFactory extends FlapItemFactory { + public static class SimpleTextItemFactory extends LayoutItemFactory { @Override protected int getLayoutResId(final SimpleTextModel model) { return R.layout.flap_item_simple_text; } - } } ``` -#### Step 3 : Create a `FlapAdapter` and register the `FlapItemFactory` + + +#### Step 3 : Register the `FlapItemFactory` and create your `FlapAdapter` Create your `FlapAdapter` and register the `SimpleTextItemFactory` that we already created , setup the models : ```java -RecyclerView recyclerView = findViewById(R.id.rv_items); +//register your ItemFactory to Flap +Flap.getDefault().register(SimpleTextModel.class, new SimpleTextItem.SimpleTextItemFactory()); FlapAdapter adapter = new FlapAdapter(); -adapter.registerItemFactory(new SimpleTextItemFactory()); - List models = new ArrayList<>(); models.add(new SimpleTextModel("Android")); models.add(new SimpleTextModel("Java")); models.add(new SimpleTextModel("Kotlin")); + +//set your models to FlapAdapter adapter.setModels(models); recyclerView.setAdapter(adapter); ``` -You are good to go! +Yeah , you are good to go! ![](art/flap-simple-showcase.png) @@ -103,19 +107,17 @@ You are good to go! Flap adds some features for `FlapItem` : -1. Access a context directly by field `context` -2. Call `findViewById()` instead of `itemView.findViewById` +1. Access a context directly by field `context`. +2. Call `findViewById()` directlly instead of `itemView.findViewById` when you want to find a view. +3. Override `onViewAttachedToWindow` & `onViewDetachedFromWindow` so that you can do something like pausing or resuming a video. -What's more , here are some methods for you that you can override if you need : -1. Override `onBind(final T model, final FlapAdapter adapter, final List payloads)` when you wanna access your adapter or payloads. -2. Override `onViewAttachedToWindow` & `onViewDetachedFromWindow` so that you can do something like pausing or resuming a video. +### Enable Lifecycle -### Enable Lifecycle -By extending `LifecycleItem` , a lifecycle aware `ViewHolder` , you can get the lifecycle callbacks : `onResume` 、`onPause`、`onStop`、`onDestroy` when you care about the lifecycle , `FlapAdapter` binds the `LifecycleOwner` automatically. +By extending `LifecycleItem` , a lifecycle aware `ViewHolder` , you can get the lifecycle callbacks : `onResume` 、`onPause`、`onStop`、`onDestroy` by default , when you care about the lifecycle , `FlapAdapter` binds the `LifecycleOwner` automatically. Releated methods : @@ -130,10 +132,18 @@ Releated methods : Check [Releases](https://github.com/AlanCheen/Flap/releases) for details. + +## Todo List + +- Support AsyncListDiffer +- Support Lifecycle + ## Contribution Any feedback would be helpful , thanks. + + ## Contact Me I'm Fitz , an Engineer working at Alibaba living in China . @@ -148,14 +158,20 @@ Follow me on : Feel free to contact me. + + ## Apps are using Flap Contact me if you are using Flap in your App. + + ## Thanks I'm using [StefMa/bintray-release](https://github.com/StefMa/bintray-release) to publish Flap to jCenter. + + ## License ``` diff --git a/app/build.gradle b/app/build.gradle index e6e37fc73..1f8a65b72 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { applicationId "me.yifeiyuan.flapdev" - minSdkVersion 17 - targetSdkVersion 27 + minSdkVersion 14 + targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -20,11 +20,11 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:appcompat-v7:27.1.1' + implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation 'com.android.support:recyclerview-v7:27.1.1' + implementation 'com.android.support:recyclerview-v7:28.0.0' implementation project(':flap') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bef7c03c1..e5220e96f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,7 +8,10 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/AppTheme"> + android:theme="@style/AppTheme" + android:name=".FlapApplication" + > + @@ -16,6 +19,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/me/yifeiyuan/flapdev/DifferActivity.java b/app/src/main/java/me/yifeiyuan/flapdev/DifferActivity.java new file mode 100644 index 000000000..4c4ad0ded --- /dev/null +++ b/app/src/main/java/me/yifeiyuan/flapdev/DifferActivity.java @@ -0,0 +1,83 @@ +package me.yifeiyuan.flapdev; + +import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.recyclerview.extensions.AsyncListDiffer; +import android.support.v7.util.DiffUtil; +import android.support.v7.widget.RecyclerView; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +import me.yifeiyuan.flap.FlapAdapter; +import me.yifeiyuan.flapdev.simpletext.SimpleTextModel; + +/** + * todo support + * AsyncListDiffer + * ListAdapter + */ +public class DifferActivity extends AppCompatActivity { + + private static final String TAG = "DifferActivity"; + + private FlapAdapter flapAdapter; + private AsyncListDiffer differ; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_differ); + + RecyclerView recyclerView = findViewById(R.id.rv_items); + + flapAdapter = new FlapAdapter(); + + List models = new ArrayList<>(); + + models.add(new SimpleTextModel("Android")); + models.add(new SimpleTextModel("Java")); + models.add(new SimpleTextModel("Kotlin")); + + flapAdapter.setModels(models); + + recyclerView.setAdapter(flapAdapter); + + differ = new AsyncListDiffer(flapAdapter, new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NonNull final SimpleTextModel simpleTextModel, @NonNull final SimpleTextModel t1) { + Log.d(TAG, "areItemsTheSame() called with: simpleTextModel = [" + simpleTextModel + "], t1 = [" + t1 + "]"); + return false; + } + + @Override + public boolean areContentsTheSame(@NonNull final SimpleTextModel simpleTextModel, @NonNull final SimpleTextModel t1) { + Log.d(TAG, "areContentsTheSame() called with: simpleTextModel = [" + simpleTextModel + "], t1 = [" + t1 + "]"); + return false; + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + changeModels(); + } + + private void changeModels() { + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + List newModels = new ArrayList<>(); + newModels.add(new SimpleTextModel("iOS")); + newModels.add(new SimpleTextModel("OC")); + newModels.add(new SimpleTextModel("Kotlin")); + flapAdapter.setModels(newModels); + differ.submitList(newModels); + } + }, 5000); + } +} diff --git a/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java new file mode 100644 index 000000000..dabf60807 --- /dev/null +++ b/app/src/main/java/me/yifeiyuan/flapdev/FlapApplication.java @@ -0,0 +1,34 @@ +package me.yifeiyuan.flapdev; + +import android.app.Application; +import android.util.Log; + +import me.yifeiyuan.flap.Flap; +import me.yifeiyuan.flapdev.simpleimage.SimpleImageItem; +import me.yifeiyuan.flapdev.simpleimage.SimpleImageModel; +import me.yifeiyuan.flapdev.simpletext.SimpleTextItem; +import me.yifeiyuan.flapdev.simpletext.SimpleTextModel; + +/** + * Flap + * Created by 程序亦非猿 on 2018/12/13. + */ +public class FlapApplication extends Application { + + @Override + public void onCreate() { + super.onCreate(); + + Flap.setDebug(true); + + long t1 = System.currentTimeMillis(); + + Flap.getDefault().register(SimpleTextModel.class, new SimpleTextItem.SimpleTextItemFactory()); + Flap.getDefault().register(SimpleImageModel.class, new SimpleImageItem.SimpleImageItemFactory()); + + long t2 = System.currentTimeMillis(); + + Log.e("Flap", "Init Flap time cost :" + (t2 - t1)); + + } +} diff --git a/app/src/main/java/me/yifeiyuan/flapdev/MainActivity.java b/app/src/main/java/me/yifeiyuan/flapdev/MainActivity.java index c1389ab06..950af7feb 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/MainActivity.java +++ b/app/src/main/java/me/yifeiyuan/flapdev/MainActivity.java @@ -9,8 +9,6 @@ import me.yifeiyuan.flap.FlapAdapter; import me.yifeiyuan.flapdev.simpleimage.SimpleImageModel; -import me.yifeiyuan.flapdev.simpleimage.SimpleImageVH; -import me.yifeiyuan.flapdev.simpletext.SimpleTextItem; import me.yifeiyuan.flapdev.simpletext.SimpleTextModel; public class MainActivity extends AppCompatActivity { @@ -24,15 +22,15 @@ protected void onCreate(Bundle savedInstanceState) { FlapAdapter adapter = new FlapAdapter(); - adapter.registerItemFactory(new SimpleTextItem.SimpleTextItemFactory()) - .registerItemFactory(new SimpleImageVH.SimpleImageItemFactory()); - List models = new ArrayList<>(); models.add(new SimpleTextModel("Android")); models.add(new SimpleTextModel("Java")); models.add(new SimpleTextModel("Kotlin")); + models.add(new SimpleImageModel()); + models.add(new SimpleImageModel()); + models.add(new SimpleImageModel()); models.add(new SimpleImageModel()); adapter.setModels(models); diff --git a/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageItem.java b/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageItem.java new file mode 100644 index 000000000..27d818c2c --- /dev/null +++ b/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageItem.java @@ -0,0 +1,35 @@ +package me.yifeiyuan.flapdev.simpleimage; + +import android.support.annotation.NonNull; +import android.view.View; + +import java.util.List; + +import me.yifeiyuan.flap.FlapAdapter; +import me.yifeiyuan.flap.FlapItem; +import me.yifeiyuan.flap.LayoutItemFactory; +import me.yifeiyuan.flapdev.R; + +/** + * Created by 程序亦非猿 on 2018/12/4. + */ +public class SimpleImageItem extends FlapItem { + + public SimpleImageItem(final View itemView) { + super(itemView); + } + + @Override + protected void onBind(@NonNull final SimpleImageModel model, @NonNull final FlapAdapter adapter, @NonNull final List payloads) { + + } + + public static class SimpleImageItemFactory extends LayoutItemFactory { + + @Override + protected int getLayoutResId(final SimpleImageModel model) { + return R.layout.flap_item_simple_image; + } + } + +} diff --git a/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageVH.java b/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageVH.java deleted file mode 100644 index 6f327e465..000000000 --- a/app/src/main/java/me/yifeiyuan/flapdev/simpleimage/SimpleImageVH.java +++ /dev/null @@ -1,40 +0,0 @@ -package me.yifeiyuan.flapdev.simpleimage; - -import android.support.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import me.yifeiyuan.flap.FlapItem; -import me.yifeiyuan.flap.ItemFactory; -import me.yifeiyuan.flapdev.R; - -/** - * Created by 程序亦非猿 on 2018/12/4. - */ -public class SimpleImageVH extends FlapItem { - - public SimpleImageVH(final View itemView) { - super(itemView); - } - - @Override - protected void onBind(final SimpleImageModel model) { - - } - - public static class SimpleImageItemFactory implements ItemFactory { - - @NonNull - @Override - public FlapItem onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent, final int viewType) { - return new SimpleImageVH(inflater.inflate(viewType, parent, false)); - } - - @Override - public int getItemViewType(final SimpleImageModel model) { - return R.layout.item_simple_image; - } - } - -} diff --git a/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextItem.java b/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextItem.java index 270d06669..426dcb1ea 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextItem.java +++ b/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextItem.java @@ -1,10 +1,14 @@ package me.yifeiyuan.flapdev.simpletext; +import android.support.annotation.NonNull; import android.view.View; import android.widget.TextView; +import java.util.List; + +import me.yifeiyuan.flap.FlapAdapter; import me.yifeiyuan.flap.FlapItem; -import me.yifeiyuan.flap.FlapItemFactory; +import me.yifeiyuan.flap.LayoutItemFactory; import me.yifeiyuan.flapdev.R; /** @@ -12,6 +16,8 @@ */ public class SimpleTextItem extends FlapItem { + private static final String TAG = "SimpleTextItem"; + private TextView tvContent; public SimpleTextItem(final View itemView) { @@ -20,17 +26,16 @@ public SimpleTextItem(final View itemView) { } @Override - protected void onBind(final SimpleTextModel model) { + protected void onBind(@NonNull final SimpleTextModel model, @NonNull final FlapAdapter adapter, @NonNull final List payloads) { tvContent.setText(model.content); } - public static class SimpleTextItemFactory extends FlapItemFactory { + public static class SimpleTextItemFactory extends LayoutItemFactory { @Override protected int getLayoutResId(final SimpleTextModel model) { return R.layout.flap_item_simple_text; } - } } diff --git a/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextModel.java b/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextModel.java index ca0dc2c8e..cad48bf61 100644 --- a/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextModel.java +++ b/app/src/main/java/me/yifeiyuan/flapdev/simpletext/SimpleTextModel.java @@ -13,4 +13,19 @@ public class SimpleTextModel { public SimpleTextModel(@NonNull final String content) { this.content = content; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final SimpleTextModel that = (SimpleTextModel) o; + + return content.equals(that.content); + } + + @Override + public int hashCode() { + return content.hashCode(); + } } diff --git a/app/src/main/res/layout/activity_differ.xml b/app/src/main/res/layout/activity_differ.xml new file mode 100644 index 000000000..20b546ac2 --- /dev/null +++ b/app/src/main/res/layout/activity_differ.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_simple_image.xml b/app/src/main/res/layout/flap_item_simple_image.xml similarity index 100% rename from app/src/main/res/layout/item_simple_image.xml rename to app/src/main/res/layout/flap_item_simple_image.xml diff --git a/flap/build.gradle b/flap/build.gradle index 572105294..2bfd7c417 100644 --- a/flap/build.gradle +++ b/flap/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { - minSdkVersion 17 - targetSdkVersion 27 + minSdkVersion 14 + targetSdkVersion 28 versionCode 1 versionName "1.0" @@ -28,14 +28,14 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation 'com.android.support:recyclerview-v7:27.1.1' + implementation 'com.android.support:recyclerview-v7:28.0.0' } apply plugin: "guru.stefma.bintrayrelease" -version = "0.5.0" +version = "0.6.0" group = "me.yifeiyuan.flap" -androidArtifact { // 2 +androidArtifact { artifactId = "flap" } publish { diff --git a/flap/src/main/java/me/yifeiyuan/flap/DefaultFlapItem.java b/flap/src/main/java/me/yifeiyuan/flap/DefaultFlapItem.java index e3b9de2ff..83591538c 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/DefaultFlapItem.java +++ b/flap/src/main/java/me/yifeiyuan/flap/DefaultFlapItem.java @@ -1,20 +1,23 @@ package me.yifeiyuan.flap; +import android.support.annotation.NonNull; import android.view.View; +import java.util.List; + /** * Created by 程序亦非猿 * * It's the default ViewHolder would be used when something wrong was happened so that we won't get a crash. */ -class DefaultFlapItem extends FlapItem { +final class DefaultFlapItem extends FlapItem { DefaultFlapItem(final View itemView) { super(itemView); } @Override - protected void onBind(final Object model) { + protected void onBind(@NonNull final Object model, @NonNull final FlapAdapter adapter, @NonNull final List payloads) { } diff --git a/flap/src/main/java/me/yifeiyuan/flap/Flap.java b/flap/src/main/java/me/yifeiyuan/flap/Flap.java index 83c38936c..fcd2105a6 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/Flap.java +++ b/flap/src/main/java/me/yifeiyuan/flap/Flap.java @@ -1,7 +1,6 @@ package me.yifeiyuan.flap; import android.support.annotation.NonNull; -import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; @@ -13,20 +12,20 @@ /** * Created by 程序亦非猿 */ -public class Flap implements IFlap { +public final class Flap implements IFlap { private static final String TAG = "Flap"; private static final int DEFAULT_ITEM_TYPE = -66666; - private static final int DEFAULT_ITEM_TYPE_COUNT = 32; + static final int DEFAULT_ITEM_TYPE_COUNT = 32; - private final Map, ItemFactory> itemFactories; - private final SparseArray factoryMapping; + private final Map, FlapItemFactory> itemFactories; + private final SparseArray factoryMapping; private static volatile Flap sInstance; - static Flap getDefault() { + public static Flap getDefault() { if (null == sInstance) { synchronized (Flap.class) { if (null == sInstance) { @@ -47,35 +46,30 @@ private Flap(int typeCount) { } @Override - public ItemFactoryManager registerItemFactory(@NonNull final ItemFactory itemFactory) { - Class modelClazz = getModelClassFromItemFactory(itemFactory); + public ItemFactoryManager register(@NonNull final Class modelClazz, @NonNull final FlapItemFactory itemFactory) { itemFactories.put(modelClazz, itemFactory); return this; } @Override - public ItemFactoryManager unregisterItemFactory(@NonNull final ItemFactory itemFactory) { - Class modelClazz = getModelClassFromItemFactory(itemFactory); + public ItemFactoryManager unregister(@NonNull final Class modelClazz) { itemFactories.remove(modelClazz); return this; } - private Class getModelClassFromItemFactory(final ItemFactory itemFactory) { - return (Class) ReflectUtils.getTypes(itemFactory)[0]; - } - + @SuppressWarnings("unchecked") @Override public int getItemViewType(@NonNull final Object model) { Class modelClazz = model.getClass(); - ItemFactory factory = itemFactories.get(modelClazz); + FlapItemFactory factory = itemFactories.get(modelClazz); if (null != factory) { int itemViewType = factory.getItemViewType(model); factoryMapping.put(itemViewType, factory); return itemViewType; } else { - Log.e(TAG, "Can't find the ItemFactory for class: " + modelClazz + " ,please register first"); + FlapDebug.throwIfDebugging(new ItemFactoryNotFoundException("Can't find the ItemFactory for : " + modelClazz + " , please register first!")); } return DEFAULT_ITEM_TYPE; } @@ -86,13 +80,13 @@ public FlapItem onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonN FlapItem vh = null; - ItemFactory factory = factoryMapping.get(viewType); + FlapItemFactory factory = factoryMapping.get(viewType); if (null != factory) { try { vh = factory.onCreateViewHolder(inflater, parent, viewType); } catch (Exception e) { e.printStackTrace(); - Log.e(TAG, "Something went wrong when creating item by ItemFactory:" + factory.getClass().getSimpleName()); + FlapDebug.throwIfDebugging(e); } } //In case that we get a null view holder , create a default one ,so won't crash the app @@ -107,4 +101,8 @@ public FlapItem onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonN public FlapItem onCreateDefaultViewHolder(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent, final int viewType) { return new DefaultFlapItem(new View(parent.getContext())); } + + public static void setDebug(final boolean isDebugging) { + FlapDebug.setDebug(isDebugging); + } } diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.java b/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.java index 0621385bb..e9623b416 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.java +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapAdapter.java @@ -15,7 +15,7 @@ /** * Created by 程序亦非猿 */ -public class FlapAdapter extends RecyclerView.Adapter implements ItemFactoryManager { +public class FlapAdapter extends RecyclerView.Adapter { @NonNull private Flap flap = Flap.getDefault(); @@ -47,6 +47,7 @@ public void onBindViewHolder(@NonNull final FlapItem holder, final int position, /** * Attaches the holder to lifecycle if need. + * * @param holder */ private void attachLifecycleOwnerIfNeed(final FlapItem holder) { @@ -65,18 +66,6 @@ public int getItemViewType(final int position) { return flap.getItemViewType(getModel(position)); } - @Override - public FlapAdapter registerItemFactory(@NonNull final ItemFactory itemFactory) { - flap.registerItemFactory(itemFactory); - return this; - } - - @Override - public FlapAdapter unregisterItemFactory(@NonNull final ItemFactory itemFactory) { - flap.unregisterItemFactory(itemFactory); - return this; - } - @Override public void onAttachedToRecyclerView(@NonNull final RecyclerView recyclerView) { super.onAttachedToRecyclerView(recyclerView); @@ -98,6 +87,7 @@ public void onViewDetachedFromWindow(@NonNull FlapItem holder) { } public FlapAdapter setLifecycleOwner(@NonNull final LifecycleOwner lifecycleOwner) { + checkNotNull(lifecycleOwner); this.lifecycleOwner = lifecycleOwner; return this; } diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapDebug.java b/flap/src/main/java/me/yifeiyuan/flap/FlapDebug.java new file mode 100644 index 000000000..30de23bd3 --- /dev/null +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapDebug.java @@ -0,0 +1,26 @@ +package me.yifeiyuan.flap; + +import android.util.Log; + +/** + * Flap + * Created by 程序亦非猿 on 2018/12/13. + */ +final class FlapDebug { + + private static final String TAG = "FlapDebug"; + + private static boolean DEBUG = false; + + static void setDebug(boolean isDebugging) { + DEBUG = isDebugging; + } + + static void throwIfDebugging(Exception e) { + if (DEBUG) { + throw new RuntimeException(e); + } else { + Log.e(TAG, "FlapDebug : ", e); + } + } +} diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapItem.java b/flap/src/main/java/me/yifeiyuan/flap/FlapItem.java index bee0fcf52..05ae00a43 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/FlapItem.java +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapItem.java @@ -2,6 +2,7 @@ import android.content.Context; import android.support.annotation.IdRes; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.View; @@ -11,6 +12,10 @@ * Created by 程序亦非猿 * * The base ViewHolder provides some useful and convenient abilities. + * + * By extending the LifecycleItem you can receive the lifecycle callbacks. + * + * @see LifecycleItem */ public abstract class FlapItem extends RecyclerView.ViewHolder { @@ -21,16 +26,13 @@ public FlapItem(View itemView) { context = itemView.getContext(); } - final void bind(T model, FlapAdapter adapter, final List payloads) { + final void bind(@NonNull final T model, @NonNull final FlapAdapter adapter, @NonNull final List payloads) { onBind(model, adapter, payloads); } - protected void onBind(final T model, final FlapAdapter adapter, final List payloads) { - onBind(model); - } - - protected abstract void onBind(final T model); + protected abstract void onBind(@NonNull final T model, @NonNull final FlapAdapter adapter, @NonNull final List payloads); + @SuppressWarnings("unchecked") protected final V findViewById(@IdRes int viewId) { return (V) itemView.findViewById(viewId); } @@ -38,13 +40,13 @@ protected final V findViewById(@IdRes int viewId) { /** * @see FlapAdapter#onViewAttachedToWindow(FlapItem) */ - void onViewAttachedToWindow() { + protected void onViewAttachedToWindow() { } /** * @see FlapAdapter#onViewDetachedFromWindow(FlapItem) */ - void onViewDetachedFromWindow() { + protected void onViewDetachedFromWindow() { } } diff --git a/flap/src/main/java/me/yifeiyuan/flap/FlapItemFactory.java b/flap/src/main/java/me/yifeiyuan/flap/FlapItemFactory.java index 269e6e201..56f5ab143 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/FlapItemFactory.java +++ b/flap/src/main/java/me/yifeiyuan/flap/FlapItemFactory.java @@ -1,50 +1,18 @@ package me.yifeiyuan.flap; -import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - /** * Created by 程序亦非猿 + * + * An ItemFactory is used for creating FlapItem. */ -public abstract class FlapItemFactory implements ItemFactory { +interface FlapItemFactory> { - @SuppressWarnings("unchecked") @NonNull - @Override - public VH onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent, final int viewType) { - - View view = inflater.inflate(viewType, parent, false); - - Class clazz = (Class) ReflectUtils.getTypes(this)[1]; - - VH vh = null; - try { - Constructor constructor = clazz.getConstructor(View.class); - constructor.setAccessible(true); - vh = (VH) constructor.newInstance(view); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - return vh; - } - - @Override - public final int getItemViewType(final T model) { - return getLayoutResId(model); - } + VH onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent, int viewType); - @LayoutRes - protected abstract int getLayoutResId(final T model); + int getItemViewType(T model); } diff --git a/flap/src/main/java/me/yifeiyuan/flap/ItemFactory.java b/flap/src/main/java/me/yifeiyuan/flap/ItemFactory.java deleted file mode 100644 index d4fe055c0..000000000 --- a/flap/src/main/java/me/yifeiyuan/flap/ItemFactory.java +++ /dev/null @@ -1,18 +0,0 @@ -package me.yifeiyuan.flap; - -import android.support.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.ViewGroup; - -/** - * Created by 程序亦非猿 - * - * An ItemFactory is used for creating FlapItem. - */ -public interface ItemFactory { - - @NonNull - FlapItem onCreateViewHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent, int viewType); - - int getItemViewType(T model); -} diff --git a/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryManager.java b/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryManager.java index 608786012..35a622330 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryManager.java +++ b/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryManager.java @@ -5,11 +5,24 @@ /** * Created by 程序亦非猿 * - * A manager for managing ItemFactory. + * A manager for ItemFactories. */ public interface ItemFactoryManager { - ItemFactoryManager registerItemFactory(@NonNull ItemFactory itemFactory); + /** + * Register a ItemFactory to ItemFactoryManager + * + * @param modelClazz The class of your Model which is used in your FlapItem. + * @param itemFactory The ItemFactory creates FlapItem. + * + * @return An ItemFactoryManager usually it could be `this`. + */ + ItemFactoryManager register(@NonNull final Class modelClazz, @NonNull final FlapItemFactory itemFactory); - ItemFactoryManager unregisterItemFactory(@NonNull ItemFactory itemFactory); + /** + * @param modelClazz The class of your Model which is used in your FlapItem. + * + * @return An ItemFactoryManager usually it could be `this`. + */ + ItemFactoryManager unregister(@NonNull final Class modelClazz); } diff --git a/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryNotFoundException.java b/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryNotFoundException.java new file mode 100644 index 000000000..fd2fe2ddd --- /dev/null +++ b/flap/src/main/java/me/yifeiyuan/flap/ItemFactoryNotFoundException.java @@ -0,0 +1,12 @@ +package me.yifeiyuan.flap; + +/** + * Created by 程序亦非猿 on 2018/12/13. + */ +final class ItemFactoryNotFoundException extends IllegalArgumentException { + + ItemFactoryNotFoundException(final String s) { + super(s); + } + +} diff --git a/flap/src/main/java/me/yifeiyuan/flap/LayoutItemFactory.java b/flap/src/main/java/me/yifeiyuan/flap/LayoutItemFactory.java new file mode 100644 index 000000000..61c00202a --- /dev/null +++ b/flap/src/main/java/me/yifeiyuan/flap/LayoutItemFactory.java @@ -0,0 +1,63 @@ +package me.yifeiyuan.flap; + +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; + +import static me.yifeiyuan.flap.Flap.DEFAULT_ITEM_TYPE_COUNT; + +/** + * Created by 程序亦非猿 + */ +public abstract class LayoutItemFactory> implements FlapItemFactory { + + private static final HashMap, Constructor> sConstructorCache = new HashMap<>(DEFAULT_ITEM_TYPE_COUNT); + + @SuppressWarnings("unchecked") + @NonNull + @Override + public final VH onCreateViewHolder(@NonNull final LayoutInflater inflater, @NonNull final ViewGroup parent, final int viewType) { + + View view = inflater.inflate(viewType, parent, false); + + Class clazz = (Class) ReflectUtils.getTypes(this)[1]; + + VH vh = null; + long t1 = System.currentTimeMillis(); + Constructor constructor = sConstructorCache.get(clazz); + try { + if (constructor == null) { + constructor = clazz.getConstructor(View.class); + constructor.setAccessible(true); + sConstructorCache.put(clazz, constructor); + } + vh = (VH) constructor.newInstance(view); + long t2 = System.currentTimeMillis(); + Log.d("Flap", "onCreateViewHolder time cost:" + (t2 - t1)); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + return vh; + } + + @Override + public final int getItemViewType(final T model) { + return getLayoutResId(model); + } + + @LayoutRes + protected abstract int getLayoutResId(final T model); +} diff --git a/flap/src/main/java/me/yifeiyuan/flap/LifecycleItem.java b/flap/src/main/java/me/yifeiyuan/flap/LifecycleItem.java index 5afaa3248..2d3cb6d24 100644 --- a/flap/src/main/java/me/yifeiyuan/flap/LifecycleItem.java +++ b/flap/src/main/java/me/yifeiyuan/flap/LifecycleItem.java @@ -6,7 +6,6 @@ import android.view.View; /** - * Flap * Created by 程序亦非猿 on 2018/12/5. */ public abstract class LifecycleItem extends FlapItem implements LifecycleObserver {