ANR при запуске главного экрана из уведомления

#android #android-intent #broadcastreceiver #android-pendingintent #android-anr-dialog

#Android #android-намерение #broadcastreceiver #android-pendingintent #android-anr-диалог

Вопрос:

Я довольно новичок и наивен в мире разработки Android. Я работаю над существующей проблемой в нашем приложении для Android, и до сих пор мне не удалось ее исправить. Я прошу прощения за то, что задал длинный вопрос.

В текущем приложении, которое предназначено для отслеживания того, открыт или закрыт магазин у владельца магазина, мы показываем уведомление, на которое пользователь может нажать (когда приложение не открыто на переднем плане) и установить флажок с «Duty Off» на «Duty On». Если у пользователя отключены службы определения местоположения, и пользователь пытается щелкнуть по уведомлению с «Дежурный выключен» на «Дежурный включен», система пытается получить широту и долготу пользователя, делает СООБЩЕНИЕ о выноске и открывает главный экран приложения. Когда открывается главный экран приложения, пользователь видит сообщение об ошибке «Приложение не отвечает». Это происходит только в том случае, когда пользователь отключил свое местоположение.

Ниже приведен фрагмент моего кода, который является классом, вызываемым при выполнении этого действия, и он в основном отвечает за 2 метода createNotification и fun_DutyONOFF. После того, как я сам много погуглил, кажется, что если BroadcastReceiver не завершится в течение 10 секунд, Android выдаст сообщение о том, что приложение не отвечает (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);

}
 

}

Комментарии:

1. Если ваше приложение выходит из строя из-за ANR, у вас должна быть трассировка стека и другие ошибки в logcat. Пожалуйста, отредактируйте свой вопрос и скопируйте их в вопрос.

Ответ №1:

Это неправильная архитектура. В общем, a BroadcastReceiver не предназначен для выполнения большого объема работы и определенно не предназначен для выполнения асинхронных операций (например, сетевого ввода-вывода с обратными вызовами). Вы не можете выполнять сетевой ввод-вывод в основном потоке (UI), а BroadcastReceiver время жизни ограничено, поэтому вы также не можете выполнять асинхронные операции с обратными вызовами.

Правильная архитектура заключается в том, чтобы использовать ваш BroadcastReceiver просто для запуска Service , который будет работать в фоновом режиме. Затем Service следует выполнить сетевой ввод-вывод и показать все необходимые Notification s.

Обратите внимание, что из-за более жестких ограничений на фоновую обработку фоновым Service s больше не разрешается запускать an Activity . Это делается для предотвращения прерывания пользователя какой-либо случайной фоновой обработкой. Правильный (удобный для пользователя) подход заключается в том, чтобы фон Service просто показывал a Notification , информируя пользователя о том, что требуется его внимание. Затем пользователь может запустить Activity (нажав на «Уведомление»), когда захочет просмотреть информацию.