从通知启动主屏幕时出现 ANR

Posted

技术标签:

【中文标题】从通知启动主屏幕时出现 ANR【英文标题】:ANR when launching the Home screen from notification 【发布时间】:2021-04-03 19:13:42 【问题描述】:

我对 android 开发的世界还很陌生。我正在处理我们的 android 应用程序中的一个现有问题,到目前为止我还没有修复它。很抱歉问了一个冗长的问题。

在当前的应用程序中,该应用程序旨在跟踪店主是否打开或关闭了商店,我们正在显示一个通知,用户可以单击该通知(当应用程序未在前台打开时)并设置标志“值班”到“值班”。如果用户关闭了定位服务并且用户尝试点击从“Duty Off”到“Duty On”的通知,系统会尝试获取用户的纬度和经度,发出 POST 标注并打开应用主屏幕。当应用程序主屏幕打开时,用户看到应用程序无响应错误。这只发生在用户关闭其位置信息的情况下。

下面是我的代码的 sn-p,它是发生此操作时调用的类,它主要负责 2 个方法 createNotification 和 fun_DutyONOFF。自己google了很多之后,似乎如果BroadcastReceiver没有在10秒内完成,Android就会抛出Application Not Responding (ANR)。但我不确定这里有什么替代方案,如果位置服务关闭,为什么会出现 ANR?任何帮助都可以挽救生命,因为我在这方面花了 3 天没有运气。

public class SwitchButtonListenerON extends BroadcastReceiver 
//Class variable declaration that I have omitted
@Override
    public void onReceive(Context context, Intent intent) 
        if ("dutyON".equalsIgnoreCase(intent.getAction())) 
            SharedPrefrence_Login.getDataLogin(context);
            location_update = new Location_Update(context);
            createNotification(context);
//This is probably the method "fun_DutyONOFF" that takes more time but I am not sure how to replace the work done by this method
            fun_DutyONOFF("1",SharedPrefrence_Login.getMhawker_code(),context);
        
    
private void createNotification(final Context context) 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
        mChannel = new NotificationChannel(CHANNEL_ID, "Hawker", NotificationManager.IMPORTANCE_HIGH);
    
    Intent notificationIntent = new Intent(context, Home.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context,0,notificationIntent,0);

    Intent dutyIntent = new Intent("action.cancel.notification");
    PendingIntent pendingDutyIntent = PendingIntent.getBroadcast(context,0,dutyIntent,PendingIntent.FLAG_UPDATE_CURRENT);
    RemoteViews notificationView = new RemoteViews(context.getPackageName(), R.layout.notification_layout);
    //the intent that is started when the notification is clicked (works)
    Notification notification = new NotificationCompat.Builder(context,CHANNEL_ID)
            .setContentTitle("Location Service")
            .setContentText("")
            .setSmallIcon(R.drawable.ic_business)
            .setContentIntent(pendingIntent)
            .setOngoing(true)
            .build();
    notification.contentView = notificationView;
    notification.contentIntent = pendingDutyIntent;
    notification.flags |= Notification.FLAG_NO_CLEAR;
    notificationView.setOnClickPendingIntent(R.id.closeDuty, pendingDutyIntent);
    NotificationManager mNotificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) 
        mNotificationManager.createNotificationChannel(mChannel);
        mNotificationManager.notify(1 , notification);
    else 
        mNotificationManager.notify(1, notification);
    


private void fun_DutyONOFF(final String sStatus,final String hawker_code,final  Context context) 
    requestQueue = VolleySingleton.getInstance(context).getRequestQueue();
    StringRequest stringRequest = new StringRequest(Request.Method.POST, Urls.URL_DUTY_ON_OFF_SELLER,
            new Response.Listener<String>() 
                @Override
                public void onResponse(String response) 
                    try 
                        // _progressDialog.dismiss();
                        // converting response to json object
                        JSONObject obj = new JSONObject(response);
                        String str = obj.getString("data");
                        JSONObject jsoObject = new JSONObject(str);
                        strStatus  = jsoObject.getString("status");
                        strActive_status = jsoObject.getString("active_status");
                        strActive_msg = jsoObject.getString("active_message");
                        if(strStatus.equals("1"))
                           // System.exit(0);
                            Intent intent = new Intent(context,Home.class);
                            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK );
                            context.startActivity(intent);
                            createNotification(context);
                        

                     catch (JSONException e) 
                        e.printStackTrace();
                    
                
            ,
            new Response.ErrorListener() 
                @Override
                public void onErrorResponse(VolleyError error) 
                    //      _progressDialog.dismiss();
                    if (error.getClass().equals(TimeoutError.class)) 
                        CallbackSnakebarModel.getInstance().SnakebarMessage(context, "It took longer than expected to get the response from Server.",
                                MessageConstant.toast_warning);
                    else 
                        CallbackSnakebarModel.getInstance().SnakebarMessage(context, "Server Respond Error! Try Again Later",
                                MessageConstant.toast_warning);
                          
            ) 
        @Override
        protected Map<String, String> getParams() throws AuthFailureError 
            Map<String, String> params = new HashMap<>();
            params.put("hawker_code", hawker_code);
            params.put("longitude", location_update.LONGITUDE);
            params.put("latitude", location_update.LATTITUDE);
            params.put("duty_status", sStatus);
            params.put("notification_id",SharedPrefrence_Login.getPnotification_id());
            return params;
        
    ;
    stringRequest.setRetryPolicy(new DefaultRetryPolicy(20000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    VolleySingleton.getInstance(context).addToRequestQue(stringRequest);


【问题讨论】:

如果您的应用程序由于 ANR 而崩溃,您应该在 logcat 中有堆栈跟踪和其他错误。请编辑您的问题并将其复制到问题中。 【参考方案1】:

这不是正确的架构。一般来说,BroadcastReceiver 不是为执行大量工作而设计的,而且它绝对不是为执行异步操作而设计的(例如带有回调的网络 I/O)。您不能在主 (UI) 线程上执行网络 I/O,并且 BroadcastReceivers 的生命周期是有限的,因此您也不能使用回调执行异步操作。

正确的架构是使用您的BroadcastReceiver 来启动一个Service,它将在后台运行。然后Service 应该执行网络 I/O 并显示任何必要的Notifications。

请注意,由于对后台处理的严格限制,后台Services 不再允许启动Activity。这是为了防止用户被一些随机的后台处理打断。正确的(用户友好的)方法是让背景Service 简单地显示Notification,通知用户需要他的注意。然后,用户可以在想要查看信息时启动Activity(通过单击“通知”)。

【讨论】:

以上是关于从通知启动主屏幕时出现 ANR的主要内容,如果未能解决你的问题,请参考以下文章

使用 curl 命令发送推送通知时出现无效注册错误

无论应用程序状态如何,都可以从通知中正确启动 Activity

从推送通知解析时出现 SwiftyJson 解析问题

Firebase 通知仅显示在控制中心

使用 GCM 从 java 服务器向 android 手机发送希伯来语推送通知时出现乱码

Xcode 8.0 beta 3 在从通知和计时器访问功能时出现非常有趣的错误