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