diff --git a/app/src/main/java/dummydomain/yetanothercallblocker/CallLogItemRecyclerViewAdapter.java b/app/src/main/java/dummydomain/yetanothercallblocker/CallLogItemRecyclerViewAdapter.java index daa868f..c5e1333 100644 --- a/app/src/main/java/dummydomain/yetanothercallblocker/CallLogItemRecyclerViewAdapter.java +++ b/app/src/main/java/dummydomain/yetanothercallblocker/CallLogItemRecyclerViewAdapter.java @@ -1,5 +1,6 @@ package dummydomain.yetanothercallblocker; +import android.text.TextUtils; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; @@ -9,8 +10,10 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatImageView; +import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; +import java.util.Collections; import java.util.List; import dummydomain.yetanothercallblocker.data.CallLogItem; @@ -22,12 +25,47 @@ public class CallLogItemRecyclerViewAdapter void onListFragmentInteraction(CallLogItem item); } - private final List items; + private static class DiffUtilCallback extends DiffUtil.Callback { + private List oldList; + private List newList; + + DiffUtilCallback(List oldList, List newList) { + this.oldList = oldList; + this.newList = newList; + } + + @Override + public int getOldListSize() { + return oldList.size(); + } + + @Override + public int getNewListSize() { + return newList.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + CallLogItem oldItem = oldList.get(oldItemPosition); + CallLogItem newItem = newList.get(newItemPosition); + + return newItem.type == oldItem.type + && TextUtils.equals(newItem.number, oldItem.number) + && newItem.timestamp == oldItem.timestamp + && newItem.duration == oldItem.duration; + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + return false; // time always updates + } + } + private final @Nullable OnListInteractionListener listener; - public CallLogItemRecyclerViewAdapter(List items, - @Nullable OnListInteractionListener listener) { - this.items = items; + private List items = Collections.emptyList(); + + public CallLogItemRecyclerViewAdapter(@Nullable OnListInteractionListener listener) { this.listener = listener; } @@ -49,6 +87,15 @@ public class CallLogItemRecyclerViewAdapter return items.size(); } + public void setItems(List items) { + DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff( + new DiffUtilCallback(this.items, items)); + + this.items = items; + + diffResult.dispatchUpdatesTo(this); + } + private void onClick(int index) { if (index != RecyclerView.NO_POSITION && listener != null) { listener.onListFragmentInteraction(items.get(index)); diff --git a/app/src/main/java/dummydomain/yetanothercallblocker/MainActivity.java b/app/src/main/java/dummydomain/yetanothercallblocker/MainActivity.java index 4e0897e..ebadb7c 100644 --- a/app/src/main/java/dummydomain/yetanothercallblocker/MainActivity.java +++ b/app/src/main/java/dummydomain/yetanothercallblocker/MainActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; +import android.os.Parcelable; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -12,13 +13,13 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.RecyclerView; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; -import java.util.ArrayList; import java.util.List; import dummydomain.yetanothercallblocker.data.CallLogHelper; @@ -38,7 +39,7 @@ public class MainActivity extends AppCompatActivity { private final UpdateScheduler updateScheduler = UpdateScheduler.get(App.getInstance()); private CallLogItemRecyclerViewAdapter callLogAdapter; - private List callLogItems = new ArrayList<>(); + private RecyclerView recyclerView; private AsyncTask checkMainDbTask; private AsyncTask> loadCallLogTask; @@ -48,10 +49,10 @@ public class MainActivity extends AppCompatActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - callLogAdapter = new CallLogItemRecyclerViewAdapter(callLogItems, this::onCallLogItemClicked); - RecyclerView recyclerView = findViewById(R.id.callLogList); + callLogAdapter = new CallLogItemRecyclerViewAdapter(this::onCallLogItemClicked); + recyclerView = findViewById(R.id.callLogList); recyclerView.setAdapter(callLogAdapter); - recyclerView.addItemDecoration(new CustomVerticalDivider(this)); + recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); } @Override @@ -228,9 +229,12 @@ public class MainActivity extends AppCompatActivity { @Override protected void onPostExecute(List items) { - callLogItems.clear(); - callLogItems.addAll(items); - callLogAdapter.notifyDataSetChanged(); + // workaround for auto-scrolling to first item + // https://stackoverflow.com/a/44053550 + @SuppressWarnings("ConstantConditions") + Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState(); + callLogAdapter.setItems(items); + recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState); setCallLogVisibility(true); }