You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android应用ListView删除日历事件后重启恢复延迟问题求助

Android日历事件删除后重复出现的问题分析

问题现象

开发Android应用时,使用ContentResolver删除日历事件后,ListView能即时刷新显示删除效果,但重新打开ListView时,已删除的事件会再次出现,需延迟数分钟才会被永久删除。尝试使用单例ContentResolver后问题仍未解决。

相关代码

Calendar_ListView.java

package com.example.eventhub;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;

import java.util.ArrayList;

public class Calendar_ListView extends AppCompatActivity {
    public ArrayList<String> Events_Name = new ArrayList<String>();
    public ArrayList<String> temporary = new ArrayList<String>();
    ArrayAdapter arrayAdapter;

    Utility utility;

    Context context;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.reminder_list_view);

        context = getApplicationContext();
        utility = new Utility(context);

        RelativeLayout relativeLayout = findViewById(R.id.ListId);
        AnimationDrawable animationDrawable = (AnimationDrawable) relativeLayout.getBackground();
        animationDrawable.setEnterFadeDuration(3500);
        animationDrawable.setExitFadeDuration(5500);
        animationDrawable.start();
        ListView listview = findViewById(R.id.listview);

        arrayAdapter = new ArrayAdapter(Calendar_ListView.this, R.layout.listview_custom_itemview, temporary);

        listview.setAdapter(arrayAdapter);
        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                AlertDialog.Builder builder = new AlertDialog.Builder(Calendar_ListView.this);
                builder.setMessage("Do you want to delete this reminder?")
                        .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                utility.deleteEventByTitle2(context, Events_Name.get(position));
                                Log.d("FETCH", Events_Name.toString());
                                Log.d("FETCH", temporary.toString());
                                arrayAdapter.remove(arrayAdapter.getItem(position));
                            }
                        })
                        .setNegativeButton("No", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.dismiss();
                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });

    }
    @Override
    protected void onResume() {
        super.onResume();
        Fetch_EventNames();
        Log.d("LISTVIEW", Events_Name.toString());
        arrayAdapter.notifyDataSetChanged();
    }
    public void Fetch_EventNames(){
        utility.readCalendarEvent(context);
        Events_Name.clear();
        temporary.clear();
        ArrayList<String> titles = utility.nameOfEvent;
        ArrayList<String> myEvents = new ArrayList<String>();
        for(String str : titles){
            if(str != null && str.length() > 3 && str.substring(str.length() - 3).equals("_eh")){
                myEvents.add(str);
            }
        }
        Events_Name = myEvents;
        for(String str : Events_Name){
            temporary.add(str.substring(0, str.length()-3));
        }
    }
}

Utility.java

package com.example.eventhub;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.util.Log;
import android.widget.Toast;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;

public class Utility {
    public ArrayList<String> nameOfEvent = new ArrayList<String>();
    public ArrayList<ArrayList<String>> Event_Start_End = new ArrayList<ArrayList<String>>();

    public ArrayList<String> startDates = new ArrayList<String>();
    public ArrayList<String> endDates = new ArrayList<String>();
    public ArrayList<String> descriptions = new ArrayList<String>();
    public ArrayList<String> eventIds = new ArrayList<String>();
    ContentResolver resolver;
    public Utility(Context context){
        resolver = context.getContentResolver();
    }

    public ArrayList<String> readCalendarEvent(Context context) {
        Cursor cursor = resolver
                .query(
                        Uri.parse("content://com.android.calendar/events"),
                        new String[]{"calendar_id", "title", "description",
                                "dtstart", "dtend", "eventLocation"}, null,
                        null, null);
        cursor.moveToFirst();
        String CNames[] = new String[cursor.getCount()];

        nameOfEvent.clear();
        startDates.clear();
        endDates.clear();
        descriptions.clear();
        Log.d("UTILITY_OBJ", "SIZE: "+ Integer.toString(cursor.getCount()));

        for (int i = 0; i < CNames.length; i++) {
            nameOfEvent.add(cursor.getString(1));

            if(cursor.getString(3) != null){
                startDates.add(getDate(Long.parseLong(cursor.getString(3))));

            }
            if(cursor.getString(4) != null){
                endDates.add(getDate(Long.parseLong(cursor.getString(4))));
            }
            descriptions.add(cursor.getString(2));
            CNames[i] = cursor.getString(1);
            cursor.moveToNext();
        }
        return nameOfEvent;
    }
    public void deleteEventByTitle(Context context, String title) {
        Cursor cursor = resolver.query(
                Uri.parse("content://com.android.calendar/events"),
                new String[]{"_id"},
                "title=?",
                new String[]{title},
                null);

        if (cursor.moveToFirst()) {
            int temp = cursor.getColumnIndex("_id");
            long id;
            if(temp >= 0) {
                id = cursor.getLong(temp);
                Uri deleteUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
                int rows = resolver.delete(deleteUri, null, null);

                Log.d("UTILITY_OBJ", "Rows deleted: " + rows);
                Toast.makeText(context, "Event Successfully Deleted", Toast.LENGTH_SHORT).show();

            }
            else {
                Log.d("UTILITY_OBJ", "EVENT ID NOT FOUND");
                Toast.makeText(context, "Event NOT FOUND!!", Toast.LENGTH_SHORT).show();
            }
        }
        else {
            Log.d("UTILITY_OBJ", "EVENT ID NOT FOUND");
            Toast.makeText(context, "Event NOT FOUND!!", Toast.LENGTH_SHORT).show();
        }
        cursor.close();
    }

    public String getDate(long milliSeconds) {
        SimpleDateFormat formatter = new SimpleDateFormat(
                "dd/MM/yyyy hh:mm:ss a");
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(milliSeconds);
        return formatter.format(calendar.getTime());
    }
    public ArrayList<String> readCalendarEvent2(Context context) {
        Cursor cursor = context.getContentResolver().query(
                Uri.parse("content://com.android.calendar/events"),
                new String[]{"_id", "calendar_id", "title", "description",
                        "dtstart", "dtend", "eventLocation"}, null, null, null);
        cursor.moveToFirst();
        String CNames[] = new String[cursor.getCount()];

        nameOfEvent.clear();
        startDates.clear();
        endDates.clear();
        descriptions.clear();
        eventIds.clear();
        Log.d("UTILITY_OBJ", "SIZE: "+ Integer.toString(cursor.getCount()));

        for (int i = 0; i < CNames.length; i++) {
            eventIds.add(cursor.getString(0));
            nameOfEvent.add(cursor.getString(2));
            if(cursor.getString(4) != null){
                startDates.add(getDate(Long.parseLong(cursor.getString(4))));
            }
            if(cursor.getString(5) != null){
                endDates.add(getDate(Long.parseLong(cursor.getString(5))));
            }
            descriptions.add(cursor.getString(3));
            CNames[i] = cursor.getString(2);
            cursor.moveToNext();
        }
        return nameOfEvent;
    }

    public void deleteEventByTitle2(Context context, String title) {
        Cursor cursor = resolver.query(
                Uri.parse("content://com.android.calendar/events"),
                new String[]{"_id"},
                "title=?",
                new String[]{title},
                null);

        ArrayList<String> eventsToDelete = new ArrayList<String>();

        if (cursor.moveToFirst()) {
            int temp = cursor.getColumnIndex("_id");
            long id;
            if(temp >= 0) {
                id = cursor.getLong(temp);
                eventsToDelete.add(title);
                Uri deleteUri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, id);
                int rows = resolver.delete(deleteUri, null, null);

                Log.d("UTILITY_OBJ", "Rows deleted: " + rows);
                Toast.makeText(context, "Event Successfully Deleted", Toast.LENGTH_SHORT).show();

            }
            else {
                Log.d("UTILITY_OBJ", "EVENT ID NOT FOUND");
                Toast.makeText(context, "Event NOT FOUND!!", Toast.LENGTH_SHORT).show();
            }
        }
        else {
            Log.d("UTILITY_OBJ", "EVENT ID NOT FOUND");
            Toast.makeText(context, "Event NOT FOUND!!", Toast.LENGTH_SHORT).show();
        }
        cursor.close();

        for (String event : eventsToDelete) {
            nameOfEvent.remove(event);
        }
    }

}

可能的原因及解决方案

1. 日历系统同步延迟

Android日历会与云端账户同步,本地执行删除后,系统需要时间完成本地与云端的同步,在此期间查询会读取未更新的缓存数据。

解决方案:
删除事件后主动通知ContentResolver数据变化,触发系统更新缓存:

// 在deleteEventByTitle2方法的resolver.delete之后添加
resolver.notifyChange(CalendarContract.Events.CONTENT_URI, null);

2. ContentResolver查询缓存

ContentResolver默认会缓存查询结果,短时间内重新查询可能返回旧数据。

解决方案:
查询时添加参数禁用缓存:

Bundle queryArgs = new Bundle();
queryArgs.putBoolean(ContentResolver.QUERY_ARG_NO_CURSOR_COPY, true);
Cursor cursor = resolver.query(
    CalendarContract.Events.CONTENT_URI,
    new String[]{"calendar_id", "title", "description", "dtstart", "dtend", "eventLocation"},
    queryArgs,
    null
);

3. 标题删除的不可靠性

当前通过标题匹配删除事件,若存在同名事件,仅会删除第一个匹配项,其余同名事件仍会保留,导致重新查询时再次出现。

解决方案:
优先通过事件ID删除:

  1. 读取事件时保存ID:在readCalendarEvent方法中添加事件ID的存储
  2. 删除时直接通过ID定位,替代标题匹配逻辑

4. 硬编码日历URI问题

代码中使用硬编码的content://com.android.calendar/events,不同厂商/版本的日历URI可能存在差异,导致删除操作未作用到正确数据源。

解决方案:
使用官方提供的CalendarContract.Events.CONTENT_URI替代硬编码URI,确保兼容性。

5. 权限验证缺失

若未正确申请并获取WRITE_CALENDAR权限,删除操作可能未真正执行,仅修改了本地列表,重新查询时会从日历读取原数据。

解决方案:
在Manifest中添加权限:

<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />

并在运行时动态申请权限。


内容的提问来源于stack exchange,提问作者Pratham Koli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 00:44:52