https://github.com/nativescript/marking-mode-example
An example demonstrating how to enable "markingMode: none" and fix a common error related to its usage.
https://github.com/nativescript/marking-mode-example
Last synced: 4 months ago
JSON representation
An example demonstrating how to enable "markingMode: none" and fix a common error related to its usage.
- Host: GitHub
- URL: https://github.com/nativescript/marking-mode-example
- Owner: NativeScript
- License: apache-2.0
- Created: 2019-02-06T13:45:07.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2019-02-07T15:03:12.000Z (over 7 years ago)
- Last Synced: 2025-09-19T00:45:49.501Z (9 months ago)
- Language: JavaScript
- Size: 2.56 MB
- Stars: 0
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# An app with markingMode:none enabled
This repo includes a {N} app with `markingMode: none` enabled. It reporoduces 2 common errors related to using this feature.
## To make it crash
1. Run the app:
```bash
tns run android
```
2. Click on `ADD BUTTON WITH CLICK LISTENER` button to create a native Android button with a native `click` callback.
3. Click the generated button intermittently (until crash).
At some time (within a minute) the app will crash with either of the following errors:
- `Error: com.tns.NativeScriptException: Attempt to use cleared object reference id=`
- `The JavaScript instance no longer has available Java instance counterpart`
## To fix it
Find the "UNCOMMENT THE FIX" lines in `home-page.ts` and uncomment them.
## But wait, what happened? (explanation)
Consider this method from `home-page.ts`:
```js
public onAddClickListener() {
let root = currentPage.getViewById('root');
let btn = new android.widget.Button(root._context);
btn.setText("ta-daa, now click!");
root.android.addView(btn);
let file = new java.io.File('real file');
btn.setOnClickListener(new android.view.View.OnClickListener(
{
onClick: () => {
this.fileName = `${file.getName()} exists at ${new Date().toTimeString()}`;
}
}
));
}
```
If you look in `onAddClickListener()` handler in the `ViewModel`, you will see that:
1. A native Android `android.widget.Button` is created and added to the page.
2. A native `java.io.File` is created.
3. An OnClickListener interface implementation is set to the button, and inside we **call file.getName()**.
So, the `java.io.File` instance is enclosed by the native button's `onClick` callback implementation, but with `markingMode: none` enabled the framework longer takes care of finding out that connection. When GC happens in V8 or in Android the `java.io.File` instance (or its native representation) is GC'ed. This can result in either Java or JavaScript instance missing and upon calling of the `onClick` the app crashes with any of the a.m. errors.
To prevent this from happening, we should make sure the `java.io.File` instance is alive as long as we need it in the app execution. In it would be enough to live as long as the ViewModel instance is alive (we don't expect we should handle button clicks when the view is dead, right?). That is why we make it a property of the `ViewModel` class:
```js
export class ViewModel extends Observable {
...
private myFile: java.io.File;
...
```
and use it in the callback implementation like:
```js
btn.setOnClickListener(new android.view.View.OnClickListener(
{
onClick: () => {
this.fileName =`${this.myFile.getName()} exists at ${new Date().toTimeString()}`;
}
}
));
```
This will ensure that the GC will not collect the `java.io.File` instance unless the object that holds it (the `ViewModel` instance) is not collecteted.