Tried creating an extension in Java, it crashes when tested in App

Hi there,
I made an extension in Java to store alarm data between different screens in an app. Currently when trying to run the app, the app will crash as soon as I try to get information out of the extension object. I am not sure why this is happening. Here is the extension I created:

package com.google.appinventor.components.runtime;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;

import java.lang.NumberFormatException;
import java.util.ArrayList;

@DesignerComponent(version = YaVersion.LABEL_COMPONENT_VERSION,
  description = "dummy object for alarm and location data",
  category = ComponentCategory.EXTENSION,
  nonVisible = true,
  iconName = "images/externalComponent.png")

@SimpleObject(external=true)
public final class AlarmLocationObject extends AndroidNonvisibleComponent {
  private String alarmName = "";
  private String alarmAddress = "";
  private String alarmLatitude = "";
  private String alarmLongitude = "";
  private String alarmHour = "";
  private String alarmMinute = "";


  /*public AlarmLocationObject(ComponentContainer container) {
   * super(container.$form());
  }*/

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "name of the alarm")
  public void createAlarm(AlarmLocationObject alarm1) {
    this.alarmName = alarm1.getAlarmName();
    this.alarmAddress = alarm1.getAlarmAddress();
    this.alarmLatitude = alarm1.getAlarmLatitude();
    this.alarmLongitude = alarm1.getAlarmLongitude();
    this.alarmHour = alarm1.getAlarmHour();
    this.alarmMinute = alarm1.getAlarmMinute();
  }

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "name of the alarm")
  public void setAlarmName(String alarmName) {
    this.alarmName = alarmName;
  }

  @SimpleProperty
  public String getAlarmName() {
    return alarmName;
  }
  
  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "address of the alarm")
  public void setAlarmAddress(String alarmAddress) {
    this.alarmAddress = alarmAddress;
  }

  @SimpleProperty
  public String getAlarmAddress() {
    return alarmAddress;
  }

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "location latitude")
  public void setAlarmLatitude(String alarmLatitude) {
    this.alarmLatitude = alarmLatitude;
  }

  @SimpleProperty
  public String getAlarmLatitude() {
    return alarmLatitude;
  }

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "location longitude")
  public void setAlarmLongitude(String alarmLongitude) {
    this.alarmLongitude = alarmLongitude;
  }

  @SimpleProperty
  public String getAlarmLongitude() {
    return alarmLongitude;
  }

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "alarm hour mark")
  public void setAlarmHour(String alarmHour) {
    this.alarmHour = alarmHour;
  }

  @SimpleProperty
  public String getAlarmHour() {
    return alarmHour;
  }

  @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_STRING)
  @SimpleProperty(description = "alarm minute mark")
  public void setAlarmMinute(String alarmMinute) {
    this.alarmMinute = alarmMinute;
  }

  @SimpleProperty
  public String getAlarmMinute() {
    return alarmMinute;
  }
}

Hello Chillie43

I have assigned your Topic to my colleague Gordon, who I hope will be available to take a look into this for you.

A simple App Inventor Project file dedicated to using your extension would help if you could upload one please, together with a brief description on how it is intended to use the extension and it's Blocks.

Use logcat ti get details of the error

Taifun

Thanks, let me see.

Why have you commented it? Constructor is must for every extension.

1 Like

Also,

This means that the Designer takes a string as the input, but the Blocks take an extension object as the input.

BTW, I don't understand why you use a property for this ... it is supposed to be a function.

I don't think variables stored in extensions in different screens can be the same ...

1 Like

Sorry, I commented that out temporarily in testing, realized it screwed it up and uncommented it. I guess I just forgot to uncomment it in the post.

I tried changing it to a function but that doesnt seem to be the issue as Im not actually using it atm. I'm passing the object between screens using the existing tinyDB but when I reference the object in the database it crashes.

this is the project I'm using it for:
better_alarms.aia (1.7 MB)

That's not possible to do.
TinyDB doesn't store value as Object.
Store all configuration in a list and then add a method in your extension to return that list.
Now this list can be stored in TinyDB easily.

Hence this is the reason of crash. When you retrieve it on other screen, you don't get an instance of AlarmLocationObject .

1 Like

Do you know whether app inventor uses an ArrayList or some other type of list?

AppInventor uses YailList.
An ArrayList can be converted into YailList in this way:

YailList.makeList(array_list);

what about converting from YailList to ArrayList so I can use the data in the YailList? I tried:

public void createAlarm(YailList list1) {
    this.alarmName = list1.getItem(0);
    this.alarmAddress = list1.getItem(1);
    this.alarmLatitude = list1.getItem(2);
    this.alarmLongitude = list1.getItem(3);
    this.alarmHour = list1.getItem(4);
    this.alarmMinute = list1.getItem(5);
  }

and I get this error when building:

C:\Users\waltersr\OneDrive - Wentworth Institute of Technology\Documents\Classes\senior project\my-extension\src\AlarmLocationObject.java:40: error: cannot find symbol
    [javac]     this.alarmName = list1.getItem(0);
    [javac]                           ^
    [javac]   symbol:   method getItem(int)
    [javac]   location: variable list1 of type YailList

using YailList.getItems() also results in the same issue

Sorry, I just noticed your post.

From what I see, the getItem method is listed as a method.

https://3nportal.com/AIBridge/API/com/google/appinventor/components/runtime/util/YailList.html#getItem(int)

I see only two methods to retrieve data by index:

 /**
   * Return the String at the given index.
   */
  public String getString(int index) {
    return get(index + 1).toString();
  }

  /**
   * Return the Object at the given index.
   */
  public Object getObject(int index) {
    return get(index + 1);
  }

If your variables are Strings, you can use the getString(index) method.
If your variables are of a different type, you can use getObject(index) and then cast the value to the type of your variable.

1 Like