Repository: mcxtzhang/DiffUtils Branch: master Commit: 73e091cc0962 Files: 65 Total size: 61.8 KB Directory structure: gitextract_90o5h7_s/ ├── .gitignore ├── .idea/ │ ├── compiler.xml │ ├── copyright/ │ │ └── profiles_settings.xml │ ├── encodings.xml │ ├── gradle.xml │ ├── libraries/ │ │ ├── animated_vector_drawable_24_2_0.xml │ │ ├── appcompat_v7_24_2_0.xml │ │ ├── espresso_core_2_2_2.xml │ │ ├── espresso_idling_resource_2_2_2.xml │ │ ├── exposed_instrumentation_api_publish_0_5.xml │ │ ├── hamcrest_core_1_3.xml │ │ ├── hamcrest_integration_1_3.xml │ │ ├── hamcrest_library_1_3.xml │ │ ├── javawriter_2_1_1.xml │ │ ├── javax_annotation_api_1_2.xml │ │ ├── javax_inject_1.xml │ │ ├── jsr305_2_0_1.xml │ │ ├── junit_4_12.xml │ │ ├── recyclerview_v7_24_2_0.xml │ │ ├── rules_0_5.xml │ │ ├── runner_0_5.xml │ │ ├── support_annotations_24_2_0.xml │ │ ├── support_compat_24_2_0.xml │ │ ├── support_core_ui_24_2_0.xml │ │ ├── support_core_utils_24_2_0.xml │ │ ├── support_fragment_24_2_0.xml │ │ ├── support_media_compat_24_2_0.xml │ │ ├── support_v4_24_2_0.xml │ │ └── support_vector_drawable_24_2_0.xml │ ├── misc.xml │ ├── modules.xml │ ├── runConfigurations.xml │ └── vcs.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── mcxtzhang/ │ │ └── diffutils/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── mcxtzhang/ │ │ │ └── diffutils/ │ │ │ ├── LauncherActivity.java │ │ │ ├── diffutil/ │ │ │ │ ├── DiffAdapter.java │ │ │ │ ├── DiffCallBack.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── TestBean.java │ │ │ └── sortedlist/ │ │ │ ├── SortedAdapter.java │ │ │ ├── SortedListActivity.java │ │ │ ├── SortedListCallback.java │ │ │ └── TestSortBean.java │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_launcher.xml │ │ │ ├── activity_main.xml │ │ │ ├── activity_sorted_list.xml │ │ │ └── item_diff.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ └── test/ │ └── java/ │ └── com/ │ └── mcxtzhang/ │ └── diffutils/ │ └── ExampleUnitTest.java ├── build.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Built application files *.apk *.ap_ # Files for the ART/Dalvik VM *.dex # Java class files *.class # Generated files bin/ gen/ out/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ # Log Files *.log # Android Studio Navigation editor temp files .navigation/ # Android Studio captures folder captures/ # Intellij *.iml .idea/workspace.xml # Keystore files *.jks ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/copyright/profiles_settings.xml ================================================ ================================================ FILE: .idea/encodings.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/libraries/animated_vector_drawable_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/appcompat_v7_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/espresso_core_2_2_2.xml ================================================ ================================================ FILE: .idea/libraries/espresso_idling_resource_2_2_2.xml ================================================ ================================================ FILE: .idea/libraries/exposed_instrumentation_api_publish_0_5.xml ================================================ ================================================ FILE: .idea/libraries/hamcrest_core_1_3.xml ================================================ ================================================ FILE: .idea/libraries/hamcrest_integration_1_3.xml ================================================ ================================================ FILE: .idea/libraries/hamcrest_library_1_3.xml ================================================ ================================================ FILE: .idea/libraries/javawriter_2_1_1.xml ================================================ ================================================ FILE: .idea/libraries/javax_annotation_api_1_2.xml ================================================ ================================================ FILE: .idea/libraries/javax_inject_1.xml ================================================ ================================================ FILE: .idea/libraries/jsr305_2_0_1.xml ================================================ ================================================ FILE: .idea/libraries/junit_4_12.xml ================================================ ================================================ FILE: .idea/libraries/recyclerview_v7_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/rules_0_5.xml ================================================ ================================================ FILE: .idea/libraries/runner_0_5.xml ================================================ ================================================ FILE: .idea/libraries/support_annotations_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_compat_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_core_ui_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_core_utils_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_fragment_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_media_compat_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_v4_24_2_0.xml ================================================ ================================================ FILE: .idea/libraries/support_vector_drawable_24_2_0.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ 1.8 ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/runConfigurations.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: README.md ================================================ #SupportDemos 本工程最初仅为DiffUtil的一个Demo,后发展为讲解Google Android Support包内那些常用or冷门有用的工具类的合集。 ## 索引: 合集Blog地址: http://blog.csdn.net/column/details/13763.html   ### DiffUtil: DiffUtils是Google官方在support-v7-24.2.0新出的一个工具类,本工程为一个讲解它使用的Demo 博文传送门: http://blog.csdn.net/zxt0601/article/details/52562770 代码地址: https://github.com/mcxtzhang/DiffUtils/tree/master/app/src/main/java/com/mcxtzhang/diffutils/diffutil 入口: MainActivity.java --- ### SortedList: 关键点: **搭配RecyclerView使用,去重,有序,自动定向刷新** 博文传送门: 待补 代码地址: https://github.com/mcxtzhang/DiffUtils/tree/master/app/src/main/java/com/mcxtzhang/diffutils/sortedlist 入口: SortedListActivity.java ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { compileSdkVersion 24 buildToolsVersion "24.0.2" defaultConfig { applicationId "com.mcxtzhang.diffutils" minSdkVersion 14 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:24.2.0' testCompile 'junit:junit:4.12' compile 'com.android.support:recyclerview-v7:24.2.0' } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in C:\Users\admin\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: app/src/androidTest/java/com/mcxtzhang/diffutils/ExampleInstrumentedTest.java ================================================ package com.mcxtzhang.diffutils; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumentation test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.mcxtzhang.diffutils", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/LauncherActivity.java ================================================ package com.mcxtzhang.diffutils; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import com.mcxtzhang.diffutils.diffutil.MainActivity; import com.mcxtzhang.diffutils.sortedlist.SortedListActivity; public class LauncherActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_launcher); findViewById(R.id.btnDiff).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(LauncherActivity.this, MainActivity.class)); } }); findViewById(R.id.btnSortedList).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(LauncherActivity.this, SortedListActivity.class)); } }); } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/diffutil/DiffAdapter.java ================================================ package com.mcxtzhang.diffutils.diffutil; import android.content.Context; import android.os.Bundle; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.mcxtzhang.diffutils.R; import java.util.List; /** * 介绍:普普通的adapter, * 但是 唯一亮点~ * public void onBindViewHolder(DiffVH holder, int position, List payloads) * 重写这个方法 * 作者:zhangxutong * 邮箱:zhangxutong@imcoming.com * 时间: 2016/9/12. */ public class DiffAdapter extends RecyclerView.Adapter { private final static String TAG = "zxt"; private List mDatas; private Context mContext; private LayoutInflater mInflater; public DiffAdapter(Context mContext, List mDatas) { this.mContext = mContext; this.mDatas = mDatas; mInflater = LayoutInflater.from(mContext); } public void setDatas(List mDatas) { this.mDatas = mDatas; } @Override public DiffVH onCreateViewHolder(ViewGroup parent, int viewType) { return new DiffVH(mInflater.inflate(R.layout.item_diff, parent, false)); } @Override public void onBindViewHolder(final DiffVH holder, final int position) { TestBean bean = mDatas.get(position); holder.tv1.setText(bean.getName()); holder.tv2.setText(bean.getDesc()); holder.iv.setImageResource(bean.getPic()); } @Override public void onBindViewHolder(DiffVH holder, int position, List payloads) { if (payloads.isEmpty()) { onBindViewHolder(holder, position); } else { //文艺青年中的文青 Bundle payload = (Bundle) payloads.get(0);//取出我们在getChangePayload()方法返回的bundle TestBean bean = mDatas.get(position);//取出新数据源,(可以不用) for (String key : payload.keySet()) { switch (key) { case "KEY_DESC": //这里可以用payload里的数据,不过data也是新的 也可以用 holder.tv2.setText(bean.getDesc()); break; case "KEY_PIC": holder.iv.setImageResource(payload.getInt(key)); break; default: break; } } } } @Override public int getItemCount() { return mDatas != null ? mDatas.size() : 0; } class DiffVH extends RecyclerView.ViewHolder { TextView tv1, tv2; ImageView iv; public DiffVH(View itemView) { super(itemView); tv1 = (TextView) itemView.findViewById(R.id.tv1); tv2 = (TextView) itemView.findViewById(R.id.tv2); iv = (ImageView) itemView.findViewById(R.id.iv); } } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/diffutil/DiffCallBack.java ================================================ package com.mcxtzhang.diffutils.diffutil; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.util.DiffUtil; import android.support.v7.widget.RecyclerView; import java.util.List; /** * 介绍:核心类 用来判断 新旧Item是否相等 * 作者:zhangxutong * 邮箱:zhangxutong@imcoming.com * 时间: 2016/9/12. */ public class DiffCallBack extends DiffUtil.Callback { private List mOldDatas, mNewDatas;//看名字 public DiffCallBack(List mOldDatas, List mNewDatas) { this.mOldDatas = mOldDatas; this.mNewDatas = mNewDatas; } //老数据集size @Override public int getOldListSize() { return mOldDatas != null ? mOldDatas.size() : 0; } //新数据集size @Override public int getNewListSize() { return mNewDatas != null ? mNewDatas.size() : 0; } /** * Called by the DiffUtil to decide whether two object represent the same Item. * 被DiffUtil调用,用来判断 两个对象是否是相同的Item。 * For example, if your items have unique ids, this method should check their id equality. * 例如,如果你的Item有唯一的id字段,这个方法就 判断id是否相等。 * 本例判断name字段是否一致 * * @param oldItemPosition The position of the item in the old list * @param newItemPosition The position of the item in the new list * @return True if the two items represent the same object or false if they are different. */ @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return mOldDatas.get(oldItemPosition).getName().equals(mNewDatas.get(newItemPosition).getName()); } /** * Called by the DiffUtil when it wants to check whether two items have the same data. * 被DiffUtil调用,用来检查 两个item是否含有相同的数据 * DiffUtil uses this information to detect if the contents of an item has changed. * DiffUtil用返回的信息(true false)来检测当前item的内容是否发生了变化 * DiffUtil uses this method to check equality instead of {@link Object#equals(Object)} * DiffUtil 用这个方法替代equals方法去检查是否相等。 * so that you can change its behavior depending on your UI. * 所以你可以根据你的UI去改变它的返回值 * For example, if you are using DiffUtil with a * {@link android.support.v7.widget.RecyclerView.Adapter RecyclerView.Adapter}, you should * return whether the items' visual representations are the same. * 例如,如果你用RecyclerView.Adapter 配合DiffUtil使用,你需要返回Item的视觉表现是否相同。 * This method is called only if {@link #areItemsTheSame(int, int)} returns * {@code true} for these items. * 这个方法仅仅在areItemsTheSame()返回true时,才调用。 * * @param oldItemPosition The position of the item in the old list * @param newItemPosition The position of the item in the new list which replaces the * oldItem * @return True if the contents of the items are the same or false if they are different. */ @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { TestBean beanOld = mOldDatas.get(oldItemPosition); TestBean beanNew = mNewDatas.get(newItemPosition); if (!beanOld.getDesc().equals(beanNew.getDesc())) { return false;//如果有内容不同,就返回false } if (beanOld.getPic() != beanNew.getPic()) { return false;//如果有内容不同,就返回false } return true; //默认两个data内容是相同的 } /** * When {@link #areItemsTheSame(int, int)} returns {@code true} for two items and * {@link #areContentsTheSame(int, int)} returns false for them, DiffUtil * calls this method to get a payload about the change. *

* 当{@link #areItemsTheSame(int, int)} 返回true,且{@link #areContentsTheSame(int, int)} 返回false时,DiffUtils会回调此方法, * 去得到这个Item(有哪些)改变的payload。 *

* For example, if you are using DiffUtil with {@link RecyclerView}, you can return the * particular field that changed in the item and your * {@link android.support.v7.widget.RecyclerView.ItemAnimator ItemAnimator} can use that * information to run the correct animation. *

* 例如,如果你用RecyclerView配合DiffUtils,你可以返回 这个Item改变的那些字段, * {@link android.support.v7.widget.RecyclerView.ItemAnimator ItemAnimator} 可以用那些信息去执行正确的动画 *

* Default implementation returns {@code null}.\ * 默认的实现是返回null * * @param oldItemPosition The position of the item in the old list * @param newItemPosition The position of the item in the new list * @return A payload object that represents the change between the two items. * 返回 一个 代表着新老item的改变内容的 payload对象, */ @Nullable @Override public Object getChangePayload(int oldItemPosition, int newItemPosition) { //实现这个方法 就能成为文艺青年中的文艺青年 // 定向刷新中的部分更新 // 效率最高 //只是没有了ItemChange的白光一闪动画,(反正我也觉得不太重要) TestBean oldBean = mOldDatas.get(oldItemPosition); TestBean newBean = mNewDatas.get(newItemPosition); //这里就不用比较核心字段了,一定相等 Bundle payload = new Bundle(); if (!oldBean.getDesc().equals(newBean.getDesc())) { payload.putString("KEY_DESC", newBean.getDesc()); } if (oldBean.getPic() != newBean.getPic()) { payload.putInt("KEY_PIC", newBean.getPic()); } if (payload.size() == 0)//如果没有变化 就传空 return null; return payload;// } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/diffutil/MainActivity.java ================================================ package com.mcxtzhang.diffutils.diffutil; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.support.v7.util.DiffUtil; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import com.mcxtzhang.diffutils.R; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private List mDatas; private RecyclerView mRv; private DiffAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); mRv = (RecyclerView) findViewById(R.id.rv); mRv.setLayoutManager(new LinearLayoutManager(this)); mAdapter = new DiffAdapter(this, mDatas); mRv.setAdapter(mAdapter); } private void initData() { mDatas = new ArrayList<>(); mDatas.add(new TestBean("张旭童1", "Android", R.drawable.pic1)); mDatas.add(new TestBean("张旭童2", "Java", R.drawable.pic2)); mDatas.add(new TestBean("张旭童3", "背锅", R.drawable.pic3)); mDatas.add(new TestBean("张旭童4", "手撕产品", R.drawable.pic4)); mDatas.add(new TestBean("张旭童5", "手撕测试", R.drawable.pic5)); } /** * 模拟刷新操作 * * @param view */ public void onRefresh(View view) { try { mNewDatas = new ArrayList<>(); for (TestBean bean : mDatas) { mNewDatas.add(bean.clone());//clone一遍旧数据 ,模拟刷新操作 } mNewDatas.add(new TestBean("赵子龙", "帅", R.drawable.pic6));//模拟新增数据 mNewDatas.get(0).setDesc("Android+"); mNewDatas.get(0).setPic(R.drawable.pic7);//模拟修改数据 TestBean testBean = mNewDatas.get(1);//模拟数据位移 mNewDatas.remove(testBean); mNewDatas.add(testBean); //新宠 //利用DiffUtil.calculateDiff()方法,传入一个规则DiffUtil.Callback对象,和是否检测移动item的 boolean变量,得到DiffUtil.DiffResult 的对象 new Thread(new Runnable() { @Override public void run() { //放在子线程中计算DiffResult DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffCallBack(mDatas, mNewDatas), true); Message message = mHandler.obtainMessage(H_CODE_UPDATE); message.obj = diffResult;//obj存放DiffResult message.sendToTarget(); } }).start(); //mAdapter.notifyDataSetChanged();//以前普通青年的我们只能这样,现在我们是文艺青年了,有新宠了 } catch (CloneNotSupportedException e) { e.printStackTrace(); } } private static final int H_CODE_UPDATE = 1; private List mNewDatas;//增加一个变量暂存newList private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case H_CODE_UPDATE: //取出Result DiffUtil.DiffResult diffResult = (DiffUtil.DiffResult) msg.obj; //利用DiffUtil.DiffResult对象的dispatchUpdatesTo()方法,传入RecyclerView的Adapter,轻松成为文艺青年 diffResult.dispatchUpdatesTo(mAdapter); //这种方法可以fix add 0 不滑动 /*diffResult.dispatchUpdatesTo(new ListUpdateCallback() { @Override public void onInserted(int position, int count) { mAdapter.notifyItemRangeInserted(position, count); if (position==0){ mRv.scrollToPosition(0); } } @Override public void onRemoved(int position, int count) { mAdapter.notifyItemRangeRemoved(position, count); } @Override public void onMoved(int fromPosition, int toPosition) { mAdapter.notifyItemMoved(fromPosition, toPosition); } @Override public void onChanged(int position, int count, Object payload) { mAdapter.notifyItemRangeChanged(position, count, payload); } });*/ //别忘了将新数据给Adapter mDatas = mNewDatas; mAdapter.setDatas(mDatas); break; } } }; } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/diffutil/TestBean.java ================================================ package com.mcxtzhang.diffutils.diffutil; /** * 介绍:一个普通的JavaBean,但是实现了clone方法,仅仅用于写Demo时,模拟刷新从网络获取数据用, * 因为使用DiffUtils比较新老数据集差异时,会遍历新老数据集的每个data,要确保他们的内存地址(指针)不一样,否则比较的是新老data是同一个,就一定相同, * 实际项目不需要,因为刷新时,数据一般从网络拉取,并且用Gson等解析出来,内存地址一定是不一样的。 * 作者:zhangxutong * 邮箱:zhangxutong@imcoming.com * 时间: 2016/9/12. */ public class TestBean implements Cloneable { private String name; private String desc; private int pic; public TestBean(String name, String desc, int pic) { this.name = name; this.desc = desc; this.pic = pic; } public int getPic() { return pic; } public void setPic(int pic) { this.pic = pic; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } //仅写DEMO 用 实现克隆方法 @Override public TestBean clone() throws CloneNotSupportedException { TestBean bean = null; try { bean = (TestBean) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return bean; } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/sortedlist/SortedAdapter.java ================================================ package com.mcxtzhang.diffutils.sortedlist; import android.content.Context; import android.support.v7.util.SortedList; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.mcxtzhang.diffutils.R; /** * 介绍:Adapter要修改, * 数据源都要从以前的ArrayList->替换为SortedList. * 其他的话,倒没有太大变化, * 因为SortedList虽然没有继承自List,但是暴漏出API还和List一样的。 * 作者:zhangxutong * 邮箱:mcxtzhang@163.com * 主页:http://blog.csdn.net/zxt0601 * 时间: 2016/11/29. */ public class SortedAdapter extends RecyclerView.Adapter { private final static String TAG = "zxt"; /** * 数据源替换为SortedList, * 以前可能会用ArrayList。 */ private SortedList mDatas; private Context mContext; private LayoutInflater mInflater; public SortedAdapter(Context mContext, SortedList mDatas) { this.mContext = mContext; this.mDatas = mDatas; mInflater = LayoutInflater.from(mContext); } public void setDatas(SortedList mDatas) { this.mDatas = mDatas; } @Override public SortedAdapter.VH onCreateViewHolder(ViewGroup parent, int viewType) { return new SortedAdapter.VH(mInflater.inflate(R.layout.item_diff, parent, false)); } @Override public void onBindViewHolder(final SortedAdapter.VH holder, final int position) { TestSortBean bean = mDatas.get(position); holder.tv1.setText(bean.getName()); holder.tv2.setText(bean.getId() + ""); holder.iv.setImageResource(bean.getIcon()); } @Override public int getItemCount() { return mDatas != null ? mDatas.size() : 0; } class VH extends RecyclerView.ViewHolder { TextView tv1, tv2; ImageView iv; public VH(View itemView) { super(itemView); tv1 = (TextView) itemView.findViewById(R.id.tv1); tv2 = (TextView) itemView.findViewById(R.id.tv2); iv = (ImageView) itemView.findViewById(R.id.iv); } } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/sortedlist/SortedListActivity.java ================================================ package com.mcxtzhang.diffutils.sortedlist; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.util.SortedList; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; import com.mcxtzhang.diffutils.R; /** * SortedListDemo */ public class SortedListActivity extends AppCompatActivity { /** * 数据源替换为SortedList, * 以前可能会用ArrayList。 */ private SortedList mDatas; private RecyclerView mRv; private SortedAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sorted_list); mRv = (RecyclerView) findViewById(R.id.rv); mRv.setLayoutManager(new LinearLayoutManager(this)); //★以前构建Adapter时,一般会将data也一起传入,现在有变化 mAdapter = new SortedAdapter(this, null); mRv.setAdapter(mAdapter); initData(); //mDatas.beginBatchedUpdates(); mAdapter.setDatas(mDatas); //mDatas.endBatchedUpdates(); } private void initData() { //★SortedList初始化的时候,要将Adapter传进来。所以先构建Adapter,再构建SortedList mDatas = new SortedList<>(TestSortBean.class, new SortedListCallback(mAdapter)); mDatas.add(new TestSortBean(10, "Android", R.drawable.pic1)); //★注意这里有一个重复的字段 会自动去重的。 mDatas.add(new TestSortBean(10, "Android重复", R.drawable.pic1)); mDatas.add(new TestSortBean(2, "Java", R.drawable.pic2)); mDatas.add(new TestSortBean(30, "背锅", R.drawable.pic3)); mDatas.add(new TestSortBean(4, "手撕产品", R.drawable.pic4)); mDatas.add(new TestSortBean(50, "手撕测试", R.drawable.pic5)); } /** * 模拟刷新操作 * * @param view */ public void onRefresh(View view) { //add 内部会自动调用 mCallback.onInserted(index, 1); ->notifyItemRangeInserted(index,1); //也就是说我们add一次 它就刷新一次,没有batch操作,有点low mDatas.add(new TestSortBean(26, "温油对待产品", R.drawable.pic6));//模拟新增 mDatas.add(new TestSortBean(12, "小马可以来点赞了", R.drawable.pic6));//模拟新增 mDatas.add(new TestSortBean(2, "Python", R.drawable.pic6));//add进去 重复的会自动修改 // 如果想batch 就必须用addAll()操作,感觉这算一个限制。 //addAll 也分两种 //第一种 以可变参数addAll //mDatas.addAll(new TestSortBean(26, "帅", R.drawable.pic6),new TestSortBean(27, "帅", R.drawable.pic6)); //第二种 集合形式 /* List temp = new ArrayList<>(); temp.add(new TestSortBean(26, "帅", R.drawable.pic6)); temp.add(new TestSortBean(28, "帅", R.drawable.pic6)); mDatas.addAll(temp); */ //刷新时,服务器给我们的一般都是一个List //直接addAll 要先clear, 会闪屏 /* List newDatas = new ArrayList<>(); for (int i = 0; i < mDatas.size(); i++) { try { newDatas.add(mDatas.get(i).clone());//clone一遍旧数据 ,模拟刷新操作 } catch (CloneNotSupportedException e) { e.printStackTrace(); } } newDatas.add(new TestSortBean(29, "帅", R.drawable.pic6));//模拟新增数据 newDatas.get(0).setName("Android+"); newDatas.get(0).setIcon(R.drawable.pic7);//模拟修改数据 TestSortBean testBean = newDatas.get(1);//模拟数据位移 newDatas.remove(testBean); newDatas.add(testBean); mDatas.clear(); mDatas.addAll(newDatas);*/ new Thread(new Runnable() { @Override public void run() { //每次add都会计算一次 想放在子线程中 //然而这是肯定不行的,上文提过,每次add 会自动 mAdapter.notifyItemRangeInserted(position, count); //这一点就不如DiffUtil啦。 //android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. /*mDatas.add(new TestSortBean(26, "帅", R.drawable.pic6));//模拟新增数据 mDatas.add(new TestSortBean(27, "帅", R.drawable.pic6));//模拟新增数据*/ } }).start(); } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/sortedlist/SortedListCallback.java ================================================ package com.mcxtzhang.diffutils.sortedlist; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.util.SortedListAdapterCallback; /** * 介绍:比较规则Callback。 * 和DiffUtil.Callback。写法套路一毛一样。 * 而且比DiffUtil.Callback简单。 * 因为不用传数据集进来,每次直接给你Item比较。 * * 作者:zhangxutong * 邮箱:mcxtzhang@163.com * 主页:http://blog.csdn.net/zxt0601 * 时间: 2016/11/29. */ public class SortedListCallback extends SortedListAdapterCallback { /** * Creates a {@link SortedList.Callback} that will forward data change events to the provided * Adapter. * * @param adapter The Adapter instance which should receive events from the SortedList. */ public SortedListCallback(RecyclerView.Adapter adapter) { super(adapter); } /** * 把它当成equals 方法就好 */ @Override public int compare(TestSortBean o1, TestSortBean o2) { return o1.getId() - o2.getId(); } /** * 和DiffUtil方法一致,不再赘述 */ @Override public boolean areItemsTheSame(TestSortBean item1, TestSortBean item2) { return item1.getId() == item2.getId(); } /** * 和DiffUtil方法一致,不再赘述 */ @Override public boolean areContentsTheSame(TestSortBean oldItem, TestSortBean newItem) { //默认相同 有一个不同就是不同 if (oldItem.getId() != newItem.getId()) { return false; } if (oldItem.getName().equals(newItem.getName())) { return false; } if (oldItem.getIcon() != newItem.getIcon()) { return false; } return true; } } ================================================ FILE: app/src/main/java/com/mcxtzhang/diffutils/sortedlist/TestSortBean.java ================================================ package com.mcxtzhang.diffutils.sortedlist; /** * 介绍: * 作者:zhangxutong * 邮箱:mcxtzhang@163.com * 主页:http://blog.csdn.net/zxt0601 * 时间: 2016/11/29. */ public class TestSortBean implements Cloneable{ private int id; private String name; private int icon; //仅写DEMO 用 实现克隆方法 @Override public TestSortBean clone() throws CloneNotSupportedException { TestSortBean bean = null; try { bean = (TestSortBean) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return bean; } @Override public String toString() { return "TestSortBean{" + "icon='" + icon + '\'' + ", name='" + name + '\'' + ", id=" + id + '}'; } public TestSortBean(int id, String name, int icon) { this.id = id; this.name = name; this.icon = icon; } public int getId() { return id; } public TestSortBean setId(int id) { this.id = id; return this; } public String getName() { return name; } public TestSortBean setName(String name) { this.name = name; return this; } public int getIcon() { return icon; } public TestSortBean setIcon(int icon) { this.icon = icon; return this; } } ================================================ FILE: app/src/main/res/layout/activity_launcher.xml ================================================