android
android copied to clipboard
Error running java.util.TimerTask
Environment
- CLI: 7.1.2
- Cross-platform modules: none
- Android Runtime: 6.0.0
- iOS Runtime (if applicable): not applicable
- Plugin(s): none
Describe the bug
I'm trying to extend the abstract class java.util.TimerTask with no success (I wonder if it's even possible), here's what I tried:
// my-timer-task.ts
@NativeClass()
class MyTimerTask extends java.util.TimerTask {
constructor() {
super();
}
public run() {
console.log('MyTimerTask run called');
}
}
export { MyTimerTask };
// index.andorid.ts
import { MyTimerTask } from './my-timer-task';
export class MyPlugin extends MyPluginCommon {
public test() {
try {
const timer: java.util.Timer = new java.util.Timer();
timer.schedule(new MyTimerTask(), 0, 1000);
} catch (e) {
console.log('Error', e);
}
}
}
}
And I get this error:
java.lang.Exception: Failed resolving constructor for class 'java.util.TimerTask_0_95_23_MyTimerTask' with 0 parameters. Check the number and type of arguments.
Primitive types need to be manually wrapped in their respective Object wrappers.
If you are creating an instance of an inner class, make sure to always provide reference to the outer `this` as the first argument.
I have also tried these variants of the timer implementation:
// global.__native(this)
class MyTimerTask extends java.util.TimerTask {
constructor() {
super();
global.__native(this);
}
public run() {
console.log('MyTimerTask run called');
}
}
// extend function
const MyTimerTask = (java as any).util.TimerTask.extend({
run() {
console.log('MyTimerTask run called');
},
});
const myTimerTask = new MyTimerTask();
// implementation parameter
const myTimerTask = new java.util.TimerTask({
run() {
console.log('MyTimerTask run called');
},
});
// NativeClass & implementation parameter with re-defining the TimerTask definition
declare module java {
export module util {
export abstract class TimerTask extends java.lang.Object implements java.lang.Runnable {
public static class: java.lang.Class<java.util.TimerTask>;
public cancel(): boolean;
public scheduledExecutionTime(): number;
public run(): void;
// public constructor();
public constructor(params: any);
}
}
}
@NativeClass()
class MyTimerTask extends java.util.TimerTask {
constructor() {
super({
run: () => this.run()
});
}
public run() {
console.log('MyTimerTask run called');
}
}
I have also considered creating the class in Java and using it in naivescript, but I don't know if it'll work and I prefer writing the implementation in naivescript.
To Reproduce Generate a new plugin using the seed, try any of the above examples on android emulator.
Expected behavior
A MyTimerTask instance is created and it's run function is called in interval by the Timer.
Sample project Will add one if necessary.
Additional context
I know there are other ways to have code execute in interval, but this is just a simplification of a wider scenario where a java library requires a TimerTask as a parameter and can't really be worked around.
Found the generated java class in the demo-app test-plugins/apps/demo-angular/platforms/android/app/src/main/java/com/tns/gen/java/util folder (i'm using the plugin seed),
here's the content:
/* AUTO-GENERATED FILE. DO NOT MODIFY.
* This class was automatically generated by the
* static binding generator from the resources it found.
* Please do not modify by hand.
*/
package com.tns.gen.java.util;
public class MyTimerTask extends java.util.TimerTask
implements com.tns.NativeScriptHashCodeProvider {
protected MyTimerTask() {
super();
com.tns.Runtime.initInstance(this);
}
public void run() {
java.lang.Object[] args = new java.lang.Object[0];
com.tns.Runtime.callJSMethod(this, "run", void.class, args);
}
public int hashCode__super() {
return super.hashCode();
}
public boolean equals__super(java.lang.Object other) {
return super.equals(other);
}
}
I was able to work around the problem by adding a java class to the demo folder which extends TimerTask and extending the derived class in TS, java class content:
// This file is not in the "gen" folder so we can keep it between builds
package com.tns.avif;
public class BaseTimerTask extends java.util.TimerTask {
public BaseTimerTask() {
super();
}
public void run() {
}
}
It would seem the the auto generated constructor "protected" modifier is the culprit, and there is no way to change it from the TS side that I can find.
When extending classes in typescript you need to return global.__native(this); in the constructor
// my-timer-task.ts
@NativeClass()
class MyTimerTask extends java.util.TimerTask {
constructor() {
super();
return global.__native(this);
}
public run() {
console.log('MyTimerTask run called');
}
}