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