Уведомления из сервиса, в котором крутится таймер
Уведомления из сервиса, в котором крутится таймер
Сервис работает, в нем есть таймер, в котором выполняются следующие действия: 1. Запись в базу 2. Запись в файл 3.Выдача уведомления
1 и 2 - работают нормально.
А с 3 - проблема - не хочет выдаваться уведомление из таймера, ругается на exception timer-0.
Поиск на стековерфлоу показал, что это (скорее всего) связанно с тем, что "из потока нельзя изменить UI"...это то, что мне удалось понять с буржуйского языка, хотя и непонятно, что это значит. Собственно два вопроса - что это за UI (пользовательский интерфейс, как я понял), который нельзя изменить (а разве уведомления = изменению)? И второй вопрос - как решить эту проблему?
Ранее уведомления выдавались нормально, правда, перед выдачей использовались таймер.пурж и таймер.кансел.... (но предполагалось их убрать)...
1 и 2 - работают нормально.
А с 3 - проблема - не хочет выдаваться уведомление из таймера, ругается на exception timer-0.
Поиск на стековерфлоу показал, что это (скорее всего) связанно с тем, что "из потока нельзя изменить UI"...это то, что мне удалось понять с буржуйского языка, хотя и непонятно, что это значит. Собственно два вопроса - что это за UI (пользовательский интерфейс, как я понял), который нельзя изменить (а разве уведомления = изменению)? И второй вопрос - как решить эту проблему?
Ранее уведомления выдавались нормально, правда, перед выдачей использовались таймер.пурж и таймер.кансел.... (но предполагалось их убрать)...
Re: Уведомления из сервиса, в котором крутится таймер
могу лишь сказать что ui поток это главный поток в котором запущенно приложение, по всему остальному у меня тёмный лес =)
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Уведомления из сервиса, в котором крутится таймер
Через Хендлер сбрось в UI поток и оттуда уже выводи сообщение.
Re: Уведомления из сервиса, в котором крутится таймер
UI-это основной поток в котором происходит прорисовка графического интерфейса. Его изменять можно (иначе какой смысл?) только нельзя это делать когда заблагорассудится из другого потока, который выполняется параллельно, вообще трудно определить в какой момент можно менять данные, которые используются в другом потоке, для этого и придумали всякие синхронизации. Представь UI поток прорисовывает какой-то TextView и уже вывел половину текста, а в этот момент другой поток меняет значение переменной, где хранится этот текст, что из этого выйдет? (Вы садитесь на стул, а в это момент ваш друг, в шутку, убирает этот стул ) Поэтому в Android и ввели полный запрет (исключения) на подобные действия и правильно сделали, в JAVA Swing подобного запрета нет, но если мы будем напрямую что-то менять в графических элементах из другого потока, поведение будет непредсказуемым и все может закончится крахом, т.е. типа мины замедленного действия, то вроде все нормально работает, то неожиданно будет падать (возможно уже у ваших пользователей).powercat писал(а):Собственно два вопроса - что это за UI (пользовательский интерфейс, как я понял), который нельзя изменить (а разве уведомления = изменению)? И второй вопрос - как решить эту проблему?
И чтобы программист не заморачивался по поводу синхронизации своих потоков с потоками отвечающими за прорисовку UI интерфейса поступают просто - ставим свой код в очередь сообщений UI-потока через Handler и пусть сама система решает, когда ей будет удобно и безопасно его выполнить. Мы как-бы оставляем заявку на выполнение кода, а не заставляем систему выполнять код немедленно.
Re: Уведомления из сервиса, в котором крутится таймер
Понятно...а как узнать, что работают разные потоки? Т.е. как заранее знать, что вот то, что в таймере - это не UI-поток, чтобы изначально вводить хандлер, а не недоумевать, почему вылезает ошибка? Есть ли какой-нить...не знаю, инструмент, чтобы знать, что ты уже пишешь код, который будет в другом потоке работать?
Re: Уведомления из сервиса, в котором крутится таймер
В UI...у меня работа идет в сервисе, основное приложение отключено, у юзера может быть открыта любае его программа...где мне прописывать тогда хандлер?neoksi писал(а):Через Хендлер сбрось в UI поток и оттуда уже выводи сообщение.
Re: Уведомления из сервиса, в котором крутится таймер
У класса Thread есть статические методы, можно, к примеру, узнать имя текущего потока:
Thread.currentThread().getName() - даст имя текущего потока, для UI потока это обычно "main".
Можно свои потоки как-то называть.
Или еще советуют Looper.getMainLooper().getThread() == Thread.currentThread() должен дать true на UI потоке.
Но обычно программист знает какой участок кода в каком потоке выполняется и если есть вероятность, что код для UI потока может быть выполнен в каком-то другом потоке, то можно на всякий случай пропустить его через Handler. А способов в Android хватает, Handler UI потока можно получить даже из любой View (getHandler()), или даже сразу вызывать его метод post к примеру:
Вместо tv.setText("Hello, World!");
можно всегда написать:
Кода чуть побольше, но зато гарантированно его выполнение в UI потоке.
Если есть доступ контексту Activity, то можно использовать его метод runOnUiThread
У меня, к примеру, была такая ситуация, я написал интерфейс с функцией обратного вызова, хотя реализация интерфейса и был прописана в Activity, но вызов этой функции делал другой поток, в результате тоже получил исключение, пришлось реализовывать вызов колбэков так же через Handler.
Thread.currentThread().getName() - даст имя текущего потока, для UI потока это обычно "main".
Можно свои потоки как-то называть.
Или еще советуют Looper.getMainLooper().getThread() == Thread.currentThread() должен дать true на UI потоке.
Но обычно программист знает какой участок кода в каком потоке выполняется и если есть вероятность, что код для UI потока может быть выполнен в каком-то другом потоке, то можно на всякий случай пропустить его через Handler. А способов в Android хватает, Handler UI потока можно получить даже из любой View (getHandler()), или даже сразу вызывать его метод post к примеру:
Вместо tv.setText("Hello, World!");
можно всегда написать:
Код: Выделить всё
tv.post(new Runnable() {
public void run() {
tv.setText("Hello, World!");
}
});
Если есть доступ контексту Activity, то можно использовать его метод runOnUiThread
Код: Выделить всё
runOnUiThread(new Runnable() {
public void run() {
tv.setText("Hello, World!");
}
});
Re: Уведомления из сервиса, в котором крутится таймер
Не очень понял ((
если надо выполнить код, содержащийся в сервисе, когда у юзера запущено другое приложение, то где мне описывать сам хандлер?
В уроках везде описывался хандлер в MainActivity, т.е. он был "прилеплен" к нему, и все раннейблы сидели там же...тут все было понятно.
А у меня - нет MainActivity, а есть сервис, в нем таймер ))
Раннейбл я пропишу, но как сказать системе, что надо бы выполнить код из сервиса, если она не знает, что там есть хандлер?
если надо выполнить код, содержащийся в сервисе, когда у юзера запущено другое приложение, то где мне описывать сам хандлер?
В уроках везде описывался хандлер в MainActivity, т.е. он был "прилеплен" к нему, и все раннейблы сидели там же...тут все было понятно.
А у меня - нет MainActivity, а есть сервис, в нем таймер ))
Раннейбл я пропишу, но как сказать системе, что надо бы выполнить код из сервиса, если она не знает, что там есть хандлер?
Re: Уведомления из сервиса, в котором крутится таймер
Тем не менее, у вашего сервиса, как и у любого компонента приложения всегда есть UI поток (со своим Looper-ом, Handler-ом и очередью сообщений), сервис всегда стартует в нем, даже если он в другом процессе запускается (в этом процессе правда будет создан свой UI-поток), а потом уже вы создаете свои потоки.powercat писал(а): В UI...у меня работа идет в сервисе, основное приложение отключено, у юзера может быть открыта любае его программа...где мне прописывать тогда хандлер?
Последний раз редактировалось AndreyI 03 дек 2012, 10:26, всего редактировалось 1 раз.
Re: Уведомления из сервиса, в котором крутится таймер
Т.е. сервис, стартуя в UI-потоке, все же имеет доступ к интерфейсу?? Что-то я тогда запутался )))AndreyI писал(а):Тем не менее, у вашего сервиса, как и у любого компонента приложения всегда есть UI поток (со своим Looper-ом, Handler-ом и очередью сообщений), сервис всегда стартует в нем, даже если он в другом процессе запускается, а потом уже вы создаете свои потоки.powercat писал(а): В UI...у меня работа идет в сервисе, основное приложение отключено, у юзера может быть открыта любае его программа...где мне прописывать тогда хандлер?
Re: Уведомления из сервиса, в котором крутится таймер
Ну если он его сам создаст (к примеру, диалоговое окно какое выведет), то конечно, а к чужому приложению, которое работает в другом процессе конечно нет.powercat писал(а):
Т.е. сервис, стартуя в UI-потоке, все же имеет доступ к интерфейсу?? Что-то я тогда запутался )))
Re: Уведомления из сервиса, в котором крутится таймер
Вообще правильней этот поток "обзывать" главным потоком процесса (Main Thread), а не UI потоком, т.к. это понятие несколько шире чем UI Любой процесс имеет главный поток, но не всякий процесс может иметь UI-интерфейс
Re: Уведомления из сервиса, в котором крутится таймер
у меня сервис должен сформировать и отправить уведомление, через NotificationManager...т.е. все же получается, что в "Главном потоке" экран менятеся, т.к. появлятеся иконка сообщения?
Значит что мне надо сделать? В сервисе отправку сообщения помещаю в раннейбл, там где его надо выполнить - использую хандлер?
Значит что мне надо сделать? В сервисе отправку сообщения помещаю в раннейбл, там где его надо выполнить - использую хандлер?
Re: Уведомления из сервиса, в котором крутится таймер
любой сервис стартует в ui-потоке, и по этому настоятельно рекомендуют все действия запускать в отдельных потоках в сервисе.
R.id.team
Политика на форуме запрещена
Политика на форуме запрещена
Re: Уведомления из сервиса, в котором крутится таймер
когда вы обращаетесь к NotificationManager вы обращаетесь к системному процессу, а по всей видимости, все обращения к нему нужно делать из главного потока сервиса.
Re: Уведомления из сервиса, в котором крутится таймер
При создании сервиса, к примеру, в его onCreate или в конструкторе просто создайте Handler (Handler h = new Handler();). А в своих потоках посылайте Notification через post
Код: Выделить всё
public class MyService extends Service {
private final Handler h = new Handler();
...
//Где-то в вашем потоке
h.post(new Runnable() {
public void run() {
nm.notify(...); //Отправляем Notification (nm - ваш NotificationManager)
}
});
Re: Уведомления из сервиса, в котором крутится таймер
Не, не хочет, ни просто через хендлер, ни через хендлер+другой поток.. вот код из сервиса - формирование уведомления
Описание хандлера на уровне класса сервиса
Раннейбл уведомления
Вот логи
Где я делаю хрень? )))
Описание хандлера на уровне класса сервиса
Код: Выделить всё
public class PlService extends Service {
Handler handler=new Handler();
Код: Выделить всё
if (numberNotif>0){ Если в базе есть записи
String str=getText(R.string.notif_numbers).toString()+numberNotif; Строка из текста+количество записей в базе
notif.setLatestEventInfo(PlantService.this, getText(R.string.app_name), str, pi);
notif.flags|=Notification.FLAG_AUTO_CANCEL;
notif.number=numberNotif; Показ количества записей в уведомлении
Thread t=new Thread(new Runnable(){
public void run(){
handler.post(SendNotif);
}
});
t.start();
}
Код: Выделить всё
Runnable SendNotif=new Runnable() {
public void run() {
nm.notify(0,notif);
}
};
Код: Выделить всё
12-04 14:25:52.351: W/dalvikvm(1433): threadid=1: thread exiting with uncaught exception (group=0x40015560)
12-04 14:25:52.361: E/AndroidRuntime(1433): FATAL EXCEPTION: main
12-04 14:25:52.361: E/AndroidRuntime(1433): java.lang.NullPointerException
12-04 14:25:52.361: E/AndroidRuntime(1433): at com.example.myplant.PlService$1.run(PlService.java:185)
12-04 14:25:52.361: E/AndroidRuntime(1433): at android.os.Handler.handleCallback(Handler.java:587)
12-04 14:25:52.361: E/AndroidRuntime(1433): at android.os.Handler.dispatchMessage(Handler.java:92)
12-04 14:25:52.361: E/AndroidRuntime(1433): at android.os.Looper.loop(Looper.java:123)
12-04 14:25:52.361: E/AndroidRuntime(1433): at android.app.ActivityThread.main(ActivityThread.java:3683)
12-04 14:25:52.361: E/AndroidRuntime(1433): at java.lang.reflect.Method.invokeNative(Native Method)
12-04 14:25:52.361: E/AndroidRuntime(1433): at java.lang.reflect.Method.invoke(Method.java:507)
12-04 14:25:52.361: E/AndroidRuntime(1433): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-04 14:25:52.361: E/AndroidRuntime(1433): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-04 14:25:52.361: E/AndroidRuntime(1433): at dalvik.system.NativeStart.main(Native Method)
Re: Уведомления из сервиса, в котором крутится таймер
Тема закрыта....я забыл nm=(NotificationManager) getSystemService(NOTIFICATION_SERVICE); БЛЯ!!
Потоки и хандлер не требуется тут - просто отправляется
Потоки и хандлер не требуется тут - просто отправляется
Re: Уведомления из сервиса, в котором крутится таймер
Давайте без матовpowercat писал(а):Тема закрыта....я забыл nm=(NotificationManager) getSystemService(NOTIFICATION_SERVICE); БЛЯ!!
Потоки и хандлер не требуется тут - просто отправляется
Re: Уведомления из сервиса, в котором крутится таймер
надо ввести модераторов, шоб терли лишнее...