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

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

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

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

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