Skip to content

Conversation

m1ga
Copy link
Contributor

@m1ga m1ga commented Aug 6, 2025

Have an app that has an ANR that points to getBool and a JSONException when reading the value. While I'm not 100% sure if this is the fix for that it will improve reading the properties a bit.

Exception:

      main (runnable):tid=1 systid=17102 
       at android.app.SharedPreferencesImpl.getBoolean(SharedPreferencesImpl.java:343)
       at org.appcelerator.titanium.TiProperties.getBool(TiProperties.java:231)
       at ti.modules.titanium.app.properties.PropertiesModule.getBool(PropertiesModule.java:33)
       at org.appcelerator.kroll.runtime.v8.V8Function.nativeInvoke(Native method)
       at org.appcelerator.kroll.runtime.v8.V8Function.callSync(V8Function.java:55)
       at org.appcelerator.kroll.runtime.v8.V8Function.call(V8Function.java:41)
       at ti.modules.titanium.TitaniumModule$Timer.run(TitaniumModule.java:142)
       at android.os.Handler.handleCallback(Handler.java:958)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:230)
       at android.os.Looper.loop(Looper.java:319)
       at android.app.ActivityThread.main(ActivityThread.java:8919)
       at java.lang.reflect.Method.invoke(Native method)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)

and

at java.lang.Throwable.nativeFillInStackTrace(Native method)
       at java.lang.Throwable.fillInStackTrace(Throwable.java:819)
       at java.lang.Throwable.<init>(Throwable.java:286)
       at java.lang.Exception.<init>(Exception.java:67)
       at org.json.JSONException.<init>(JSONException.java:47)
       at org.json.JSONObject.get(JSONObject.java:398)
       at org.json.JSONObject.getBoolean(JSONObject.java:419)
       at org.appcelerator.titanium.TiProperties.getBool(TiProperties.java:229)
       at ti.modules.titanium.app.properties.PropertiesModule.getBool(PropertiesModule.java:33)
       at org.appcelerator.kroll.runtime.v8.V8Function.nativeInvoke(Native method)
       at org.appcelerator.kroll.runtime.v8.V8Function.callSync(V8Function.java:55)
       at org.appcelerator.kroll.runtime.v8.V8Function.call(V8Function.java:41)
       at ti.modules.titanium.TitaniumModule$Timer.run(TitaniumModule.java:142)
       at android.os.Handler.handleCallback(Handler.java:959)
       at android.os.Handler.dispatchMessage(Handler.java:100)
       at android.os.Looper.loopOnce(Looper.java:257)
       at android.os.Looper.loop(Looper.java:342)
       at android.app.ActivityThread.main(ActivityThread.java:9634)
       at java.lang.reflect.Method.invoke(Native method)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:619)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929)

Current way
Currently Ti SDK flow is:

if (systemProperties != null) {
  try {
    value = systemProperties.getBoolean(key);
  } catch (JSONException e) {
    value = preferences.getBoolean(key, def);
  }
} else {
  value = preferences.getBoolean(key, def);
}

(source)

It tries to read it from systemProperties, that fails and then it reads it from the preferences.

With this PR
This PR will check if systemProperties has the key and if not just it will just go to the else case and not waiting for the try/catch error to happen.


Test code to read/write some properties:

Ti.App.Properties.setString('givenName', 'Paul');
console.log('The value of the givenName property is: ' + Ti.App.Properties.getString('givenName'));

Ti.App.Properties.setBool('boolValue', true);
console.log('boolValue', Ti.App.Properties.getBool('boolValue', false));

console.log('boolValueDefault1', Ti.App.Properties.getBool('boolValueDefault1', false));
console.log('boolValueDefault2', Ti.App.Properties.getBool('boolValueDefault2'));

// get all
var props = Ti.App.Properties.listProperties();
for (var i = 0, ilen = props.length; i < ilen; i++) {
	var value = Ti.App.Properties.getString(props[i]);
	console.log(props[i] + ' = ' + value);
}

@prashantsaini1
Copy link
Contributor

@m1ga I doubt this would actually resolve that ANR because the try-catch is essentially doing the same thing. If there's no property in systemProperties, it would go to catch block anyways. Is it possible to share more details of that ANR here, or on Slack to me in DM?

@m1ga
Copy link
Contributor Author

m1ga commented Aug 17, 2025

I've added the crashlytics stack to the first post. The last Ti place is before going into the native preferences to fetch the value. I don't know if the property doesn't exists but since it's throwing that error in the native code it might not be there and then my check would prevent it from trying to read it at all (thought it might even be quicker if not waiting for a catch exception)

@prashantsaini1
Copy link
Contributor

Looks like in your case there are some other ops going on that same property as I see a Timer runnable (seems unusual here). SharedPref ops are still I/O blocking in Titanium SDK which are often the root cause of many ANRs.

For now, you can also use the hasProperty(String key) method in this same class. For long term, I can start working on Async Shared Preferences.

@m1ga
Copy link
Contributor Author

m1ga commented Aug 17, 2025

oh, interesting! I thought #13944 was already helping here but that makes sense that it is blocked somewhere.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants