从通知启动主屏幕时出现 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,并且 BroadcastReceiver
s 的生命周期是有限的,因此您也不能使用回调执行异步操作。
正确的架构是使用您的BroadcastReceiver
来启动一个Service
,它将在后台运行。然后Service
应该执行网络 I/O 并显示任何必要的Notification
s。
请注意,由于对后台处理的严格限制,后台Service
s 不再允许启动Activity
。这是为了防止用户被一些随机的后台处理打断。正确的(用户友好的)方法是让背景Service
简单地显示Notification
,通知用户需要他的注意。然后,用户可以在想要查看信息时启动Activity
(通过单击“通知”)。
【讨论】:
以上是关于从通知启动主屏幕时出现 ANR的主要内容,如果未能解决你的问题,请参考以下文章
无论应用程序状态如何,都可以从通知中正确启动 Activity