Reconnect to AccessibilityService / переподключение к AccessibilityService

188
25 августа 2018, 03:20

Есть android-приложение, которое использует AccessibilityService. После разрешения юзера приложение коннектится к сервису и работает с ним. Но обнаружилось, что если приложение падает, то автоматически отключается от сервиса. При повторном запуске приложения сервис не работает, но разрешение на подключение к нему есть. Снова подключиться к сервису удается если в настройках спец. возможностей отключить и снова включить разрешение использования сервиса. Вопрос: можно ли программно восстановить соединение к сервису, если оно уже разрешено?

Answer 1

В ходе экспериментов выяснилось, что когда программа падает, система уничтожает все классы, созданные программой, в том числе и MyAccessibilityService, который был связан с системным AccessibilityService. Инструментов, позволяющих принудительно восстановить связь с системным сервисом не обнаружил, зато оказалось, что если использовать UncaughtExceptionHandler (подробнее в статье), то приложение остается "живым" и падает только активити, в котором возникла ошибка. После перезапуска активити, связь с системным сервисом сохраняется и приложение работает нормально.

ps Генерация и отлавливание ошибок проводились только в активити, но я думаю, аналогичный механизм можно "вшить" и в сервис или ресивер. Если у кого-либо есть другие варианты - внимательно слушаю.

Update: Ниже приведенное решение работает на 3-х из 4 испытуемых девайсах!!! Сервис продолжает отваливаться на Xiaomi Redmi4A (Android 7.1.2) Для отлова ошибок любых компонентов приложения было сделано следующее: Создан класс MyApplication, наследующий само приложение:

public class MyApplication extends Application {
private static MyApplication instance;
  @Override
  public void onCreate() {
      super.onCreate();
      instance = this;
      //This is crash catcher!;
      Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler(this)); 
  }
  public static ContextWrapper getInstance() {
    return instance;
  }
}

Создан класс DefaultExceptionHandler:

public class DefaultExceptionHandler implements Thread.UncaughtExceptionHandler {
private Context context;
public static final String NAME_ERROR_MESSAGE = "error_message";

public DefaultExceptionHandler(Context context) {
    this.context = context;
}
@Override
public void uncaughtException(Thread t, Throwable ex) {
    ex.printStackTrace();
    Log.d("nocrash",  "Localized Message: " + ex.getLocalizedMessage());
    try {
        Intent intent = null;
            intent = new Intent(context, AfterCrashActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_CLEAR_TASK
                | Intent.FLAG_ACTIVITY_NEW_TASK);
        // Информацию об ошибке можно будет увидеть в AfterCrashActivity
        intent.putExtra(NAME_ERROR_MESSAGE, ex.getMessage());
        PendingIntent pendingIntent = PendingIntent.getActivity(
                MyApplication.getInstance().getBaseContext(), 0, intent, intent.getFlags());//getBaseContext() is null
        //Following code will restart your application after 2 seconds
        AlarmManager mgr = (AlarmManager) MyApplication.getInstance().getBaseContext()
                .getSystemService(Context.ALARM_SERVICE);
        if (mgr != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000,
                            pendingIntent);
                } else {
                    mgr.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000,
                            pendingIntent);
                }
            } else {
                mgr.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2000,
                        pendingIntent);
            }
        }
        //This will stop your application and take out from it.
        System.exit(2);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

AfterCrashActivity оформляем на свой вкус. У меня есть кнопка "Закрыть приложение", "Попробовать снова" и "Отправить информацию об ошибке".

READ ALSO
Android список с добавление элементов

Android список с добавление элементов

День добрый, подскажите пожалуйста, как лучше реализовать следующее на языке Java для Android:

248
Перегрузка методов, продвижение типов JAVA

Перегрузка методов, продвижение типов JAVA

Рассмотрим следующий код:

192
Android studio - Движение клавиатуры вместе с edittext

Android studio - Движение клавиатуры вместе с edittext

У меня есть EditText большой длины (около 100 строк), мне надо сделать так, чтобы при нажатии на нужную строку она двигалась так, чтобы она была видна...

170