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

Android列表显示服务器新增项时触发本地通知的问题求助

问题解决:服务器新增事件时触发本地通知,避免启动Activity时重复弹出

问题分析

你当前的代码存在几个核心问题导致通知异常弹出:

  • 循环逻辑错误:for(int i = result.items.data.size(); i <= result.items.data.size(); i++) 这个循环仅执行一次,且i > result.items.data.size()的判断永远不成立,同时你初始化了空的Event item,通知内容会为空
  • 未区分新增事件和已有事件:每次启动Activity拉取数据时,没有判断哪些是服务器新增的,导致只要有数据就可能触发通知逻辑
  • 通知触发条件错误:没有基于“新事件”的判断逻辑,而是错误的循环条件触发

解决方案

要实现仅在服务器新增事件时触发通知,核心是记录本地已处理过的最新事件ID,每次拉取数据后对比筛选出新增事件,再针对这些事件发送通知。

步骤1:本地存储最新事件ID

使用SharedPreferences存储最后一次处理的最大事件ID,用来区分新旧事件。

步骤2:拉取数据后筛选新增事件

在Retrofit的success回调中,对比服务器返回的事件ID和本地存储的ID,找出所有ID更大的事件(即新增事件)。

步骤3:对新增事件发送通知

仅针对新增事件构建并发送通知,同时更新本地存储的最大ID。

步骤4:修正ListView的30条限制逻辑

确保ListView最多显示30条,新增项加入时移除最早的项。

修改后的代码示例

1. EventsActivity修改

public class EventsActivity extends AppCompatActivity
{
    @Bind(R.id.back) View back;
    @Bind(R.id.list) ListView list;
    @Bind(R.id.clearAllEvents) View clearAllEvents;
    @Bind(R.id.content_layout) View content_layout;
    @Bind(R.id.loading_layout) View loading_layout;
    @Bind(R.id.nodata_layout) View nodata_layout;
    @Bind(R.id.search) View search;
    String searchtext;
    private SharedPreferences prefs;
    private static final String KEY_LAST_EVENT_ID = "last_event_id";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_events);
        ButterKnife.bind(this);
        prefs = getSharedPreferences("EventPrefs", MODE_PRIVATE);

        final String api_key = (String) DataSaver.getInstance(EventsActivity.this).load("api_key");
        final EventsAdapter adapter = new EventsAdapter(this);
        list.setAdapter(adapter);

        loading_layout.setVisibility(View.VISIBLE);
        API.getApiInterface(this).getEvents(api_key, getResources().getString(R.string.lang), 0, new Callback<ApiInterface.GetEventsResult>() {
            @Override
            public void success(ApiInterface.GetEventsResult result, Response response)
            {
                loading_layout.setVisibility(View.GONE);
                if(result.items.data.size() != 0) {
                    content_layout.setVisibility(View.VISIBLE);
                    // 处理ListView最多30条逻辑:保留最新的30条,移除旧项
                    ArrayList<Event> events = result.items.data;
                    if(events.size() > 30) {
                        events = new ArrayList<>(events.subList(0, 30));
                    }
                    adapter.setArray(events);

                    // 处理新增事件通知
                    processNewEvents(events);
                } else {
                    nodata_layout.setVisibility(View.VISIBLE);
                }
            }

            @Override
            public void failure(RetrofitError retrofitError) {
                Toast.makeText(EventsActivity.this, R.string.errorHappened, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void processNewEvents(ArrayList<Event> events) {
        int lastProcessedId = prefs.getInt(KEY_LAST_EVENT_ID, 0);
        int newMaxId = lastProcessedId;

        // 遍历事件,筛选出新增的(ID大于本地记录的最后ID)
        for(Event event : events) {
            if(event.id > lastProcessedId) {
                sendEventNotification(event);
                // 更新最大ID
                if(event.id > newMaxId) {
                    newMaxId = event.id;
                }
            }
        }

        // 更新本地存储的最新事件ID
        if(newMaxId != lastProcessedId) {
            prefs.edit().putInt(KEY_LAST_EVENT_ID, newMaxId).apply();
        }
    }

    private void sendEventNotification(Event event) {
        String channelId = "notification_channel_1";
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // 创建Android O及以上的通知渠道
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            if(notificationManager != null && notificationManager.getNotificationChannel(channelId) == null){
                NotificationChannel notificationChannel = new NotificationChannel(
                        channelId, "事件通知", NotificationManager.IMPORTANCE_HIGH
                );
                notificationChannel.setDescription("服务器新增事件通知");
                notificationChannel.enableLights(true);
                notificationChannel.enableVibration(true);
                notificationManager.createNotificationChannel(notificationChannel);
            }
        }

        // 构建通知跳转Intent
        Intent intent = new Intent(this, EventsActivity.class);
        intent.putExtra("event", new Gson().toJson(event));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
                event.id, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);

        // 构建通知内容
        NotificationCompat.Builder builder = new NotificationCompat.Builder(
                getApplicationContext(), channelId
        );
        builder.setSmallIcon(R.drawable.ic_notification_original);
        builder.setDefaults(NotificationCompat.DEFAULT_ALL);
        builder.setContentTitle("GPSTrackr");
        builder.setContentText(String.format("%s: %s", event.device_name, event.message));
        builder.setContentIntent(pendingIntent);
        builder.setAutoCancel(true);
        builder.setPriority(NotificationCompat.PRIORITY_MAX);

        // 发送通知,用事件ID作为通知ID避免重复覆盖
        if (notificationManager != null) {
            notificationManager.notify(event.id, builder.build());
        }
    }
}

2. EventsAdapter修改(简化数组处理逻辑)

public class EventsAdapter extends AwesomeAdapter<Event> {
    public EventsAdapter(Context context) {
        super(context);
    }

    @Override
    public void setArray(ArrayList<Event> array) {
        super.setArray(array);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView == null)
            convertView = getLayoutInflater().inflate(R.layout.adapter_events, null);

        Event item = getItem(position);
        TextView device_name = (TextView) convertView.findViewById(R.id.device_name);
        device_name.setText(item.device_name);
        TextView date = (TextView) convertView.findViewById(R.id.date);
        date.setText(item.time);
        TextView message = (TextView) convertView.findViewById(R.id.message);
        message.setText(item.message);
        TextView geofence_name = (TextView) convertView.findViewById(R.id.geofence_name);
        geofence_name.setText(item.geofence_name);

        return convertView;
    }
}

关键优化点

  • 用SharedPreferences记录已处理的最大事件ID,确保仅对新增事件发送通知
  • 修正通知逻辑:使用事件ID作为通知ID,避免重复通知被覆盖,同时传递正确的事件数据
  • 完善ListView的30条限制逻辑:当返回数据超过30条时,只保留最新的30条
  • 移除无效的循环和错误的条件判断,简化通知触发逻辑

内容的提问来源于stack exchange,提问作者Leyoussi Lauriel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 09:31:04