Урок 83. Handler. Отложенные сообщения, удаление из очереди, Handler.Callback
Урок 83. Handler. Отложенные сообщения, удаление из очереди, Handler.Callback
В этом уроке:
- посылаем отложенные сообщения
- удаляем сообщения из очереди
- используем Handler.Callback для обработки сообщений
Click here to read this article!
- посылаем отложенные сообщения
- удаляем сообщения из очереди
- используем Handler.Callback для обработки сообщений
Click here to read this article!
Последний раз редактировалось damager82 20 май 2017, 20:08, всего редактировалось 6 раз.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Сначала долго старался понять чем конструкция в этом уроке существенно отличается от предыдущего. Какая разница делать ли обработку в самом Хендлере или в его Колбеке.
Но в принципе различие есть. Например у вас есть Активити, где возможны разные состояния экрана (начала игры, сама игра, переход на следующий уровень, подсчет очков и так далее), при изменении состояния игры мы можем менять Колбек и тем самым для каждого состояния иметь свой класс реакции на сообщения. Если само приложении сильно разрастается, в большом количестве операторов case можно заблудится, а так обработка каждого состояния вынесена в отдельный класс.
Вот только надо проверить можно ли менять динамически колбеки у Хендлера.
И ещё, сделайте плиз урок, посвященный заливки собственного приложения на маркет.
Но в принципе различие есть. Например у вас есть Активити, где возможны разные состояния экрана (начала игры, сама игра, переход на следующий уровень, подсчет очков и так далее), при изменении состояния игры мы можем менять Колбек и тем самым для каждого состояния иметь свой класс реакции на сообщения. Если само приложении сильно разрастается, в большом количестве операторов case можно заблудится, а так обработка каждого состояния вынесена в отдельный класс.
Вот только надо проверить можно ли менять динамически колбеки у Хендлера.
И ещё, сделайте плиз урок, посвященный заливки собственного приложения на маркет.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Судя по хелпу Callback сменить нельзя. Он только в конструкторе фигурирует...Prospekt писал(а):Вот только надо проверить можно ли менять динамически колбеки у Хендлера.
И ещё, сделайте плиз урок, посвященный заливки собственного приложения на маркет.
Я еще ни одного приложения на маркет не закидывал, поэтому вообще не представляю как это делается. Времени совсем нет на разработку чего-то своего. А в рунете нет материалов на эту тему?
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
В голову пришла аналогия из урока 10. Раз Handler.Callback - это интерфейс, то мы можем прикрутить его к нашему MainActivity:Кроме этого способа Handler также может использовать для обработки сообщений объект, реализующий интерфейс Handler.Callback. У интерфейса всего один метод handleMessage – в нем и прописываем всю логику обработки сообщений. Я пока не встречал практической пользы от этой штуки, но все же разберемся, как ее можно использовать.
Код: Выделить всё
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);
}
}
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Кстати да! Об этом я как-то не подумал)screamer писал(а):В голову пришла аналогия из урока 10. Раз Handler.Callback - это интерфейс, то мы можем прикрутить его к нашему MainActivity
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Спасибо. Этим способом удалось побороть намеки Eclipse на то, что Handler хорошо бы объявить статическим.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
не хэндлер должен быть статическим, а класс хэндлера, если он расширялся прямо в Activity должен быть статическим, чтобы он не хранил ссылку на сам Activity. Т.к. задержка обработки сообщения, может быть большой и за это время можно закрыть Activity. Но ссылка на Activity будет храниться в хэндлере, который будет лежать в очереди сообщений и не сможет уничтожиться, пока сообщение не обработается.
http://android-developers.blogspot.ru/2 ... leaks.html
http://android-developers.blogspot.ru/2 ... leaks.html
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
anton9088 это и так понятно, знаешь как реализовать код более правильно, покажи.
Мне вот не ясно(плохо знаю яву), как сделать статичный класс хендлера, если я его вызываю. а не создаю. Только через колбек...
Далее не объяснено возврат false. Нам нужно вернуть true, так как дальнейшая обработка сообщения нам не требуется.
Вот пример.
Если вернем false, сработает дальше обработчик, т.е. Log.i("Test","Handler");
Мне вот не ясно(плохо знаю яву), как сделать статичный класс хендлера, если я его вызываю. а не создаю. Только через колбек...
Код: Выделить всё
Handler.Callback hc = new Handler.Callback() {
public boolean handleMessage(Message msg) {
Log.d(LOG_TAG, "what = " + msg.what);
return false;
}
};
Вот пример.
Код: Выделить всё
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");
}
};
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Приведу пример static Handler. Если есть предложения и замечания по коду и тексту - пишите. Надо будет это решение отшлифовать и вынести в ветку Наработки.
В чем отличие 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, значит объект был удален из памяти.
Код: Выделить всё
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();
}
}
}
Выше уже написали об этом. Я еще раз напишу своими словами. Необходимо учесть две вещи:
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, значит объект был удален из памяти.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Ну как? Нет претензий-замечаний-улучшений? Публикую в Наработках так?
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Как узнать текущее количество сообщений в очереди?
-
- Сообщения: 36
- Зарегистрирован: 28 июн 2015, 03:13
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Можете объяснить почему метод handler.removeCallbacksAndMessages(null); сам по себе не решает всех этих проблем с утечкой памяти???
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Решение проблемы утечек памяти на сайте 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 в анонимном классе внутри активити это тоже потенциальная утечка. Рекомендую выше указанную статью к прочтению.
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 в анонимном классе внутри активити это тоже потенциальная утечка. Рекомендую выше указанную статью к прочтению.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Написал точно так же, как на уроке.
Изменил только этот код
Ну и в самом хэндле в handleMessage добавил код изменения текстового поля.
При запуске прораммы текстовое поле сразу принимает значение 99. Других цифр 100, 98, 97 я даже и не вижу. Хотя судя по коду он должен сначала принять 100, потом 98, потом 97 и потом только 99.
В чем может быть причина? Программа сразу проставляет значение максимальных миллисекунд.
Версия Андроид Студио - 2.3
Изменил только этот код
Код: Выделить всё
h.sendEmptyMessageDelayed(100, 1000);
h.sendEmptyMessageDelayed(99, 50000);
h.sendEmptyMessageDelayed(98, 2000);
h.sendEmptyMessageDelayed(97, 3000);
Код: Выделить всё
textView1.setText(""+msg.what);
В чем может быть причина? Программа сразу проставляет значение максимальных миллисекунд.
Версия Андроид Студио - 2.3
Последний раз редактировалось androman 04 мар 2017, 15:30, всего редактировалось 1 раз.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
Проблема решилась.
Но, появилась другая задачка.
Разместил на событие нажатия кнопки мой следующий текст
h.sendEmptyMessageDelayed(100, 1000);
h.sendEmptyMessageDelayed(99, 50000);
h.sendEmptyMessageDelayed(98, 2000);
h.sendEmptyMessageDelayed(97, 3000);
И на теле хендлера оставил textView1.setText(""+msg.what);
При первом нажатий на кнопку все работает. А на втором нажатий, ничего на текстовом поле не меняется - остается значение 99 от первого нажатия кнопки. Как решить эту задачу - как сделать так, чтобы после каждого нажатия кнопки он менял значение текстового поля?
Но, появилась другая задачка.
Разместил на событие нажатия кнопки мой следующий текст
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 раза.
Re: Урок 83. Handler. Отложенные сообщения, удаление из очер
И эту проблему тоже решил самостоятельно )