Урок 83. Handler. Отложенные сообщения, удаление из очереди, Handler.Callback

Обсуждение уроков
Ответить
Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Урок 83. Handler. Отложенные сообщения, удаление из очереди, Handler.Callback

Сообщение damager82 » 30 май 2012, 23:00

В этом уроке:
- посылаем отложенные сообщения
- удаляем сообщения из очереди
- используем Handler.Callback для обработки сообщений


Click here to read this article!
Последний раз редактировалось damager82 20 май 2017, 20:08, всего редактировалось 6 раз.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение Prospekt » 31 май 2012, 10:01

Сначала долго старался понять чем конструкция в этом уроке существенно отличается от предыдущего. Какая разница делать ли обработку в самом Хендлере или в его Колбеке.
Но в принципе различие есть. Например у вас есть Активити, где возможны разные состояния экрана (начала игры, сама игра, переход на следующий уровень, подсчет очков и так далее), при изменении состояния игры мы можем менять Колбек и тем самым для каждого состояния иметь свой класс реакции на сообщения. Если само приложении сильно разрастается, в большом количестве операторов case можно заблудится, а так обработка каждого состояния вынесена в отдельный класс.

Вот только надо проверить можно ли менять динамически колбеки у Хендлера.

И ещё, сделайте плиз урок, посвященный заливки собственного приложения на маркет.

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение damager82 » 31 май 2012, 17:05

Prospekt писал(а):Вот только надо проверить можно ли менять динамически колбеки у Хендлера.
И ещё, сделайте плиз урок, посвященный заливки собственного приложения на маркет.
Судя по хелпу Callback сменить нельзя. Он только в конструкторе фигурирует...

Я еще ни одного приложения на маркет не закидывал, поэтому вообще не представляю как это делается. Времени совсем нет на разработку чего-то своего. А в рунете нет материалов на эту тему?
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

screamer
Сообщения: 2
Зарегистрирован: 20 июн 2012, 22:47

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение screamer » 20 июн 2012, 22:53

Кроме этого способа Handler также может использовать для обработки сообщений объект, реализующий интерфейс Handler.Callback. У интерфейса всего один метод handleMessage – в нем и прописываем всю логику обработки сообщений. Я пока не встречал практической пользы от этой штуки, но все же разберемся, как ее можно использовать.
В голову пришла аналогия из урока 10. Раз Handler.Callback - это интерфейс, то мы можем прикрутить его к нашему MainActivity:

Код: Выделить всё

public class MainActivity extends Activity implements Handler.Callback {

  final String LOG_TAG = "myLogs";
  Handler h;

  public boolean handleMessage(Message msg) {
    Log.d(LOG_TAG, "what = " + msg.what);
    return false;
  }

  /** Called when the activity is first created. */
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    h = new Handler(this);
    sendMessages();
  }

  void sendMessages() {
    Log.d(LOG_TAG, "send messages");
    h.sendEmptyMessageDelayed(1, 1000);
    h.sendEmptyMessageDelayed(2, 2000);
    h.sendEmptyMessageDelayed(3, 3000);
    h.removeMessages(2);
  }
}

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение damager82 » 21 июн 2012, 08:58

screamer писал(а):В голову пришла аналогия из урока 10. Раз Handler.Callback - это интерфейс, то мы можем прикрутить его к нашему MainActivity
Кстати да! Об этом я как-то не подумал)
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Roger68
Сообщения: 16
Зарегистрирован: 12 фев 2013, 23:43

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение Roger68 » 14 фев 2013, 16:34

Спасибо. Этим способом удалось побороть намеки Eclipse на то, что Handler хорошо бы объявить статическим.

anton9088
Сообщения: 2
Зарегистрирован: 06 мар 2013, 01:28

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение anton9088 » 13 мар 2013, 21:48

не хэндлер должен быть статическим, а класс хэндлера, если он расширялся прямо в Activity должен быть статическим, чтобы он не хранил ссылку на сам Activity. Т.к. задержка обработки сообщения, может быть большой и за это время можно закрыть Activity. Но ссылка на Activity будет храниться в хэндлере, который будет лежать в очереди сообщений и не сможет уничтожиться, пока сообщение не обработается.
http://android-developers.blogspot.ru/2 ... leaks.html

xr0m
Сообщения: 131
Зарегистрирован: 06 апр 2013, 14:01

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение xr0m » 07 апр 2013, 12:34

anton9088 это и так понятно, знаешь как реализовать код более правильно, покажи.

Мне вот не ясно(плохо знаю яву), как сделать статичный класс хендлера, если я его вызываю. а не создаю. Только через колбек...

Код: Выделить всё

Handler.Callback hc = new Handler.Callback() {
    public boolean handleMessage(Message msg) {
      Log.d(LOG_TAG, "what = " + msg.what);
      return false;
    }
  };
Далее не объяснено возврат false. Нам нужно вернуть true, так как дальнейшая обработка сообщения нам не требуется.

Вот пример.

Код: Выделить всё

h = new Handler(new Handler.Callback() {
	@Override
	public boolean handleMessage(Message msg) {
				
        	Log.i("Test","HandlerCallback");
		return false;
	};
})
{
	@Override
	public void handleMessage(Message msg)
	{
		Log.i("Test","Handler");
	}
};
Если вернем false, сработает дальше обработчик, т.е. Log.i("Test","Handler");

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение damager82 » 10 апр 2013, 14:54

Приведу пример static Handler. Если есть предложения и замечания по коду и тексту - пишите. Надо будет это решение отшлифовать и вынести в ветку Наработки.

Код: Выделить всё

public class MainActivity extends Activity {

	Handler handler;
	TextView tvTest;
	int cnt = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		tvTest = (TextView) findViewById(R.id.tvTest);
		
		handler = new MyHandler(this);
		handler.sendEmptyMessageDelayed(0, 1000);
	}

	void someMethod() {
		tvTest.setText("Count = " + cnt++);
		handler.sendEmptyMessageDelayed(0, 1000);
	}

	@Override
	protected void onDestroy() {
		if (handler != null)
			handler.removeCallbacksAndMessages(null);
		super.onDestroy();
	}

	static class MyHandler extends Handler {

		WeakReference<MainActivity> wrActivity;

		public MyHandler(MainActivity activity) {
			wrActivity = new WeakReference<MainActivity>(activity);
		}

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			MainActivity activity = wrActivity.get();
			if (activity != null)
				activity.someMethod();
		}
	}
}
В чем отличие static Handler от обычного, на который Eclipse ругается: "This Handler class should be static or leaks might occur "?
Выше уже написали об этом. Я еще раз напишу своими словами. Необходимо учесть две вещи:

1) Если бы я класс MyHandler сделал не static, то он бы содержал в себе скрытую ссылку на Activity.
2) Сообщения предназначенные для Handler содержат ссылку на сам Handler.

Два этих факта могут вызвать утечку памяти. Например, вы в системную очередь на выполнение помещаете сообщение, которое должно выполниться через час. Затем закрываете приложение. Система хочет освободить память и поудалять из нее неиспользуемые объекты. И она удалила бы закрытое Activity и все его содержимое, но не может. Потому что сообщение, которое будет висеть еще час, хранит ссылку на Handler, а Handler хранит ссылку на Activity. В итоге одно сообщение (которое, скорее всего, уже никому не нужно) держит зря целое Activity и не дает системе удалить его из памяти.

Объявляя Handler как static, мы разрубаем цепь ссылок и Handler больше не хранит ссылку на Activity. Но! Handler обычно используется чтобы взаимодействовать с UI, и он должен уметь работать с Activity и его методами. А для этого он должен иметь ссылку на Activity.

Получается легкое противоречие. Handler должен хранить ссылку на Activity, чтобы работать с ним. Но не должен хранить ссылку на Activity, чтобы не вызвать утечку памяти.

Тут выручает Java-механизм слабых ссылок - WeakReference. Слабая ссылка не учитывается системой при очистке памяти. Если система видит, что Acvtivity больше не нужно, но есть Handler, который хранит слабую ссылку на Activity, - слабая ссылка будет проигнорена, Activity будет удалено и утечек памяти не будет.

Мы в конструктор Handler-а передаем Activity и для хранения используем WeakReference. Если WeakReference возвращает null, значит объект был удален из памяти.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение damager82 » 12 апр 2013, 10:51

Ну как? Нет претензий-замечаний-улучшений? Публикую в Наработках так?
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
Isaev
Сообщения: 145
Зарегистрирован: 03 сен 2013, 09:39
Откуда: Германия
Контактная информация:

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение Isaev » 05 ноя 2013, 15:07

Как узнать текущее количество сообщений в очереди?

K_Vladimir
Сообщения: 36
Зарегистрирован: 28 июн 2015, 03:13

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение K_Vladimir » 26 июл 2015, 16:28

Можете объяснить почему метод handler.removeCallbacksAndMessages(null); сам по себе не решает всех этих проблем с утечкой памяти???

Аватара пользователя
Kirill
Сообщения: 19
Зарегистрирован: 09 сен 2015, 13:53

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение Kirill » 15 сен 2015, 23:55

Решение проблемы утечек памяти на сайте androiddesignpatterns.com:
http://www.androiddesignpatterns.com/20 ... -leak.html

[syntax=java]
public class SampleActivity extends Activity {

/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;

public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}

@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}

private final MyHandler mHandler = new MyHandler(this);

/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);

// Go back to the previous Activity.
finish();
}
}
[/syntax]


Интересно, что реализация интерфейса Runnable в анонимном классе внутри активити это тоже потенциальная утечка. Рекомендую выше указанную статью к прочтению.

androman
Сообщения: 6
Зарегистрирован: 04 мар 2017, 13:56

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение androman » 04 мар 2017, 14:07

Написал точно так же, как на уроке.
Изменил только этот код

Код: Выделить всё

  h.sendEmptyMessageDelayed(100, 1000);
  h.sendEmptyMessageDelayed(99, 50000); 
  h.sendEmptyMessageDelayed(98, 2000);
  h.sendEmptyMessageDelayed(97, 3000);
Ну и в самом хэндле в handleMessage добавил код изменения текстового поля.

Код: Выделить всё

textView1.setText(""+msg.what);
При запуске прораммы текстовое поле сразу принимает значение 99. Других цифр 100, 98, 97 я даже и не вижу. Хотя судя по коду он должен сначала принять 100, потом 98, потом 97 и потом только 99.
В чем может быть причина? Программа сразу проставляет значение максимальных миллисекунд.
Версия Андроид Студио - 2.3
Последний раз редактировалось androman 04 мар 2017, 15:30, всего редактировалось 1 раз.

androman
Сообщения: 6
Зарегистрирован: 04 мар 2017, 13:56

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение androman » 04 мар 2017, 14:33

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

h.sendEmptyMessageDelayed(100, 1000);
h.sendEmptyMessageDelayed(99, 50000);
h.sendEmptyMessageDelayed(98, 2000);
h.sendEmptyMessageDelayed(97, 3000);

И на теле хендлера оставил textView1.setText(""+msg.what);

При первом нажатий на кнопку все работает. А на втором нажатий, ничего на текстовом поле не меняется - остается значение 99 от первого нажатия кнопки. Как решить эту задачу - как сделать так, чтобы после каждого нажатия кнопки он менял значение текстового поля?
Последний раз редактировалось androman 04 мар 2017, 15:35, всего редактировалось 2 раза.

androman
Сообщения: 6
Зарегистрирован: 04 мар 2017, 13:56

Re: Урок 83. Handler. Отложенные сообщения, удаление из очер

Сообщение androman » 04 мар 2017, 15:11

И эту проблему тоже решил самостоятельно )

Ответить