Страница 1 из 1

Пропадает флаг

Добавлено: 30 мар 2012, 23:20
andev
Начал ловить в своем приложении плавающий глюк :(
Вернее, он постоянный и я уже четко определил условия, после которых он начинает проявляться, но причину понять не могу, надеюсь подскажете что-то дельное.

Итак, опишу барахлящую часть.
Классы:
1) класс ActivityMessage активити с ListView, отображает сообщения (суть приложения - обмен сообщениями)
2) класc MessageService, сингелтон, хранит массив сообщений, отдает их для активити по его запросу.
3) класс NetworkService, "ходит" за сообщениями на сервер, сохраняет их в MessageService


Содержание классов, все лишнее порезал.

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


import java.util.Timer;
import java.util.TimerTask;

public class ActivityMessage extends ListActivity implements OnClickListener {

	private String collocutor;
	private Timer timer;
	private TimerTask updateList;
	
	/** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_message);
        
        /// try to get inner data
        Intent intent = getIntent();        
        boolean fromChats = intent.getBooleanExtra("havePhone", false);
        if(fromChats) {
        	String phone = intent.getStringExtra("phone");
        	
        	this.collocutor = phone;
        	update(collocutor);
        }
        
        startUpdateList(); // prepare timer
    }
        
	@Override
    public void onBackPressed() {
    	Intent intent = new Intent(this, ActivityChats.class);
        startActivity(intent);
        this.finish();
    }
    /// Method updates ListView
      private void update(String collocutor) {
    	
    	MessageService messageService = MessageService.getInstance(getApplicationContext());
    	ArrayList<MessageEntity> list = messageService.list(collocutor);
        messageListAdapter = new MessageListAdapter(this, R.layout.list_item_message_enemy, list);
        setListAdapter(messageListAdapter);
        
        listView.setSelection(listView.getCount() - 1);
	}

	}
	/// method for ListView update
	private void startUpdateList() {
		timer = new Timer();
		
		updateList = new TimerTask() {
			@Override
			public void run() {
				runOnUiThread(new Runnable() {
					@Override
					public void run() {						
						MessageService messageService = MessageService.getInstance(getApplicationContext());
						
						if (messageService.HasNewMessages()) {
							update(collocutor);
							messageService.clearHasNewMessages();
						}						
					}
				});
			}
		};
		
		timer.schedule(updateList, 1000, 3000);
	}
}

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

public class MessageService {
	
	private static MessageService instance;
	
    private Context context;
    private ArrayList<MessageEntity> messages; // messages
 
    private boolean hasNewMessages = false;
    
    /// constructor
	private MessageService(Context context) {
		this.context = context;
    	messages = new ArrayList<MessageEntity>();
    	dbHelper = new DBHelper(context);
	}
	
	/// constructor
    public static MessageService getInstance(Context context) {
        if (instance == null) {
            instance = new MessageService(context);
        }
        return instance;
    }
	
    /// return list of the messages with specified collocutor
	public ArrayList<MessageEntity> list(String collocutor) {
		 ArrayList<MessageEntity> result = new ArrayList<MessageEntity>();
		 
		 for (int i = 0; i < messages.size(); i++) {
			 if (messages.get(i).getPhoneFrom().equalsIgnoreCase(collocutor)) {
				 result.add(messages.get(i));
			 }
			 if (messages.get(i).getPhoneTo().equalsIgnoreCase(collocutor)) {
				 result.add(messages.get(i));
			 }
		 }
		 
		 return result;	
	}
	
	/// Method, when new message has come
	public void NewIncomingMessage(String from, String text) {
		// Этот метод вызывается из NetworkService сервиса, который "ходит"
		// за сообщениями и при получении новых сообщений вызывет этот метод
		
		MessageEntity message = new MessageEntity(from, text, false);
		
		ChatService.getInstance(context).CreateChat(from); // create new chat (inner check, is exist)
		messages.add(message);	
		
		hasNewMessages = true; // <--- Устанавливаю флаг, говорящий о том, что в массиве есть
							   // новые сообщения и их надо отобразить на ListView
	}
	
	public boolean HasNewMessages() {
		return hasNewMessages;
	}
	
	public void clearHasNewMessages() {
		hasNewMessages = false;
	}
}
NetworkService проверяет раз в N секунд наличие обновлений на сервере и при наличии новых сообщений получает их и вызывает MessageService.NewIncomingMessage()
Этот метод добавляет новое сообщения в коллекцию messages и устанавливает флаг hasNewMessages в true.
Метод MessageService.list возвращает массив сообщений из коллекции

ActivityMessage при создании в onCreate вызывает метод update() и метод startUpdateList()
Метод update() :
а) получает из MessageService list - все сообщения, которые надо вывести в ListView
б) создает messageListAdapter - самописный адаптер, с inflate из xml и прочим
в) устанавливает для ListView этот адаптер, ну и перематывает его в конец.

Метод startUpdateList(), на который главные подозрения:
Этот метод создает новый таймер и таймертаск, в котором раз в 3 секунды проверяется флаг messageService.HasNewMessages() и если он установлен в true, то обновляет ListView при помощи метода update() и чистит флаг, означая, что новые сообщения отобразились в ListView.
Так же обратите внимание, что при нажатии Back активити финиширует finish().

Общая идея - сообщения поступают с сервера в рандомные моменты времени, когда поступили - попали в массив и флаг о том что они есть стал true
Активити по таймеру проверяет этот флаг и когда видит его в true, то обновляет ListView и обнуляет флаг.

Теперь описание самого глюка.
Когда запускаю приложение и перехожу на эту активити то все работает нормально, при наличии новых сообщений они в течении максимум 3 секунд отображаются в ListView.
Но когда я жму back, а затем снова захожу на эту активити то новые сообщения иногда отображаются, а иногда нет. Они гарантированно приходят, так как в MessageService.messages они есть, но вот механизм с флагом уже не срабатывает. Создается впечатление, что таймер, который создался при первом заходе на активити, после выхода с нее не уничтожился и продолжает работать. Затем я снова захожу на активити, создается второй таймер, но т.к. первый уже работает (якобы), то он забирает и обнуляет флаг раньше второго, актуального в данный момент таймера, поэтому новые сообщения нормально приходят, записываются в коллекцию messages, но отобразить их не получается. Иногда начинает работать, возможно происходит конкуренция между таймерами (если этот фантомный таймер действительно есть, просто у меня другого объяснения пока нет).

Re: Пропадает флаг

Добавлено: 04 апр 2012, 13:25
andev
Извините, что апаю, но никто даже приблизительно не знает куда копать?

Re: Пропадает флаг

Добавлено: 05 апр 2012, 11:34
damager82
Очень может быть, что дело в Timer. Когда Activity закрывается, его объекты еще могут жить и работать.

А что, если вынести timer в переменные класса и в onDestory его останавливать: timer.cancel() ?

Re: Пропадает флаг

Добавлено: 06 апр 2012, 14:02
andev
Да! помогло!!!!
Как я сам не додумался? В очередной раз убеждаюсь что часто бывает полезен "незамыленный" взгляд со стороны.
Спасибо!