#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
(нажав на «Уведомление»), когда захочет просмотреть информацию.