User files are lost after updating Kivy app on Android

152 views
Skip to first unread message

Giù sé

unread,
Jun 17, 2020, 5:59:15 AM6/17/20
to Kivy users support
I have not been able to preserve user files in between updates of my Kivy Android app. The only file I need to preserve is a .db file. To achieve that, my code includes:


db = db_path
if db.is_file():
    print("DB already exists")
else:
    createDb(db)

which checks whether the .db file exists, and if not, it is created (this should indeed happen only on the first install of the app).

The file to be preserved is located in the folder above the one containing app.py, as I understood is required in order to keep user files (i.e. the app.py is located in App/app.py, while the db is located in user/database.db).

Am I doing something wrong?

K leo

unread,
Jun 17, 2020, 6:53:25 AM6/17/20
to Kivy users support
I seem also to experience this, and hope to find a solution.

Robert Flatt

unread,
Jun 17, 2020, 1:09:40 PM6/17/20
to Kivy users support
My understanding is that app.user_data_dir should persist between updates but not uninstalls.
Nothing else survives an update.


On Android, Context.GetFilesDir is returned.

K leo

unread,
Jun 17, 2020, 1:53:55 PM6/17/20
to Kivy users support
From the bottom of the link page:

On Android, Context.GetFilesDir is returned.

Changed in version 1.11.0: On Android, this function previously returned /sdcard/<app_name>. This folder became read-only by default in Android API 26 and the user_data_dir has therefore been moved to a writeable location.


I think I tested with Kivy 1.11.1, user_data_dir on Android is /Data/ which is not permissible for writing.  I had to use the following to get the dir path:
        if platform == 'android':
           
from android.storage import app_storage_path
            datadir
= app_storage_path()
So I guess that path is not preserved during update?

Robert Flatt

unread,
Jun 17, 2020, 3:11:58 PM6/17/20
to Kivy users support

Giù sé

unread,
Jun 17, 2020, 5:53:08 PM6/17/20
to Kivy users support
I don't really understand this. Right now, my code reads:

db_path = Path('user/database.db')

How do I refer to user_data_dir?

Robert Flatt

unread,
Jun 17, 2020, 8:14:21 PM6/17/20
to Kivy users support
To understand, first stop thinking Android is POSIX, it is not. POSIX is so deep in our assumptions we don't even know its there.
This means read the Android docs.
Never use absolute paths, they may not be portable between devices.

To help with understanding, build a small test case and run it on Android.
(set build orientation to landscape or all so yuo can see the paths)

For example:

from kivy.app import App
from kivy.uix.label import Label
from android.storage import app_storage_path
from os.path import abspath
from os import getcwd

class MyApp(App):
   
def build(self):
        text
= App.get_running_app().user_data_dir + '\n'
        text
+= self.user_data_dir + '\n'
        text
+= app_storage_path() + '\n'
        text
+= getcwd() + '\n'
        text
+= abspath('.') + '\n'
        text
+= abspath('~') + '\n'
        text
+= abspath(__file__) +'\n'
       
return Label(text=text)

if __name__ == '__main__':
   
MyApp().run()

Giù sé

unread,
Jun 18, 2020, 12:32:31 PM6/18/20
to Kivy users support
Very helpful, thank you! However, I have an additional problem when implementing this into my code. My app.py script reads:

class RecipApp(App):
    def build(self):
        user_dir = App.get_running_app().user_data_dir
        print('THE DIRECTORY IS: ',user_dir)
        dbFile = user_dir+'/recipes.db'


Now the problem is, I have a query.py script where I define a number of functions related to DB operations. For this, I therefore need to call 'dbFile' (the path of the DB) defined in app.py. How can I do this?

I also tried including the same code (i.e. 'user_dir = App.get_running_app().user_data_dir') in query.py to get the user_dir directly. This. however, does not work either.

Robert Flatt

unread,
Jun 18, 2020, 1:02:49 PM6/18/20
to Kivy users support
Not very specific, but reading between the lines:

Either: pass  dbFile to the class in query.py when (or after) it is instantiated
Or: import App in query.py

Giù sé

unread,
Jun 18, 2020, 2:02:04 PM6/18/20
to Kivy users support
My file structure is as follows:

RecipApp/
|-RecipApp/
|  |-db/
|  |  |-query.py
|  |  |-__init__.py
|  |-app.py
|  |-__init__.py
|-main.py

in app.py, I have:

class RecipApp(App):
    def build(self):
        user_dir = App.get_running_app().user_data_dir
        dbFile = user_dir+'/recipes.db'


and query.py contains a bunch of methods which need to use the path of the database ('dbFile'). For example:

def fetchIngredients(ingInput):  
    conn = sqlite3.connect(dbFile)


Elliot Garbus

unread,
Jun 18, 2020, 3:26:21 PM6/18/20
to kivy-...@googlegroups.com

Here is what I would suggest:

 

 

class RecipApp(App):

 

    @property

    def dbfile(self):

        return self.user__data_dir+'/recipes.db'

# in the App class, self is App.get_running_app()

 

def fetchIngredients(ingInput): 

    app = App.get_running_app()

    conn = sqlite3.connect(app.dbfile)

 

 

As an FYI you might also want to look at the pathlib library in the python standard library for constructing and manipulating file manes and paths.

--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/39677ec4-fa9e-41ee-92a3-b39ebed316e5o%40googlegroups.com.

 

Giù sé

unread,
Jun 18, 2020, 5:46:30 PM6/18/20
to Kivy users support
I had tried this already. It results in:

AttributeError: 'NoneType' object has no attribute 'dbFile'

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-...@googlegroups.com.

Robert Flatt

unread,
Jun 18, 2020, 6:05:20 PM6/18/20
to Kivy users support
Try android.storage app_storage_path()

As in the example.

Elliot Garbus

unread,
Jun 18, 2020, 7:16:52 PM6/18/20
to kivy-...@googlegroups.com

Looks like an error somewhere,   attach some code.

To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/d2b6bdd8-372f-43a1-b67c-c9d7693e9b63o%40googlegroups.com.

 

Robert Flatt

unread,
Jun 18, 2020, 7:44:09 PM6/18/20
to Kivy users support
I infer this is a mixture of OO and script style code. OO techniques probably wont work.

Giù sé

unread,
Jun 19, 2020, 5:44:56 AM6/19/20
to Kivy users support
You are right indeed about mixing script and OO. Using Path from pathlib works on Windows, but it gives me error on Android. However this was a very precious advice.

I have solved my issue thanks to os.path. Now my query.py reads:

from kivy.utils import platform
from pathlib import Path
import os.path

if platform == 'android':
    from android.storage import app_storage_path
    user_data_dir = app_storage_path()
    dbFile = user_data_dir+'/recipes.db'
else:
    dbFile = Path('user/recipes.db')

def dbInit():
    if os.path.isfile(dbFile):
        return dbFile
    else:
        conn = sqlite3.connect(dbFile)
        # a bunch of sqlite operations
        return dbFile

and from app.py I simply do:

class RecipApp(App):
    manager = ObjectProperty()
  
    def build(self):
        dbFile = dbInit()

Tested it and finally my dbFile is preserved between updates on Android. 
Reply all
Reply to author
Forward
0 new messages