Взаимодействие с UI в AsyncTask. Удаляем системные приложения.

Урок #19

Урок 19 — Взаимодействие с UI в AsyncTask. Удаляем системные приложения.

В прошлом уроке мы с вами научились удалять приложения, используя root. Удаление работает, однако, есть одна недоработка: после удаления приложение остаётся в списке.

Нам нужно как-то узнать о том, что процесс удаления завершён, и, если он завершён успешно — обновить список, а если нет — показать пользователю уведомление.

Взаимодействуем с UI из AsyncTask

Для того, чтобы получить результат выполнения AsyncTask для начала создадим listener. Его можно объявить как внутренний интерфейс внутри UninstallAsyncTask. В итоге он будет выглядеть следующим образом:

public class UninstallAsyncTask extends AsyncTask<String, Void, Boolean> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }

    @Override
    protected Boolean doInBackground(String... params) {
        String packageName = params[0];

        boolean result = RootHelper.uninstall(packageName);

        return result;
    }

    @Override
    protected void onPostExecute(Boolean result) {
        super.onPostExecute(result);
    }

    public interface UninstallListener {
        void onUninstalled();

        void onFailed();
    }
}
  • onUninstalled() — этот метод мы будем вызывать в случае, если удаление прошло успешно
  • onFailed() — этот метод мы вызовем, если удаление не удалось

Помните, мы обсуждали в прошлом уроке проблемы с утечками памяти? Поскольку мы будем создавать инстанс UninstallListener внутри Activity, нужно так же задуматься о возможных утечках, если MainActivity будет уничтожена раньше, чем закончится выполнение AsyncTask.

Поэтому мы будем использовать так называемую слабую ссылку. Если мы просто объявим поле:

private UninstallListener uninstallListener;

То это поле будет сильной ссылкой. Это значит, что в случае завершения Activity раньше, чем закончится выполнение AsyncTask, то Garbage Collector не сможет удалить Activity из памяти, потому что на неё всё ещё есть сильная ссылка. В случае, если мы будем использовать слабую ссылку такого не произойдёт — Garbage Collector просто удалит Activity из памяти, и ссылка обнулится. Давайте попробуем на практике — для начала создадим поле в классе UninstallAsyncTask:

private final WeakReference<UninstallListener> uninstallListenerWeakReference;

Теперь создадим конструктор и инициализируем ссылку:

public UninstallAsyncTask(UninstallListener uninstallListener) {
    super();
    this.uninstallListenerWeakReference = new WeakReference<>(uninstallListener);
}

Отлично, ссылка создана. Теперь нужно её использовать. Использовать её мы будем в методе onPostExecute():

@Override
protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);

    // Получаем сильную ссылку
    UninstallListener uninstallListener = uninstallListenerWeakReference.get();

    // Проверяем на null
    if (uninstallListener != null) {

        // Вызываем соответствующий метод
        if (result) {
            uninstallListener.onUninstalled();
        } else {
            uninstallListener.onFailed();
        }
    }
}

Поскольку слабая ссылка — это всего лишь "обёртка", использовать её напрямую мы не можем.

Сначала нужно получить сильную ссылку. После этого проверяем ссылку на null, ведь на самом деле объекта уже может и не быть в памяти (как раз если Activity была удалена), и тогда мы получим NullPointerException. Ну и после этого просто вызываем нужный нам метод.

Осталось лишь добавить UninstallListener в MainActivity. В конце Activity добавьте в код:

private final UninstallAsyncTask.UninstallListener uninstallListener = new UninstallAsyncTask.UninstallListener() {
    @Override
    public void onUninstalled() {
        Toast.makeText(MainActivity.this, "Удалено!", Toast.LENGTH_LONG).show();
    }
    @Override
    public void onFailed() {
        Toast.makeText(MainActivity.this, "Не удалось удалить!", Toast.LENGTH_LONG).show();
    }
};

Теперь добавим uninstallListener в конструктор AsyncTask в методе uninstallWithRoot():

private void uninstallWithRoot(AppInfo appInfo) {
    UninstallAsyncTask uninstallAsyncTask = new UninstallAsyncTask(uninstallListener);
    uninstallAsyncTask.execute(appInfo.getPackageName());
}

Теперь запустите приложение и попробуйте удалить любое несистемное приложение:

Удаление несистемных приложений
Удаление несистемных приложений

Работает!

Теперь давайте сделаем так, чтобы список пакетов обновлялся в каждом из вариантов (даже в случае неудачи — нам ведь нужно вернуть свайпнутое приложение обратно):

private final UninstallAsyncTask.UninstallListener uninstallListener = new UninstallAsyncTask.UninstallListener() {
    @Override
    public void onUninstalled() {
        reloadApps();
    }
    @Override
    public void onFailed() {
        reloadApps();
    }
};

Запустите приложение и попробуйте удалить любое несистемное приложение — оно исчезнет из списка. Супер.

Удаление системных приложений

Попробуйте теперь удалить совершенно любое системное приложение. Не беспокойтесь, вы ничего не сломаете — потому что у вас это не получится :)

Почему же так? Давайте разберемся, как Android хранит приложения.



Продолжение доступно на платных тарифах

А вместе с ним — проверка домашних заданий нашими менторами.

Это совсем недорого — всего от 440 ₽ в месяц!



ВЫБРАТЬ ТАРИФ

Курсовая работа

После этого урока нужно выполнить курсовую работу.



Вход

Войдите, чтобы пользоваться всеми преимуществами.
Это займёт всего пару секунд!

или