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

Android Widget刷新按钮真机无响应及Toast失效问题求助

问题排查与修复方案

一、真机刷新按钮无响应问题

核心原因

  1. PendingIntent标记不符合高版本要求:Android 12(API 31)及以上系统要求创建PendingIntent时必须指定FLAG_IMMUTABLE或FLAG_MUTABLE,原代码中使用0作为标记,在高版本真机上会导致广播无法触发。
  2. RemoteViews更新顺序错误:先执行耗时的爬取操作,再绑定点击事件并更新Widget,可能导致点击事件未及时生效;且最后调用空的updateAppWidget方法会覆盖已设置的点击事件。
  3. 静态变量引发多Widget冲突:全局静态变量alturaNueva等会在多个Widget实例间互相覆盖,导致数据异常。

修复步骤

  1. 修正PendingIntent标记
    在创建PendingIntent时添加版本适配的标记:

    import android.os.Build;
    
    // 替换原PendingIntent创建代码
    int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
    PendingIntent pendingSync = PendingIntent.getBroadcast(context, 0, intentSync, flags);
    
  2. 调整onUpdate执行顺序
    先绑定点击事件并更新Widget,再执行数据爬取,移除无用的空方法调用:

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        for (int appWidgetId : appWidgetIds) {
            RemoteViews remoteV = new RemoteViews(context.getPackageName(), R.layout.altura_rio_widget);
            Intent intentSync = new Intent(context, AlturaRioWidget.class);
            intentSync.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
            
            int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
            PendingIntent pendingSync = PendingIntent.getBroadcast(context, 0, intentSync, flags);
            remoteV.setOnClickPendingIntent(R.id.refresh, pendingSync);
            
            // 先绑定点击事件再更新Widget
            appWidgetManager.updateAppWidget(appWidgetId, remoteV);
            // 再执行数据爬取
            LoadDataRio(context, appWidgetManager, appWidgetId);
        }
    }
    
  3. 替换静态变量为局部变量
    在LoadDataRio中使用局部变量存储爬取结果,避免多Widget冲突,同时更新数据后重新绑定点击事件(防止被覆盖):

    public void LoadDataRio(Context context, AppWidgetManager appWidgetManager, int appWidgetId){
        CountDownLatch latch = new CountDownLatch(1);
        // 使用数组存储局部变量(线程内可修改)
        final String[] alturaNueva = new String[1];
        final String[] variacionNueva = new String[1];
        final String[] fechaNueva = new String[1];
    
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Document doc = Jsoup.connect(url).get();
                    Element row = doc.select("tr:contains(SANTA FE):not(:contains(San Javier))").first();
                    alturaNueva[0] = row.select("[data-label=Ultimo Registro:]").text();
                    variacionNueva[0] = row.select("[data-label=Variacion]").text();
                    fechaNueva[0] = row.select("[data-label=Fecha Hora:]").text();
                    Log.i("hola","data");
                    latch.countDown();
                } catch (IOException e) {
                    Log.i("Error", e.getMessage() + " ERRORRR");
                }
            }
        }).start();
    
        try {
            latch.await();
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.altura_rio_widget);
            views.setTextViewText(R.id.altura_tv, alturaNueva[0]);
            views.setTextViewText(R.id.variacion_tv, variacionNueva[0]);
            
            String replaceFecha = fechaNueva[0].replace("/24"," ");
            String replaceFecha2 = replaceFecha.replace("/","-").replace(" ","");
            String fechaEdit = replaceFecha2.substring(0,9)+":"+replaceFecha2.substring(9,11);
            views.setTextViewText(R.id.fecha_tv, fechaEdit);
    
            // 重新绑定点击事件,防止更新数据后丢失
            Intent intentSync = new Intent(context, AlturaRioWidget.class);
            intentSync.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
            int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
            PendingIntent pendingSync = PendingIntent.getBroadcast(context, 0, intentSync, flags);
            views.setOnClickPendingIntent(R.id.refresh, pendingSync);
    
            appWidgetManager.updateAppWidget(appWidgetId, views);
            Log.i("hola","seteos");
        } catch (InterruptedException e ) {
            Thread.currentThread().interrupt();
            Log.i("Error", e.getMessage() + " ERRORRR");
        }
    }
    

二、Toast消息不显示问题

核心原因

AppWidgetProvider运行在系统广播接收器进程中,使用普通Toast时,由于上下文不是前台Activity上下文,且未在主线程执行,导致Toast无法显示;而Log不受进程限制,可正常输出。

修复方案

方案1:使用Notification替代Toast(推荐)

Notification是后台组件的标准提示方式,适配所有系统版本:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import androidx.core.app.NotificationCompat;

// 在需要提示的位置添加(比如爬取成功/失败时)
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel("WIDGET_CHANNEL", "Widget更新提示", NotificationManager.IMPORTANCE_LOW);
    notificationManager.createNotificationChannel(channel);
}

NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "WIDGET_CHANNEL")
        .setSmallIcon(R.drawable.ic_pesca)
        .setContentTitle("数据更新")
        .setContentText("数据更新完成")
        .setPriority(NotificationCompat.PRIORITY_LOW)
        .setAutoCancel(true);
notificationManager.notify(1, builder.build());

方案2:强制在主线程显示Toast

如果坚持使用Toast,需通过Handler切换到主线程:

import android.os.Looper;
import android.os.Handler;

// 在需要显示Toast的位置添加
new Handler(Looper.getMainLooper()).post(() -> {
    Toast.makeText(context.getApplicationContext(), "数据更新完成", Toast.LENGTH_SHORT).show();
});

额外优化建议

避免使用CountDownLatch阻塞主线程,改用Coroutine异步爬取数据,防止ANR:

// 添加依赖:implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
import kotlinx.coroutines.CoroutineScope;
import kotlinx.coroutines.Dispatchers;
import kotlinx.coroutines.Job;
import kotlinx.coroutines.launch;
import kotlinx.coroutines.withContext;

public void LoadDataRio(Context context, AppWidgetManager appWidgetManager, int appWidgetId){
    CoroutineScope scope = CoroutineScope(Dispatchers.IO + Job());
    scope.launch {
        try {
            Document doc = Jsoup.connect(url).get();
            Element row = doc.select("tr:contains(SANTA FE):not(:contains(San Javier))").first();
            String altura = row.select("[data-label=Ultimo Registro:]").text();
            String variacion = row.select("[data-label=Variacion]").text();
            String fecha = row.select("[data-label=Fecha Hora:]").text();

            // 切换到主线程更新Widget
            withContext(Dispatchers.Main) {
                RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.altura_rio_widget);
                views.setTextViewText(R.id.altura_tv, altura);
                views.setTextViewText(R.id.variacion_tv, variacion);
                
                String replaceFecha = fecha.replace("/24"," ");
                String replaceFecha2 = replaceFecha.replace("/","-").replace(" ","");
                String fechaEdit = replaceFecha2.substring(0,9)+":"+replaceFecha2.substring(9,11);
                views.setTextViewText(R.id.fecha_tv, fechaEdit);

                // 绑定点击事件
                Intent intentSync = new Intent(context, AlturaRioWidget.class);
                intentSync.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
                int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
                PendingIntent pendingSync = PendingIntent.getBroadcast(context, 0, intentSync, flags);
                views.setOnClickPendingIntent(R.id.refresh, pendingSync);

                appWidgetManager.updateAppWidget(appWidgetId, views);
                Log.i("hola","seteos");
            }
        } catch (IOException e) {
            Log.i("Error", e.getMessage() + " ERRORRR");
            withContext(Dispatchers.Main) {
                // 显示错误通知
                NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    NotificationChannel channel = new NotificationChannel("WIDGET_CHANNEL", "Widget更新提示", NotificationManager.IMPORTANCE_LOW);
                    notificationManager.createNotificationChannel(channel);
                }
                NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "WIDGET_CHANNEL")
                        .setSmallIcon(R.drawable.ic_pesca)
                        .setContentTitle("更新失败")
                        .setContentText(e.getMessage())
                        .setPriority(NotificationCompat.PRIORITY_LOW)
                        .setAutoCancel(true);
                notificationManager.notify(1, builder.build());
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Nacho Mascherpa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 22:45:55