android - 当我使用 LiveData 观察 dataList 时,通过服务 RecyclerView 调用 API 时出现故障
问题描述
我必须实时显示数据。所以我创建了一个服务并添加了一个计时器。我每 1 分钟访问一次 Rest API 并将数据存储在 room-Bb 中。
问题:在调用服务的每一分钟后,我的适配器会被重置,并且我的 recyclerView 每隔一分钟就会一次又一次地闪烁,即使我滚动了一个列表,我也会到达列表的顶部。
在我的活动中,这是我的片段的基础,我称之为 MySimpleService 。在服务中,我使用计时器每隔一分钟调用一次我的 API,以检查我是否有任何新预订。每当调用我的 API 时,我的列表都会更新,并且我的 Recyclerview 适配器会由于我的适配器中的 setBookingData 方法中的 notifydatasetchanged() 而重置。所以我的 recyclerView 每隔一分钟就会闪烁一次。
这是我的代码
我的简单服务
public class MySimpleService extends Service {
private static final String TAG = "MyTag";
private Timer mTimer;
private Handler mHandler = new Handler();
private static final int TIMER_INTERVAL = 10000; // 1 Minute
private static final int TIMER_DELAY = 0;
private MyDatabase appDatabase;
@Override
public void onCreate() {
super.onCreate();
appDatabase = MyDatabase.getInstance(getApplicationContext());
Log.d(TAG, "MySimpleService onCreate: ");
if (mTimer != null)
mTimer = null;
// Create new Timer
mTimer = new Timer();
// Required to Schedule DisplayToastTimerTask for repeated execution with an interval of `1 min`
mTimer.scheduleAtFixedRate(new DisplayToastTimerTask(), TIMER_DELAY, TIMER_INTERVAL);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "MySimpleService onStartCommand: ");
return Service.START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "My Service onDestroy: ");
// Cancel timer
mTimer.cancel();
}
private class DisplayToastTimerTask extends TimerTask {
@Override
public void run() {
mHandler.post(() -> {
if (Utils.getConnectivityStatus(getApplicationContext()) == 0) {
Utils.showOkAlert(getApplicationContext(), getString(R.string.info), "Please check your internet connection", false);
} else {
new Thread(() -> callApbookingList()).start();
new Thread(() -> callApiAssignList()).start();
new Thread(() -> callApiBookingActivitiesList()).start();
}
});
}
}
private void callApbookingList() {
RetrofitApiInterface apiInterface = RetrofitClient.getClient().create(RetrofitApiInterface.class);
Call<BookingDataResponse> call = apiInterface.getAllData(new PostContData(PreferenceData.getLong(getApplicationContext(), "cont_id")));
call.enqueue(new Callback<BookingDataResponse>() {
@Override
public void onResponse(Call<BookingDataResponse> call, Response<BookingDataResponse> response) {
if (response.isSuccessful()) {
BookingDataResponse body = response.body();
appDatabase.myDao().deleteBookingList();
if (body.getStatus() == 0) {
Log.d(TAG, "onResponse: " + body.getMessage());
new Thread(() -> {
try {
appDatabase.myDao().insertBooking(body.getBookingList());
} catch (Exception e) {
}
}).start();
}
}
}
@Override
public void onFailure(Call<BookingDataResponse> call, Throwable t) {
Log.e(TAG, "onFailure: " + t);
}
});
}
我的片段
public class BookingAssignFragment extends Fragment {
private BookingViewModel bookingViewModel;
private BookingListAdepter bookingListAdepter;
public BookingAssignFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_booking_assign, container, false);
bookingListAdepter = new BookingListAdepter(getActivity());
RecyclerView recyclerView = view.findViewById(R.id.rev_booking_list);
TextView errorMessasge = view.findViewById(R.id.error_message);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(bookingListAdepter);
bookingViewModel = new ViewModelProvider(getActivity()).get(BookingViewModel.class);
bookingViewModel.getBooking().observe(getActivity(), bookingLists -> {
if (bookingLists.isEmpty()) {
if (errorMessasge.getVisibility() == View.GONE)
errorMessasge.setVisibility(View.VISIBLE);
} else {
if (errorMessasge.getVisibility() == View.VISIBLE)
errorMessasge.setVisibility(View.GONE);
// bookingListAdepter.setBookingData(bookingLists);
}
bookingListAdepter.setBookingData(bookingLists);
});
return view;
}
}
我的适配器
public class BookingListAdepter extends RecyclerView.Adapter<BookingListAdepter.BookingViewHolder> {
private List<BookingList> bookingLists;
private LayoutInflater mInflater;
private Context mContext;
public BookingListAdepter(Context context) {
mInflater = LayoutInflater.from(context);
mContext =context;
}
@NonNull
@Override
public BookingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_view_booking_list, parent, false);
return new BookingViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull BookingViewHolder holder, int position) {
BookingList li = bookingLists.get(position);
if(li.getPlanType().equalsIgnoreCase("Both Way")){
if (holder.numberOfDay.getVisibility()==View.GONE) {
holder.numberOfDay.setVisibility(View.VISIBLE);
holder.numberOfDay.setText(String.valueOf(li.getBookingDays()));
}
}else {
if (holder.numberOfDay.getVisibility()==View.VISIBLE)
holder.numberOfDay.setVisibility(View.GONE);
}
if (li.getPlanType().equals(li.getTerrifType())){
if (holder.palanTyupe.getVisibility()==View.VISIBLE)
holder.palanTyupe.setVisibility(View.GONE);
}else { if (holder.palanTyupe.getVisibility()==View.GONE)
holder.palanTyupe.setVisibility(View.VISIBLE);}
holder.packageName.setText(li.getPlanType());
holder.cabCategory.setText(li.getCabCategory());
holder.dateTime.setText(li.getDatetime());
holder.formLocation.setText(li.getFromLocation());
holder.toLocation.setText(li.getToLocation());
holder.amount.setText(String.valueOf(li.getTotalAmount()));
holder.paidWalletAmount.setText(String.valueOf(li.getPaidWalletAmount()));
holder.assignBooking.setOnClickListener(v -> {
if (Utils.getConnectivityStatus(mContext) == 0) {
Utils.showOkAlert(mContext,mContext.getString(R.string.info), "Please check your internet connection", false);
}else {
BookingAssignDialogFragment updateDriver = BookingAssignDialogFragment.newInstance(li.getBookingId(), PreferenceData.getLong(mContext,"cont_id"),0,"");
updateDriver.show((Activity) mContext);
}
});
}
@Override
public int getItemCount() {
if (bookingLists!=null)
return bookingLists.size();
else return 0;
}
public void setBookingData(List<BookingList> bookingData) {
bookingLists = bookingData;
Log.d("UpdatedBooking", String.valueOf(bookingLists.size()));
notifyDataSetChanged();
}
class BookingViewHolder extends RecyclerView.ViewHolder{
TextView packageName,palanTyupe,cabCategory,amount,formLocation,toLocation,dateTime,numberOfDay,paidWalletAmount;
ImageView assignBooking,acceptBooking;
public BookingViewHolder(@NonNull View itemView) {
super(itemView);
packageName = itemView.findViewById(R.id.package_name);
palanTyupe = itemView.findViewById(R.id.plan_type);
cabCategory = itemView.findViewById(R.id.cab_category);
amount = itemView.findViewById(R.id.amount);
formLocation = itemView.findViewById(R.id.from_location);
toLocation = itemView.findViewById(R.id.to_location);
dateTime = itemView.findViewById(R.id.date_and_time);
numberOfDay = itemView.findViewById(R.id.no_of_day);
assignBooking = itemView.findViewById(R.id.assign_booking);
paidWalletAmount = itemView.findViewById(R.id.paid_wallet_amount);
acceptBooking =itemView.findViewById(R.id.accept_booking);
}
}
}
我的视图模型
public class BookingActivitiesListViewModel extends AndroidViewModel {
private BookingActivitiesListRepository bookingActivitiesListRepository;
private LiveData<List<BookingActivitiesList>> mLiveData;
public BookingActivitiesListViewModel(@NonNull Application application) {
super(application);
bookingActivitiesListRepository = new BookingActivitiesListRepository(application);
mLiveData = bookingActivitiesListRepository.getBookingActivitiesList();
}
public LiveData<List<BookingActivitiesList>> getBookingActivitiesList()
{
return mLiveData;
}
}
我的仓库
public class BookingRepository {
private MyDao myDao;
private LiveData<List<BookingList>> mBookingList;
BookingRepository(Application application){
MyDatabase db = MyDatabase.getInstance(application);
myDao = db.myDao();
mBookingList = myDao.getBookingList();
}
LiveData<List<BookingList>> getBooking(){return mBookingList;}
我的 item_view_booking_list
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardUseCompatPadding="true"
android:elevation="5dp"
app:cardCornerRadius="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
style="@style/ItemViewStyle"
android:weightSum="1">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight=".85">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_location_form_24dp"
android:drawablePadding="@dimen/dp5"
android:padding="5dp"
android:layout_weight="1"
android:id="@+id/from_location"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_location_to_24dp"
android:drawablePadding="@dimen/dp5"
android:layout_weight="1"
android:padding="5dp"
android:id="@+id/to_location"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:padding="5dp"
android:gravity="left|center"
android:drawableLeft="@drawable/ic_car"
android:drawablePadding="@dimen/dp5"
android:id="@+id/cab_category"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_work_black_24dp"
android:drawablePadding="@dimen/dp5"
android:layout_weight="1"
android:gravity="center|left"
android:padding="5dp"
android:id="@+id/package_name"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="2560"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_rupee_indian"
android:drawablePadding="@dimen/dp5"
android:padding="5dp"
android:gravity="left|center"
android:id="@+id/amount"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center|left"
android:drawableLeft="@drawable/wallet"
android:drawablePadding="@dimen/dp5"
android:layout_weight="1"
android:padding="5dp"
android:id="@+id/paid_wallet_amount"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="match_parent"
android:padding="5dp"
android:layout_weight="1"
android:layout_gravity="center"
android:textStyle="bold"
android:drawableLeft="@drawable/ic_access_time_black_24dp"
android:drawablePadding="@dimen/dp5"
android:layout_height="wrap_content"
android:id="@+id/date_and_time"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableLeft="@drawable/ic_date_range_black_24dp"
android:layout_gravity="center"
android:drawablePadding="@dimen/dp5"
android:visibility="gone"
android:padding="5dp"
android:id="@+id/no_of_day"/>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="plan type"
android:layout_gravity="center"
android:gravity="center|left"
android:drawableLeft="@drawable/ic_work_black_24dp"
android:drawablePadding="@dimen/dp5"
android:layout_weight="1"
android:padding="5dp"
android:id="@+id/plan_type"/>
</LinearLayout>
<ImageView
android:layout_width="0dp"
android:layout_weight=".15"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_send_black_24dp"
android:id="@+id/assign_booking"
android:visibility="visible"
android:scaleType="centerInside"/>
<ImageView
android:layout_width="0dp"
android:layout_weight=".15"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/check_black"
android:visibility="gone"
android:id="@+id/accept_booking"
android:scaleType="centerInside"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
我的 fragment_booking_assign xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.booking.assigned.UnassignedBooking.BookingAssignFragment">
<!-- TODO: Update blank fragment layout -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rev_booking_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:layout_marginBottom="@dimen/dp20"
android:scrollbarSize="@dimen/dp15"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/data_not_available"
android:id="@+id/error_message"
android:visibility="gone"
android:layout_centerInParent="true"
android:textColor="@color/red"
android:textSize="@dimen/dimen_26dp"/>
</RelativeLayout>
解决方案
更新
在本地尝试代码后,我无法重现您的问题,唯一不同的是我模拟了数据并且没有使用该服务。因此,我再次查看了您的服务课程,我想我发现了问题。在您的服务类中,在成功请求新数据后,您可以:
appDatabase.myDao().deleteBookingList();
当您的mBookingList
liveData 被更新时myDao
(正如您在存储库中声明的那样),这将导致mBookingList
使用空列表进行更新,因此 recyclerView 会很快重置为空 == 闪烁。紧接着,你用新数据填充你的 DAO,即mBookingList
用新数据更新你的,导致用新数据填充当前空的 recyclerView == 看似滚动到顶部(但实际上发生的事情只是从空数据变为完整数据)。
因此,要解决您的问题,请提出更新您的数据库而不是清除它并重新填充的实现,或者如果传入的数据集为空,则避免为您的 recyclerView 设置数据。
推荐阅读
- selenium-webdriver - 我正在尝试在 selenium webdriver 中上传文件,因为 selenium 正在选择要上传的文件,但无法单击上传按钮
- vba - 通过 iCalendar 转发信息减少的约会
- flutter - 未找到使用颤振中的mailto链接处理意图错误的活动
- java - 需要加快条件复制属性操作
- python - 如何从 s3 存储桶在 lambda 函数中输入 ttf 文件?
- javascript - 使用javascript检测单词中的哪个字母被点击
- nginx - Nginx 入口:基于主机的 TCP 端口路由
- javascript - 如何从嵌套数组中仅获取布尔值
- node.js - 定义一个 mongodb 集合架构来定义用户、角色及其权限
- sql - SQL - 如果列为空,则列出所有数据