Skip to content

Commit 5c7607f

Browse files
authored
optimize lazy imports to keep start speed at 0 (#54)
* Refactor platform detection and lazy imports- start-up speed issue * start-up speed issue 1 * cleanup and removed unnessary cache * incase someone switches activity and no androidx checks on non-android platform * write cleanup
1 parent 583bf0c commit 5c7607f

1 file changed

Lines changed: 123 additions & 36 deletions

File tree

‎android_notify/config.py‎

Lines changed: 123 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
1+
"""Environment detection and Android component accessors.
2+
3+
This module provides functions to determine the environment in which the code is running (e.g., Kivy on Android, Flet app, etc.)
4+
And to access Android-specific components like the activity, service, notification manager, and storage paths.
5+
6+
It uses lazy initialization to keep the startup time at 0 and avoid errors in non-Android environments.
7+
"""
8+
9+
110
import os
211

312
__version__ = "1.61.6"
413

514
from .internal.logger import logger
615

16+
17+
_activity_class_name = None
18+
19+
_jnius = None
20+
_python_activity = None
21+
_python_service = None
22+
_activity_context = None
23+
_app_storage_path = None
24+
_package_name = None
25+
_androidx_dependency = None
26+
727
def on_kivy_android():
828
kivy_build = os.environ.get('KIVY_BUILD', '')
9-
if kivy_build in {'android'}:
29+
if kivy_build == 'android':
1030
return True
1131
elif 'P4A_BOOTSTRAP' in os.environ:
1232
return True
@@ -21,18 +41,27 @@ def on_flet_app():
2141

2242

2343
def on_android_platform():
24-
return on_kivy_android() or on_flet_app()
44+
return on_kivy_android() or bool(on_flet_app())
2545

2646

27-
if on_android_platform():
28-
try:
29-
from jnius import cast, autoclass
30-
except ModuleNotFoundError:
47+
def _get_jnius():
48+
global _jnius
49+
50+
if _jnius is not None:
51+
return _jnius
52+
53+
if on_android_platform():
54+
try:
55+
from jnius import cast, autoclass
56+
except ModuleNotFoundError:
57+
cast = lambda x, y: x
58+
autoclass = lambda x: None
59+
else:
3160
cast = lambda x, y: x
3261
autoclass = lambda x: None
33-
else:
34-
cast = lambda x, y: x
35-
autoclass = lambda x: None
62+
63+
_jnius = (cast, autoclass)
64+
return _jnius
3665

3766

3867
def on_pydroid_app():
@@ -46,35 +75,55 @@ def on_pydroid_app():
4675
return False
4776

4877

78+
4979
def has_androidx_dependency():
50-
"""Check if androidx dependencies are available"""
80+
global _androidx_dependency
81+
82+
if _androidx_dependency is not None:
83+
return _androidx_dependency
84+
85+
if not on_android_platform():
86+
_androidx_dependency = False
87+
return _androidx_dependency
88+
5189
try:
52-
_=autoclass('androidx.core.app.NotificationCompat')
53-
return True
90+
_, autoclass = _get_jnius()
91+
autoclass("androidx.core.app.NotificationCompat")
92+
_androidx_dependency = True
5493
except Exception:
55-
return False
94+
_androidx_dependency = False
95+
96+
return _androidx_dependency
5697

5798

5899
def get_activity_class_name():
59-
ACTIVITY_CLASS_NAME = os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME") # flet python
60-
if not ACTIVITY_CLASS_NAME:
100+
global _activity_class_name
101+
102+
if _activity_class_name is not None:
103+
return _activity_class_name
104+
105+
activity_class_name = os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME") # flet python
106+
107+
if not activity_class_name:
61108
try:
62109
# noinspection PyPackageRequirements
63110
from android import config # type: ignore
64-
ACTIVITY_CLASS_NAME = config.JAVA_NAMESPACE
111+
activity_class_name = config.JAVA_NAMESPACE
65112
except (ImportError, AttributeError):
66-
ACTIVITY_CLASS_NAME = 'org.kivy.android'
67-
return ACTIVITY_CLASS_NAME
113+
activity_class_name = "org.kivy.android"
114+
115+
_activity_class_name = activity_class_name
116+
117+
return _activity_class_name
68118

69119

70120
def from_service_file():
71121
return 'PYTHON_SERVICE_ARGUMENT' in os.environ
72122

73123

74-
run_on_ui_thread = None
75124
if on_flet_app() or from_service_file() or not on_android_platform():
76125
def run_on_ui_thread(func):
77-
"""Fallback for Developing on PC"""
126+
"""Fallback for development/non-Kivy environments."""
78127

79128
def wrapper(*args, **kwargs):
80129
logger.warning("Simulating run on UI thread")
@@ -87,46 +136,73 @@ def wrapper(*args, **kwargs):
87136

88137

89138
def get_python_activity():
139+
global _python_activity
140+
141+
if _python_activity is not None:
142+
return _python_activity
143+
90144
if not on_android_platform():
91145
logger.warning("Can't get python activity, Not on Android.")
92146
from .internal.facade import PythonActivity
93-
return PythonActivity
94-
ACTIVITY_CLASS_NAME = get_activity_class_name()
147+
_python_activity = PythonActivity
148+
return _python_activity
149+
150+
_, autoclass = _get_jnius()
151+
activity_class_name = get_activity_class_name()
152+
95153
if on_flet_app():
96-
PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
154+
class_name = activity_class_name
97155
else:
98-
PythonActivity = autoclass(ACTIVITY_CLASS_NAME + '.PythonActivity')
99-
return PythonActivity
156+
class_name = activity_class_name + '.PythonActivity'
157+
_python_activity = autoclass(class_name)
158+
return _python_activity
159+
100160

101161

102162
def get_python_service():
163+
global _python_service
164+
165+
if _python_service is not None:
166+
return _python_service
167+
103168
if not on_android_platform():
104169
from .internal.facade import PythonActivity
105170
logger.warning("Can't get python service, Not on Android.")
106-
return PythonActivity
171+
_python_service = PythonActivity
172+
return _python_service
173+
174+
_, autoclass = _get_jnius()
107175
PythonService = autoclass(get_activity_class_name() + '.PythonService')
108-
return PythonService.mService
176+
_python_service = PythonService.mService
177+
return _python_service
109178

110179

111180
def get_python_activity_context():
181+
global _activity_context
182+
183+
if _activity_context is not None:
184+
return _activity_context
185+
112186
if not on_android_platform():
113187
logger.warning("Can't get python context, Not on Android.")
114188
from .internal.facade import Context
115-
return Context
189+
_activity_context = Context
190+
return _activity_context
116191

117-
PythonActivity = get_python_activity()
118192
if from_service_file():
119193
service = get_python_service()
120-
context = service.getApplication().getApplicationContext()
194+
_activity_context = service.getApplication().getApplicationContext()
121195
else:
122-
context = PythonActivity.mActivity
123-
return context
196+
PythonActivity = get_python_activity()
197+
_activity_context = PythonActivity.mActivity
198+
return _activity_context
124199

125200

126201
def get_notification_manager():
127202
if not on_android_platform():
128203
logger.warning("Can't get notification manager, Not on Android.")
129204
return None
205+
cast, autoclass = _get_jnius()
130206
NotificationManager = autoclass('android.app.NotificationManager')
131207

132208
context = get_python_activity_context()
@@ -135,16 +211,27 @@ def get_notification_manager():
135211

136212

137213
def app_storage_path():
214+
global _app_storage_path
215+
216+
if _app_storage_path is not None:
217+
return _app_storage_path
218+
138219
if on_flet_app():
139220
context = get_python_activity_context()
140-
return os.path.join(context.getFilesDir().getAbsolutePath(), 'flet')
221+
_app_storage_path = os.path.join(context.getFilesDir().getAbsolutePath(), 'flet')
141222
elif on_kivy_android():
142223
# noinspection PyPackageRequirements
143224
from android.storage import app_storage_path as kivy_app_storage_path # type: ignore
144-
return kivy_app_storage_path()
225+
_app_storage_path = kivy_app_storage_path()
145226
else:
146-
return os.getcwd() # TODO return file main.py path (not android)
227+
_app_storage_path = os.getcwd()
228+
return _app_storage_path
147229

148230

149231
def get_package_name():
150-
return get_python_activity_context().getPackageName() # package.domain + "." + package.name
232+
global _package_name
233+
234+
if _package_name is not None:
235+
return _package_name
236+
_package_name = get_python_activity_context().getPackageName()
237+
return _package_name

0 commit comments

Comments
 (0)