• 0
Rusland

Одновременное обращение к БД Sqlite из программы и из сервиса

Вопросы

Можно ли работать с одной базой одновременно и из программы и из сервиса?

PS. Android

Изменено пользователем Rusland

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 ответов на этот вопрос

  • 0

Совсем забыл, из сервиса никак к БД не обратиться - иначе валится с ошибкой Segment fault и валит вместе с собой основное приложение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 1
В 01.04.2016 в 15:01, Rusland сказал:

Совсем забыл, из сервиса никак к БД не обратиться - иначе валится с ошибкой Segment fault и валит вместе с собой основное приложение.

А как ты connection к БД прописываешь с апликухи и из сервиса?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

 

SQLite может быть собран в однопоточном варианте (параметр компиляции SQLITE_THREADSAFE = 0). 

Подробнее:

https://m.habrahabr.ru/post/149635/

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 02.04.2016 в 23:29, umkes сказал:

А как ты connection к БД прописываешь с апликухи и из сервиса?

Через TFDConnection, указав путь к файлу

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

 

2 часа назад, Rusland сказал:

Через TFDConnection, указав путь к файлу

Rusland, может конечно бредовая версия, т.к. слишком просто :-)  где файл БД лежит? есть ли у сервиса доступ к нему?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 1
3 часа назад, Belov.V. сказал:

 

Rusland, может конечно бредовая версия, т.к. слишком просто :-)  где файл БД лежит? есть ли у сервиса доступ к нему?

БД кладу в TPath.GetDocumentsPath.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я так же мучался с ини файлом. В конце концов прописал путь напрямую. Думаю что с БД так же прокатит.

Пример:

В апликации фаил создавался по такому пути:

System.IOUtils.TPath.Combine(System.IOUtils.TPath.GetDocumentsPath, 'KDGConfig.ini');

А в сервисе задавался такой путь:

'/data/data/com.embarcadero.KDGPhoneCallApplication/files/KDGConfig.ini'

Изменено пользователем umkes

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Rusland, удалось решить эту проблему?

Еще есть эта ветка про такое.

На Stackoverflow создал вопрос, ждем ответа.

Изменено пользователем Pax Beach

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

в PlatformSDK есть helper SQLiteOpenHelper.java, в нем метод getWritableDatabase(). Осталось научиться в сервисе работать с SQLite таким образом.

Может есть из вас, кто хорошо разобрался, как импортировать JAVA код в Delphi?

    /**
     * Create and/or open a database that will be used for reading and writing.
     * The first time this is called, the database will be opened and
     * {@link #onCreate}, {@link #onUpgrade} and/or {@link #onOpen} will be
     * called.
     *
     * <p>Once opened successfully, the database is cached, so you can
     * call this method every time you need to write to the database.
     * (Make sure to call {@link #close} when you no longer need the database.)
     * Errors such as bad permissions or a full disk may cause this method
     * to fail, but future attempts may succeed if the problem is fixed.</p>
     *
     * <p class="caution">Database upgrade may take a long time, you
     * should not call this method from the application main thread, including
     * from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
     *
     * @throws SQLiteException if the database cannot be opened for writing
     * @return a read/write database object valid until {@link #close} is called
     */
    public synchronized SQLiteDatabase getWritableDatabase() {
        if (mDatabase != null) {
            if (!mDatabase.isOpen()) {
                // darn! the user closed the database by calling mDatabase.close()
                mDatabase = null;
            } else if (!mDatabase.isReadOnly()) {
                return mDatabase;  // The database is already open for business
            }
        }

        if (mIsInitializing) {
            throw new IllegalStateException("getWritableDatabase called recursively");
        }

        // If we have a read-only database open, someone could be using it
        // (though they shouldn't), which would cause a lock to be held on
        // the file, and our attempts to open the database read-write would
        // fail waiting for the file lock.  To prevent that, we acquire the
        // lock on the read-only database, which shuts out other users.

        boolean success = false;
        SQLiteDatabase db = null;
        if (mDatabase != null) mDatabase.lock();
        try {
            mIsInitializing = true;
            if (mName == null) {
                db = SQLiteDatabase.create(null);
            } else {
                db = mContext.openOrCreateDatabase(mName, 0, mFactory, mErrorHandler);
            }

            int version = db.getVersion();
            if (version != mNewVersion) {
                db.beginTransaction();
                try {
                    if (version == 0) {
                        onCreate(db);
                    } else {
                        if (version > mNewVersion) {
                            onDowngrade(db, version, mNewVersion);
                        } else {
                            onUpgrade(db, version, mNewVersion);
                        }
                    }
                    db.setVersion(mNewVersion);
                    db.setTransactionSuccessful();
                } finally {
                    db.endTransaction();
                }
            }

            onOpen(db);
            success = true;
            return db;
        } finally {
            mIsInitializing = false;
            if (success) {
                if (mDatabase != null) {
                    try { mDatabase.close(); } catch (Exception e) { }
                    mDatabase.unlock();
                }
                mDatabase = db;
            } else {
                if (mDatabase != null) mDatabase.unlock();
                if (db != null) db.close();
            }
        }
    }

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • -1

Возможный выход из ситуации не держать постоянный коннект к базе? Открыл, прочитал или записал, закрыл. Можно перед открытием проверку на доступ сделать с ожиданием.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Я нашел решение, к сожалению, пока только для работы с UniDAC:

Обновил UniDAC компоненты для Berlin до последней версии (6.3.12).

Компоненты TUniConnection и TUniQuery отлично работают с SQLite в Android Service. FireDAC в Android Service пока запустить не удалось, но у меня такой задачи нет.

В Deployment host приложения добавляю файл базы данных, Remote Path задаю ".\assets\internal\". И спокойно из сервиса получаю к нему доступ. Мой сервис локальный в одном потоке с приложением. Если делать Intent Service или Remote — наверное, придется помещать файл в другой, доступный каталог, или общаться через намерения (Intents).

Надеюсь мой код будет полезен для вас.

procedure TDM.conSQLiteBeforeConnect(Sender: TObject);
begin
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
  conSQLite.Database := TPath.Combine(TPath.GetDocumentsPath, 'mybase.sqlite');
{$ENDIF}
end;

procedure TDM.conSQLiteError(Sender: TObject; E: EDAError; var Fail: Boolean);
begin
  Log('--- DB error: %s:', [E.Message]);
  Fail := False;
end;

function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
  Log('+ START with Intent: ' + JStringToString(Intent.getAction.toString), []);
  if Intent.getAction.equalsIgnoreCase(StringToJString('StopIntent')) then
  begin
    try
      conSQLite.Disconnect;
      Log('- DB disconnected', []);
    except
      on E: Exception do
        Log('- can not to disconnect DB', [E.Message]);
    end;

    Log('... service to be stoped', []);
    JavaService.stopSelf;

    Result := TJService.JavaClass.START_NOT_STICKY; // don't reload service
  end
  else
  begin
    Log('... service started', []);

    try
      conSQLite.Connect;
      Log('+ DB connected', []);

      UniQuery.SQL.Text := 'select count(*) as ALLREC from orders';
      UniQuery.Open;
      if UniQuery.RecordCount > 0 then
      begin
        UniQuery.First;
        Log('... record count: %s', [UniQuery.FieldByName('ALLREC').AsString]);
      end;
      UniQuery.Close;
    except
      on E: Exception do
        Log('- can not to connect DB: %s', [E.Message]);
    end;

    Result := TJService.JavaClass.START_STICKY; // rerun service if it stops
  end;
end;
Изменено пользователем Pax Beach

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
  • 0

... Продолжаем исследование по теме:

Оказывается в модуле Androidapi.JNI.GraphicsContentViewText есть класс TJSQLiteDatabase, который реализует возможность работы с SQLite на Android.

Пример использования этого класса на JAVA я писал выше, осталось просто перенести пример реализацию работы с классом на Delphi.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти


  • Похожий контент

    • От zekelive
      Добрый день, товарищи. Если кто сталкивался, подскажите) в потоке создаются картинкив виде плиток и прочие компоненты и падают на scrollbox.  Но в runtime пролистывание лагает, да в целом вся программа подлагивает. Можно ли как то реализовать подгрузка в фоне без ущерба? Или может ещё какой способ есть?
    • От Вольдемар
      Пользуюсь в своем Android приложении этим компонентом, вроде всё работает. Но хотелось бы асинхронности. Помогите пожалуйста с примером, как сделать асинхронность и получать результат после Post. Спасибо
    • От Aptyp
      На моём Samsung Note 5 вокруг букв проглядываются линии. Причём пробовал 3 различных разрешения экрана, ничего не меняется. У друга на Xiaomi Redmi 4x такого не наблюдается.
      Что это может быть?
       


    • От om.pranayama
      Здравствуйте форумчане и профессионалы разработчики.
      Компилирую проект через C++Builder 10.2  под Android
      Появилась следующая проблема при использовании компонента TBitmapListAnimation
      Если приложение свернуть, а затем развернуть - то появляются жуткие глитчи в ввиде чёрных фонов вокруг компонентов, типа TImage, TButton.
      В Windows такая проблема - не наблюдается.
      Попытки вызвать Repaint или даже Invalidate для всей формы - положительного результата не дают.
      Пожалуйста, помогите решить эту проблему.
      //--------------------------------------------------------------------------------------------------------------------------------------------
      ТЕМУ МОЖНО УДАЛЯТЬ
      Причина не в TBitmapListAnimation а в TAniIndicator, который работал совместно с TBitmapListAnimation.
      Приношу извинения за беспокойство. Проблема была в TAniIndicator. Буду разбираться почему он так себя безобразно ведёт.
      Тему можно удалять.
    • От Aptyp
      В приложении:
          procedure TForm7.Button1Click(Sender: TObject);     var AIntent: JIntent;         AServiceName: string;     begin       AIntent := TJIntent.Create;       AServiceName := 'com.embarcadero.services.Service';       AIntent.setClassName( TAndroidHelper.Context.getPackageName(), TAndroidHelper.StringToJString( AServiceName ) );       AIntent.putExtra( TAndroidHelper.StringToJString( 'Code' ), 0 );       AIntent.putExtra( TAndroidHelper.StringToJString( 'Data' ), TAndroidHelper.StringToJString( 'DataString' ) );       TAndroidHelper.Activity.startService( AIntent );     end;
      В сервисе:
          procedure TDM.AndroidIntentServiceCreate(Sender: TObject);     begin       Toast( 'Create' );     end;          procedure TDM.AndroidIntentServiceHandleIntent(const Sender: TObject;       const AnIntent: JIntent);     begin       Toast( 'HandleIntent' );     end; Сообщение 'Create' показывается, а 'HandleIntent' нет. OnCreate срабатывает, но onHandleIntent не вызывается что бы я не делал. Может я что-то не так делаю?
    • От Roman V
      Всем привет. Учусь работать с ini-файлами на Android. И сразу же возникла проблема, которую никак не могу решить. Хотел написать подобие приложение-тест с хранением данных в ini файле. В итоге все отлично работает на windows,а под Андроид при запуске висит только значок firemonkey секунд 10 и приложение вырубается так и не запустившись. В чем может быть проблема? Использую отладку по USB. 
      TIniFile *Ini = new TIniFile(System::Ioutils::TPath::GetDocumentsPath() + PathDelim + "options.ini"); Юзаю эти библиотеки 
      #include <System.IOUtils.hpp> #include <System.IniFiles.hpp>  
    • От gonzales
      Доброго времени суток!
      Решаю следующую задачу, в приложении динамически формируются разные объекты, наследники от одного класса. При формировании объектов заполняется динамический массив этих элементов. Далее я хочу в отдельном потоке для каждого из элементов массива получить его состояние, то есть делаю запрос к серверу. Все это повешено на таймер, каждую секунду должен отрабатываться запрос. Все более менее работает в Windows, а на Андроиде со временем приложение валится. Вот код таймера, для читаемости я удалил куски с различными вариантами E. RootElements - это массив TEssense от которого есть наследники. Функции GetBoardCurrentValue, GetBoardMaxValue - по сути запросы к серверу. 
      Подскажите, правильно ли я оформляю работу с потоками для работы на Андроиде?
      procedure TForm1.MasterTimerTimer(Sender: TObject); begin TTask.Run( procedure var l, d, a: byte; i,j:integer; E: TEssence; p: Pointer; VirtualNode: IXMLNode; VirtualElementNode: IXMLNode; id: byte; begin l := Length(Form1.RoomElements); for j := 0 to l - 1 do begin E := Form1.RoomElements[j]; // Реле if E is TRele then begin d := (E as TRele).Device_ID; a := (E as TRele).Device_Adress; if Form1.GetBoardCurrentValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin (E as TRele).ReleSwitch.IsChecked := Form1.device[d].Board[a].CurrentValue.ToBoolean; end); end; // (E as TRele).ReleOnTimer(E) end // Диммер else if E is TDimmer then begin d := (E as TDimmer).Device_ID; a := (E as TDimmer).Device_Adress; if Form1.GetBoardMaxValue(d, a) = true then begin TThread.Synchronize(nil, procedure begin if (Form1.device[d].Board[a].Type_ID = TType.Светодиод) or (Form1.device[d].Board[a].Type_ID = TType.Диммер220) then begin (E as TDimmer).DimmerValue.Text := (Form1.device[d].Board[a].MaxValue).ToString; end; end); end; // (E as TDimmer).DimmerOnTimer(E) end // Таймер else if E is TSTimer then begin id := (E as TSTimer).STimerIndex; Form1.FillHTTPRequest(0, 0, HTTP_GET_TIMER_INFO, id); if Form1.AnswerIsComming = HTTP_GET_TIMER_INFO then begin TThread.Synchronize(nil, procedure begin if Form1.HTTPAnswer.Data1 = 0 then (E as TSTimer).Interval.Text := 'OFF' else (E as TSTimer).Interval.Text := 'ON' end); end; // (E as TSTimer).STimerOnTimer(E); end; end; end); end;   
    • От andahay
      Доброго времени суток. Есть android приложение, в нем есть диалоговое окно, которое предлагает перейти в google play и скачать другое приложение (pro версию), с 2 кнопками (да/нет). Как реализовать этот переход в Google play, чтобы в нем сразу было загружено нужное приложение. Использую Delphi XE7
    • От zekelive
      Добрый день, друзья. Начал заниматься вопросом описанным в шапке и столкнулся со множеством непонятных для меня проблем. Как примерно должно выглядеть на Рис. ниже. Знаю, что сам список барабан выполнен в TlistBox. Есть хорошая ссылка на блог Ярослава тут. Пошерстил файлы в FMX, и не нашел ключа для своего дела. Может кто занимался этим? Я изначально брал TScrollBox, кидал на него Tlayout и в него TLabel. Но думаю, видимо не то совсем.

    • От zekelive
      Добрый день. Кто знает, подскажите, можно ли средствами firemonkey менять иконку приложения в рантайм либо после закрытия и повторного открытия приложения? На win вроде бы можно, статьи на форуме находил, а для Андроида найти не удалось.
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу