Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.example.android.supportv7.util;
     17 
     18 import android.os.AsyncTask;
     19 import android.os.Bundle;
     20 import android.support.annotation.Nullable;
     21 import android.support.v4.util.Pair;
     22 import android.support.v7.app.AppCompatActivity;
     23 import android.support.v7.util.DiffUtil;
     24 import android.support.v7.widget.LinearLayoutManager;
     25 import android.support.v7.widget.RecyclerView;
     26 import android.view.View;
     27 import android.view.ViewGroup;
     28 import android.widget.Button;
     29 import android.widget.LinearLayout;
     30 import android.widget.Toast;
     31 
     32 import com.example.android.supportv7.Cheeses;
     33 import com.example.android.supportv7.widget.adapter.SimpleStringAdapter;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.List;
     38 import java.util.Random;
     39 import java.util.concurrent.atomic.AtomicBoolean;
     40 
     41 /**
     42  * A sample activity that demonstrates usage if {@link android.support.v7.util.DiffUtil} with
     43  * a RecyclerView.
     44  */
     45 public class DiffUtilActivity extends AppCompatActivity {
     46     private Random mRandom = new Random(System.nanoTime());
     47 
     48     @Override
     49     protected void onCreate(@Nullable Bundle savedInstanceState) {
     50         super.onCreate(savedInstanceState);
     51         LinearLayout ll = new LinearLayout(this);
     52         RecyclerView rv = new RecyclerView(this);
     53         Button shuffle = new Button(this);
     54         shuffle.setText("Shuffle");
     55         ll.addView(shuffle);
     56         ll.addView(rv);
     57         rv.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
     58                 ViewGroup.LayoutParams.MATCH_PARENT));
     59         rv.setLayoutManager(new LinearLayoutManager(this));
     60         List<String> cheeseList = createRandomCheeseList(Collections.<String>emptyList(), 50);
     61         final SimpleStringAdapter adapter =
     62                 new SimpleStringAdapter(this, cheeseList.toArray(new String[cheeseList.size()]));
     63         rv.setAdapter(adapter);
     64         final AtomicBoolean refreshingList = new AtomicBoolean(false);
     65         shuffle.setOnClickListener(new View.OnClickListener() {
     66             @Override
     67             public void onClick(View view) {
     68                 if (refreshingList.getAndSet(true)) {
     69                     // already refreshing, do not allow modifications
     70                     return;
     71                 }
     72                 //noinspection unchecked
     73                 new AsyncTask<List<String>, Void, Pair<List<String>, DiffUtil.DiffResult>>() {
     74 
     75                     @Override
     76                     protected Pair<List<String>, DiffUtil.DiffResult> doInBackground(
     77                             List<String>... lists) {
     78                         List<String> oldList = lists[0];
     79                         List<String> newList = createRandomCheeseList(oldList, 5);
     80                         DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(
     81                                 new MyCallback(oldList, newList));
     82                         //noinspection unchecked
     83                         return new Pair(newList, diffResult);
     84                     }
     85 
     86                     @Override
     87                     protected void onPostExecute(
     88                             Pair<List<String>, DiffUtil.DiffResult> resultPair) {
     89                         refreshingList.set(false);
     90                         adapter.setValues(resultPair.first);
     91                         resultPair.second.dispatchUpdatesTo(adapter);
     92                         Toast.makeText(DiffUtilActivity.this, "new list size "
     93                                 + resultPair.first.size(), Toast.LENGTH_SHORT).show();
     94                     }
     95                 }.execute(adapter.getValues());
     96 
     97             }
     98         });
     99         setContentView(ll);
    100     }
    101 
    102     private static class MyCallback extends DiffUtil.Callback {
    103         private final List<String> mOld;
    104         private final List<String> mNew;
    105 
    106         public MyCallback(List<String> old, List<String> aNew) {
    107             mOld = old;
    108             mNew = aNew;
    109         }
    110 
    111         @Override
    112         public int getOldListSize() {
    113             return mOld.size();
    114         }
    115 
    116         @Override
    117         public int getNewListSize() {
    118             return mNew.size();
    119         }
    120 
    121         @Override
    122         public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
    123             // for strings, content equality is the same as identitiy equality since we don't have
    124             // duplicates in this sample.
    125             return mOld.get(oldItemPosition).equals(mNew.get(newItemPosition));
    126         }
    127 
    128         @Override
    129         public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
    130             return mOld.get(oldItemPosition).equals(mNew.get(newItemPosition));
    131         }
    132     }
    133 
    134     private List<String> createRandomCheeseList(List<String> seed, int iterations) {
    135         List<String> output = new ArrayList<>();
    136         output.addAll(seed);
    137         for (int i = 0; i < iterations; i++) {
    138             switch (mRandom.nextInt(3)) {
    139                 case 0: //add
    140                     output.add(mRandom.nextInt(1 + output.size()), getRandomCheese(output));
    141                     break;
    142                 case 1: // remove
    143                     if (output.size() > 0) {
    144                         output.remove(mRandom.nextInt(output.size()));
    145                     }
    146                     break;
    147                 case 2: // move
    148                     if (output.size() > 0) {
    149                         int from = mRandom.nextInt(output.size());
    150                         int to = mRandom.nextInt(output.size());
    151                         output.add(to, output.remove(from));
    152                     }
    153                     break;
    154             }
    155         }
    156         return output;
    157     }
    158 
    159     private String getRandomCheese(List<String> excludes) {
    160         String chosen = Cheeses.sCheeseStrings[mRandom.nextInt(Cheeses.sCheeseStrings.length)];
    161         while (excludes.contains(chosen)) {
    162             chosen = Cheeses.sCheeseStrings[mRandom.nextInt(Cheeses.sCheeseStrings.length)];
    163         }
    164         return chosen;
    165     }
    166 }
    167