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

Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 02 ноя 2013, 20:56
Tamachi
Вот класс:

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

package ru.tamachi.pacer;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import android.widget.Toast;

public class IncommingCommandDBHelper extends SQLiteOpenHelper {
	
	final static String INCOMMING_COMMAND_DB_NAME = "incommingcommand";
	final static String INCOMMING_COMMAND_BODY_COLUMN_NAME = "cmdbody";
	final static String INCOMMING_COMMAND_TIME_COLUMN_NAME = "cmdtime";
	final static String INCOMMING_COMMAND_ANSWER_TO_PHONE_COLUMN_NAME = "cmdanswertophone";
	final static String INCOMMING_COMMAND_ID_COLUMN_NAME   = "_id";	
	
	private SQLiteDatabase m_readableDB = null;
	
	public IncommingCommandDBHelper(Context context) {
		super(context, INCOMMING_COMMAND_DB_NAME, null, 1);  
        if (!(m_readableDB==null)) {
            m_readableDB.close();
        }
		m_readableDB = getReadableDatabase(); 
		System.gc();		
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("create table " + INCOMMING_COMMAND_DB_NAME + " ( " + INCOMMING_COMMAND_ID_COLUMN_NAME
				+ " integer primary key autoincrement, " 
				+ INCOMMING_COMMAND_TIME_COLUMN_NAME + " integer, " 
				+ INCOMMING_COMMAND_BODY_COLUMN_NAME + " text, " 
				+ INCOMMING_COMMAND_ANSWER_TO_PHONE_COLUMN_NAME + " text);");
	}
	
	public long add(final String cmdBody, final String answerToPhone) {
		if (commandExists(cmdBody, answerToPhone)) {
			return -1;
		}
		long result = -1;
		try {
			SQLiteDatabase db = getWritableDatabase(); 
		    ContentValues contentValues = new ContentValues();
		  	    contentValues.put(INCOMMING_COMMAND_BODY_COLUMN_NAME, cmdBody); 
		  	    contentValues.put(INCOMMING_COMMAND_TIME_COLUMN_NAME, System.currentTimeMillis()); 
		  	    contentValues.put(INCOMMING_COMMAND_ANSWER_TO_PHONE_COLUMN_NAME, answerToPhone); 
			    result = db.insert(INCOMMING_COMMAND_DB_NAME, null, contentValues);
			db.close();
			
		} catch(Exception e) {
		
		}	
		return result;
	}
	
	public Boolean commandExists(String cmdBody, String answerToPhone) {
		String where ="("+INCOMMING_COMMAND_BODY_COLUMN_NAME+"=?) and ("+INCOMMING_COMMAND_ANSWER_TO_PHONE_COLUMN_NAME+"=?)";
		Cursor cursor = m_readableDB.query(INCOMMING_COMMAND_DB_NAME, null, where, new String[] { cmdBody, answerToPhone }, null, null, null);
		if (cursor==null) {
			return false;
		} else {
		  Boolean result = cursor.moveToFirst();
		  cursor.close();
		  return result;	
		}
	}
	
	public Cursor getCursor() {
		String orderby = INCOMMING_COMMAND_TIME_COLUMN_NAME+" asc";
		Cursor cursor = null;
		try {
			cursor = m_readableDB.query(INCOMMING_COMMAND_DB_NAME, null, null, null, null, null, orderby);
		} catch (Exception e) {
			cursor = null;
		}
		return cursor;
	}	
	
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub
		
	}
}


Вот обращение к этому классу из BroadcastReceiver:

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

	
         private static void storeSomething(final Context context, final String phoneNumber, final String body) {
		if (!(m_dbHelper==null)) {
			m_dbHelper = new IncommingCommandDBHelper(context);
		}
		Toast.makeText(context, "DEBUG POINT A", 6000).show();
    	        m_dbHelper.add(body, phoneNumber);
    	        Toast.makeText(context, "DEBUG POINT B", 6000).show();
	}

Однако практика показывает, что приложение падает при выполнении лексемы
m_dbHelper.add(body, phoneNumber);

Сообщение "DEBUG POINT A" отображается, но сообщение "DEBUG POINT B" не отображается.

У же неделю пытаюсь найти причину!

Подскажите, кто знает, в чём фишка?

Очередной баг или я что-то не так делаю.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 02 ноя 2013, 21:10
trew
m_dbHelper.add(body, phoneNumber);
Выведи в Log значение переменных body и phoneNumber.

Если значения есть, добавляй логирование в public long add и по цепочке в остальные методы.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 02 ноя 2013, 23:22
neoksi
1) Ну как бы напрямую работать с БД - это плохой тон. Нужно все делать через ContentProvider или на худой случай через синглтон.
2) Время жизни и выполнения BroadcastReciver ограничено и большие по длительности операции, в нем выполнять не рекомендуется.

Посоветовать могу в лог вывести Exception из метода аdd, чтоб понять что происходит именно сейчас.

П.С. Но архитектурный подход вам нужно менять в корне.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 02 ноя 2013, 23:33
Foenix
Как можно неделю искать причину, если она написана в логе? там даже строчка с ошибкой указана. И при этом гадать..?

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 09:12
Tamachi
neoksi писал(а):1) Ну как бы напрямую работать с БД - это плохой тон. Нужно все делать через ContentProvider или на худой случай через синглтон.
2) Время жизни и выполнения BroadcastReciver ограничено и большие по длительности операции, в нем выполнять не рекомендуется.

Посоветовать могу в лог вывести Exception из метода аdd, чтоб понять что происходит именно сейчас.

П.С. Но архитектурный подход вам нужно менять в корне.
После официального обновления прошивок двух телефонов (LG705 и FLYIQ505) в них перестали писаться логи.

То есть если я в коде напишу Log.d("MyTag", "MyComment") --- в лог ничего записано не будет!

А на смартфоне FLY404 возможность записи в лог была с самого начала отключена!

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 09:14
Tamachi
neoksi писал(а):1) Ну как бы напрямую работать с БД - это плохой тон. Нужно все делать через ContentProvider или на худой случай через синглтон.
2) Время жизни и выполнения BroadcastReciver ограничено и большие по длительности операции, в нем выполнять не рекомендуется.

Посоветовать могу в лог вывести Exception из метода аdd, чтоб понять что происходит именно сейчас.

П.С. Но архитектурный подход вам нужно менять в корне.

ContentProvider нужен только для того чтобы стучаться к базе из разных приложений.
А если этого не требуется, то рекоммендуется DBHelper. Собственно я и делаю как рекоммендуется!


Кстати, Синглтон тоже считается плохим тоном для андроид. Реализация синглтона в андроид чревата утечками памяти, курсора и пр... В ОС андроид временем жизни приложения (или его части) управляет не программист, а операционная система. Поэтому синглтон для андроид -- это не просто скверный тон: это верная смерть всего приложения!

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 09:23
Tamachi
Foenix писал(а):Как можно неделю искать причину, если она написана в логе? там даже строчка с ошибкой указана. И при этом гадать..?
Я ж говорю: после официпльного обновления прошивок телефонов ведение логов стало невозможным.

Кстати, причину я нашел: она оказалась в манифесте.

Вот почему структура файла манифеста так плохо докумментировна!!!

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 10:35
trew
Tamachi писал(а):Вот почему структура файла манифеста так плохо докумментировна!!!
что там не написано?
http://developer.android.com/guide/topi ... intro.html

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 12:12
Tamachi
trew писал(а):
Tamachi писал(а):Вот почему структура файла манифеста так плохо докумментировна!!!
что там не написано?
http://developer.android.com/guide/topi ... intro.html

Вот сейчас обнаружил, следующее:

Если изнутри BroadcastReceiver сделать startService (запустить службу),
то поток BroadcastReceiver не завершится до тех пор пока не завершится служба.

У меня BroadcastReceiver делает только одно действие: запускает службу!
По идее он (receiver) должен после этого сразу завершаться!
Но практика показывает, что это не так!
Подскажите, куда рыть?

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 17:49
neoksi
Tamachi писал(а):...

ContentProvider нужен только для того чтобы стучаться к базе из разных приложений.
А если этого не требуется, то рекоммендуется DBHelper. Собственно я и делаю как рекоммендуется!
Ты не забыл, что SQLite однопоточная БД и очередью запросов должен управлять сам программист? Если у тебя произойдет одновременное открытие нескольких копий DBHelper одной базы в разных частях приложения, то это черевато вылетами и ошибками записи в БД, чтоб не мучаться с реализацией очереди, CP используется не только для передачи инфы между приложениями, но и внутри одного приложения, в манифесте просто запрещаем экспорт. Так что теорию ты понял не очень верно.
Tamachi писал(а): Кстати, Синглтон тоже считается плохим тоном для андроид. Реализация синглтона в андроид чревата утечками памяти, курсора и пр... В ОС андроид временем жизни приложения (или его части) управляет не программист, а операционная система. Поэтому синглтон для андроид -- это не просто скверный тон: это верная смерть всего приложения!
Неверная реализация синглтона, да. Но ты опять же забываешь теорию, когда на данные все ссылки убиты, то они удаляются GC из памяти.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 03 ноя 2013, 21:08
Foenix
Tamachi писал(а): Кстати, Синглтон тоже считается плохим тоном для андроид. Реализация синглтона в андроид чревата утечками памяти, курсора и пр... В ОС андроид временем жизни приложения (или его части) управляет не программист, а операционная система. Поэтому синглтон для андроид -- это не просто скверный тон: это верная смерть всего приложения!
В синглтоне, действительно, не рекомендуют хранить данные. Данные. Т.к. при определенных обстоятельсвах объект может быть удален из памяти. Но при реализации там хранится только ссылка на экземпляр хэлпера, в случае чего он сам пересоздатся, так что это можно сказать одно из идеалных использований синглтона.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 04 ноя 2013, 11:15
Tamachi
Foenix писал(а):
Tamachi писал(а): Кстати, Синглтон тоже считается плохим тоном для андроид. Реализация синглтона в андроид чревата утечками памяти, курсора и пр... В ОС андроид временем жизни приложения (или его части) управляет не программист, а операционная система. Поэтому синглтон для андроид -- это не просто скверный тон: это верная смерть всего приложения!
В синглтоне, действительно, не рекомендуют хранить данные. Данные. Т.к. при определенных обстоятельсвах объект может быть удален из памяти. Но при реализации там хранится только ссылка на экземпляр хэлпера, в случае чего он сам пересоздатся, так что это можно сказать одно из идеалных использований синглтона.
Вы не учитываете того, что объект может потребоваться одновременно и в Activity и в BroadcastReceiver. И тогда будут сразу две копии объекта Вашего синглтона!

Шаблоны С++ в андроиде плохо работают!

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 04 ноя 2013, 11:35
Tamachi
При правильной организации DBHelper проблем с двойным открытием можно легко избежать.

ContentProvider -- слишком тяжеловесное решение. Да, гугль его рекоммендует, но исключительно для того, чтобы с его помощью формализовать данные пользователей для своих поисковых целей (как-никак гугль это поисковая система и его интересы не всегда совпадают с интересами программиста)

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 04 ноя 2013, 12:29
rezak90
Tamachi писал(а):При правильной организации DBHelper проблем с двойным открытием можно легко избежать.

ContentProvider -- слишком тяжеловесное решение. Да, гугль его рекоммендует, но исключительно для того, чтобы с его помощью формализовать данные пользователей для своих поисковых целей (как-никак гугль это поисковая система и его интересы не всегда совпадают с интересами программиста)
ContentProvider выгоден тем что система руководит открытием и закрытием бд, в таком случае у вас не будет ошибок и колизий.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 04 ноя 2013, 13:26
Foenix
Tamachi писал(а):При правильной организации DBHelper проблем с двойным открытием можно легко избежать.

ContentProvider -- слишком тяжеловесное решение. Да, гугль его рекоммендует, но исключительно для того, чтобы с его помощью формализовать данные пользователей для своих поисковых целей (как-никак гугль это поисковая система и его интересы не всегда совпадают с интересами программиста)
ну откройте тайну, что значит "правильная организация DBHelper"

Иначе, если при использовании BroadcastReceiver синглтон не подходит, единственный выход - использовать C.P., ничего там "тяжеловестного" как выяснилось, нет.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 05 ноя 2013, 11:59
neoksi
Да ладно, давайте дадим человеку набить свои шишки и потом переписать тонну кода =).

Если серьезно брать, все мы изначально невзлюбили CP, но каждый своими путями пришел к тому, что все равно пишет через CP.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 05 ноя 2013, 12:01
rezak90
neoksi писал(а):Если серьезно брать, все мы изначально невзлюбили CP, но каждый своими путями пришел к тому, что все равно пишет через CP.
Я и до сех пор не люблю СР. Но увы, люди убедили использовать его.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 05 ноя 2013, 12:10
neoksi
rezak90 писал(а):
neoksi писал(а):Если серьезно брать, все мы изначально невзлюбили CP, но каждый своими путями пришел к тому, что все равно пишет через CP.
Я и до сех пор не люблю СР. Но увы, люди убедили использовать его.
Ну ты любишь ORMLite =)

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 05 ноя 2013, 12:16
Foenix
Я к нему две недели привыкала :-D
Зато теперь когда знаешь как, то просто реализовываешь и все.

Re: Сохранение данных из BroadcastReceiver. Очередной баг?

Добавлено: 05 ноя 2013, 12:24
rezak90
neoksi писал(а):Ну ты любишь ORMLite =)
я его любил только за удобство, я вообще обёртки и либы не люблю, потому что в них трудно найти ошибку, когда сам пишешь свой велосипед то и найти ошибку проще