OutOfMemoryError using MapContainer - codenameone

After my splash screen, my mainform contains a MapContainer where I show a several points. It works well on Simulator. On device however, after some seconds, the phone just hangs and the app crashes. Does it have anything to do with the way I add multiple points? I have shown the code below. I have also added my LogCat stackTrace.
public void addMarkers(MapContainer mc)
{
Vector v= new Vector();
try
{
Style s = new Style();
s.setFgColor(0xff0000);
s.setBgTransparency(0);
FontImage markerImg = FontImage.createMaterial(FontImage.MATERIAL_PLACE, s, 7);
EncodedImage ei = EncodedImage.createFromImage(markerImg, false);
List lx = (List) Storage.getInstance().readObject("CASES");
Coord c = null;
for(Object m: lx)
{
Map p= (Map) m;
c = new Coord(Double.parseDouble(p.get("latitude").toString()), Double.parseDouble(p.get("longitude").toString()));
v.add(c);
mc.addMarker(ei, c, "Hi marker", "Optional long description", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
ToastBar.showMessage("You clicked the marker", FontImage.MATERIAL_PLACE);
}
});
}
mc.fitBounds(BoundingBox.create(v));
}catch(Exception er){er.printStackTrace();}
}
And my LogCat strackTrace below
01-29 00:06:24.407 21924-22089/com.jajitech.mobile.creporter E/AndroidRuntime: FATAL EXCEPTION: androidmapsapi-Snapshot
Process: com.jajitech.mobile.creporter, PID: 21924
java.lang.OutOfMemoryError: Failed to allocate a 1831692 byte allocation with 48112 free bytes and 46KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:975)
at android.graphics.Bitmap.createBitmap(Bitmap.java:946)
at android.graphics.Bitmap.createBitmap(Bitmap.java:913)
at com.google.maps.api.android.lib6.impl.a.b(:com.google.android.gms.dynamite_mapsdynamite#14366045#14.3.66 (040304-213742215):9)
at com.google.maps.api.android.lib6.impl.bk.run(:com.google.android.gms.dynamite_mapsdynamite#14366045#14.3.66 (040304-213742215):4)
at java.lang.Thread.run(Thread.java:818)

Related

How to use the retrieveConnected method?

I'd like to know how to use the retrieveConnected() method from the Bluetooth class please. This class is part of the CN1Bluetooth.cn1lib.
I don't know how to get the paired devices with this method.
Unfortunately, there are no examples about the using of this method.
EDIT:
I used retrieveConnected() as you told me to do:
Button retco = new Button("Retrieve");
this.add(retco);
retco.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ev) {
try {
debug("Action performed 1: "+ev);
debug("Bt: "+bt);
ArrayList ar = new ArrayList();
//ar.add("180D");
debug("array: "+ar);
bt.retrieveConnected(
new ActionListener() {
public void actionPerformed(ActionEvent ev) {
debug("actionPerformed : " + ev);
main.add(new SpanLabel("TEST 3"));
debug("ev.getSource() = " + ev.getSource());
JSONObject res = (JSONObject)ev.getSource();
debug("RES = " + res);
try {
updateUI(res);
} catch (JSONException e) {
// TODO Auto-generated catch block
debug(e.getMessage());
}
};
},ar);
} catch (IOException e) {
// TODO Auto-generated catch block
debug(e.getMessage());
}
}
});
private void updateUI(JSONObject obj) throws JSONException {
this.add(new SpanLabel(obj.toString()));
this.add(new SpanLabel("TEST"));
this.revalidate();
}
But i have those error messages
ca.weblite.codename1.json.JSONException: A JSONObject text must begin with '{' at character 1 of []
at ca.weblite.codename1.json.JSONTokener.syntaxError(JSONTokener.java:448)
at ca.weblite.codename1.json.JSONObject.<init>(JSONObject.java:176)
at ca.weblite.codename1.json.JSONObject.<init>(JSONObject.java:253)
atcom.codename1.cordova.CordovaCallbackManager.sendResult(CordovaCallbackManager.java:50)
at com.codename1.cordova.CallbackContext.sendPluginResult(CallbackContext.java:26)
at com.codename1.bluetoothle.BluetoothLePlugin.retrieveConnectedAction(BluetoothLePlugin.java:1212)
at com.codename1.bluetoothle.BluetoothLePlugin.execute(BluetoothLePlugin.java:306)
at com.codename1.cordova.CordovaPlugin.execute(CordovaPlugin.java:34)
at com.codename1.cordova.CordovaNativeImpl.execute(CordovaNativeImpl.java:14)
at com.codename1.cordova.CordovaNativeStub.execute(CordovaNativeStub.java:9)
at com.codename1.cordova.Cordova.execute(Cordova.java:29)
at com.codename1.bluetoothle.Bluetooth.retrieveConnected(Bluetooth.java:129)
at be.ssii.app.forms.EidReader$3.actionPerformed(Unknown Source:97)
at com.codename1.ui.util.EventDispatcher.fireActionEvent(EventDispatcher.java:349)
at com.codename1.ui.Button.fireActionEvent(Button.java:570)
at com.codename1.ui.Button.released(Button.java:604)
at com.codename1.ui.Button.pointerReleased(Button.java:708)
at com.codename1.ui.Form.pointerReleased(Form.java:3369)
at com.codename1.ui.Component.pointerReleased(Component.java:4552)
at com.codename1.ui.Display.handleEvent(Display.java:2180)
at com.codename1.ui.Display.edtLoopImpl(Display.java:1152)
at com.codename1.ui.Display.mainEDTLoop(Display.java:1070)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120)
at com.codename1.impl.CodenameOneThread$1.run(CodenameOneThread.java:60)
at java.lang.Thread.run(Thread.java:764)
There is one device paired to the device which use the app but it doesn't detect the paired one. It should work, the paired device is a BLE device.
The method retrieved paired Bluetooth LE devices. In iOS, devices that are "paired" to will not return during a normal scan. Callback is "instant" compared to a scan. UUID filtering might not work on Android, so it returns all paired BLE devices.
bluetoothle.retrieveConnected(e -> { }, params);
The params value is an array of service IDs to filter the retrieval by. If no service IDs are specified, no devices will be returned.
E.g.
ArrayList a = new ArrayList();
a.add("180D");
a.add("180F");
On success you should get an array of device objects as a result.
However looking at the code here: https://github.com/chen-fishbein/bluetoothle-codenameone/blob/master/CN1Bluethooth/src/com/codename1/bluetoothle/Bluetooth.java#L135
It looks like this line is wrong and should be changed from this:
plugin.execute("retrieveConnected", j.toString(), callack);
To this:
plugin.execute("retrieveConnected", callack, callack, j.toString());
But I haven't tested this.

Adding x number Markers to Codenameone MapContainer at runtime

I have retrieved a large number of latlong values and stored in an ArrayList. I want to add markers to my MapContainer using the latlong values in the ArrayList. The challenges however is that the pins are never positioned correctly on the map (simulator and device). I have tried everything but still no success. Here is a working example. This works but the pins are positioned wrongly at runtime.
Form hi = new Form("cReporter", new BorderLayout());
hi.setScrollableY(false);
Container n = new Container(new BorderLayout());
MapContainer mc = new MapContainer();//
mc.setShowMyLocation(true);
hi.add("Center", mc);
List lx = new ArrayList();
addPoints(lx);
hi.show();
addMarkers(mc, lx);
public void addPoints(List lx)
{
Map m= new HashMap();
m.put("long", 8.993082);
m.put("lat", 38.747393);
lx.add(m);
m= new HashMap();
m.put("long", 8.988419);
m.put("lat", 38.727094);
lx.add(m);
m= new HashMap();
m.put("long", 8.991724);
m.put("lat", 38.775203);
lx.add(m);
}
public void addMarkers(MapContainer mc, List coordList)
{
Style s = new Style();
s.setFgColor(0xff0000);
s.setBgTransparency(0);
FontImage markerImg = FontImage.createMaterial(FontImage.MATERIAL_PLACE, s, 5);
for(Object m: coordList)
{
Map p= (Map)m;
Coord moscone = new Coord(Double.parseDouble(p.get("lat").toString()), Double.parseDouble(p.get("long").toString()));
mc.addMarker(EncodedImage.createFromImage(markerImg, false), mc.getCameraPosition(), "Hi marker", "Optional long description", new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println("Bounding box is "+mc.getBoundingBox());
ToastBar.showMessage("You clicked the marker", FontImage.MATERIAL_PLACE);
}
});
mc.setCameraPosition(moscone);
mc.revalidate();
}
}
I'm guessing that you aren't using the correct projection lat/long values for the map as these vary based on different implementations. See this for discussion of the different types of positioning: Source event strange latitude & longitude
I notice you create a new encoded image for every marker position. This is very inefficient as every such image would take up RAM and doing it x100 could introduce a serious overhead. This is an image you should reuse.

Crash on iOS when downloading and inserting in Database

I have a problem with my application on iOS only (iPad 9.7" 11.3.1), it works perfectly on the simulator and on Android device.
When the app is launched for the first time, the user has to log in. This works fine. After that, the menu form is launched and a Dialog is shown on onShowCompleted():
if (!Preferences.get("download", false)) {
dialog = new Dialog("...");
dialog.setLayout(new BorderLayout());
SpanLabel label = new SpanLabel("...");
dialog.addComponent(BorderLayout.CENTER, label);
dialog.show(Display.getInstance().getDisplayHeight() / 5, ..., ..., ...);
}
In the constructor, a method that downloads informations is launched :
if (!Preferences.get("download", false)) {
dlReferentiel();
}
The method :
public void dlReferentiel() {
source = DataSource.getInstance();
// I also tried with invokeAndBlock() but doesn't work
/*
Display.getInstance().invokeAndBlock(() -> requestS());
Display.getInstance().invokeAndBlock(() -> requestB());
Display.getInstance().invokeAndBlock(() -> requestZ());
Display.getInstance().invokeAndBlock(() -> requestA());
*/
requestS();
requestB();
requestZ();
requestA();
}
The requestX methods get informations from server with ConnectionRequest :
(Exemple with requestA() which needs to be the last because it disposes the dialog, it is the only one that calls the UI)
public void requestA() {
ConnectionRequest connectionRequest = new ConnectionRequest() {
ArrayList<A> as = new ArrayList<>();
#Override
protected void readResponse(InputStream in) throws IOException {
JSONParser json = new JSONParser();
Reader reader = new InputStreamReader(in, "UTF-8");
Map<String, Object> data = json.parseJSON(reader);
for (String s : data.keySet()) {
as.add(new A(s, (String) data.get(s)));
}
}
#Override
protected void postResponse() {
source.createAllA(as); // makes insertions with Transaction
ToastBar.showErrorMessage("Référentiel téléchargé", 10);
dialog.dispose();
Preferences.set("download", true);
}
};
connectionRequest.setUrl(URL_A);
connectionRequest.setPost(true);
NetworkManager.getInstance().addToQueue(connectionRequest);
}
I was able to see some logs with a Mac. Each time, the app crashes after the Dialog is shown and few insertions are made. The same error message is output :
HW kbd: Failed to set (null) as keyboard focus
Unable to get short BSD proc info for 513: No such process
Unable to get proc info for 513: Undefined error: 0
I search for informations about this issue but nothing interesting with Codename One.
I don't know what to do with this error, I tried some things like using invokeAndBlock() or changing build hints like ios.keyboardOpen (just because there is "keyboard" in it) but nothing worked.
Thanks for the help.

Timer in Javafx Creating FX Thread null pointers and out of bounds exceptions

I was trying to make a simple timer in Javafx with a GUI and Timer class. When the start button is pressed, it is supposed to count down from the inputed time and stop when it reaches 0.
I have the remaining time in milliseconds updating in a TextField on the GUI but it only runs for a random number of milliseconds usually between 100-200 and then it freezes up and throws a VERY large number of exceptions.
I tried to pinpoint where the error was coming from, and found there was also a concurrent modification exception as well.
Here is my Timer class:
import java.sql.Time;
/**
* Created by Josh on 19/8/2015.
*/
public class Timer {
private long endTimeMillis;
public Timer(long hours, long minutes, long seconds){
long currentTime = System.currentTimeMillis();
endTimeMillis = ((seconds*1000 + minutes*1000*60 + hours*1000*60*60) + currentTime);
}
public boolean isFinished(){
long currentTime = System.currentTimeMillis();
if(endTimeMillis - currentTime <= 0){
return true;
}else{
return false;
}
}
public long getRemainingTimeMillis(){
long currentTime = System.currentTimeMillis();
return endTimeMillis - currentTime;
}
}
and this is the GUI
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
/**
* Created by Josh on 19/8/2015.
*/
public class GUI extends Application {
private BorderPane root;
Label hoursLabel, minutesLabel, secondsLabel;
TextField hoursTF, minutesTF, secondsTF;
Button startButton;
Label remainingTimeLabel;
TextField remainingTimeTF;
long remainingTime;
#Override
public void start(Stage primaryStage) throws Exception {
root = new BorderPane();
primaryStage.setScene(new Scene(root, 1300, 125));
primaryStage.show();
primaryStage.setResizable(true);
primaryStage.setTitle("Timer");
primaryStage.setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
event.consume();
System.exit(0);
}
});
FlowPane center = new FlowPane();
hoursLabel = new Label(" Hours: ");
hoursTF = new TextField();
minutesLabel = new Label(" Minutes: ");
minutesTF = new TextField();
secondsLabel = new Label(" Seconds: ");
secondsTF = new TextField();
center.getChildren().addAll(hoursLabel, hoursTF, minutesLabel, minutesTF, secondsLabel, secondsTF);
root.setCenter(center);
FlowPane bottom = new FlowPane();
bottom.setAlignment(Pos.CENTER);
startButton = new Button("Start");
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
start();
}
});
remainingTimeLabel = new Label(" Time Remaining: ");
remainingTimeTF = new TextField();
bottom.getChildren().addAll(startButton, remainingTimeLabel, remainingTimeTF);
root.setBottom(bottom);
}
public void start(){
Task timer = new Task<Void>() {
#Override
protected Void call() throws Exception {
long hours = 0, minutes = 0, seconds = 0;
try{
if(hoursTF.getText() == null || hoursTF.getText().equals("")){
hours = 0;
}else{
hours = Long.parseLong(hoursTF.getText());
}
if(minutesTF.getText() == null || minutesTF.getText().equals("")){
minutes = 0;
}else{
minutes = Long.parseLong(minutesTF.getText());
}
if(secondsTF.getText() == null || secondsTF.getText().equals("")){
seconds = 0;
}else{
seconds = Long.parseLong(secondsTF.getText());
}
}catch(NumberFormatException e){
System.out.println("Error");
}
Timer timer = new Timer(hours, minutes, seconds);
while(!timer.isFinished()){
remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
return null;
}
};
new Thread(timer).start();
}
public static void main(String[] args) {
launch(args);
}
}
any help would be appreciated!
New stack trace:
x.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at GUI$3.call(GUI.java:109)
at GUI$3.call(GUI.java:80)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:438)
at javafx.scene.Parent$2.onProposedChange(Parent.java:364)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$$Lambda$102/1442917786.call(Unknown Source)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
at javafx.scene.control.Labeled.setText(Labeled.java:145)
at GUI$3.call(GUI.java:109)
at GUI$3.call(GUI.java:80)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1423)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
You are violating the rule about not accessing the state of a node in a live scene graph on a background thread. Most JavaFX controls will actually check for this and throw an IllegalStateException when you do this: apparently TextInputControl.setText(...) doesn't (presumably for reasons of performance).
The simplest fix is to update the message property of the task:
while(!timer.isFinished()){
updateMessage(Long.toString(timer.getRemainingTimeMillis()));
// remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
(this causes an update to the message property to occur on the FX Application Thread), and then bind the text field's text property to it:
remainingTimeTF.textProperty().bind(timer.messageProperty());
new Thread(timer).start();
However, there are a lot of things about your code that violate good practice. Fo example, you should really compute the total time outside of the task (i.e. on the FX Application Thread) and store it in a final variable; and the busy while loop is pretty horrible (though updateMessage(...) will fix most of the issues associated with that for you).
I recommend you read up on multithreading in JavaFX. Start with the Task API docs. Maybe this question will help: Using threads to make database requests
First of all, if you really need to update that TextField in the way you are doing it I would recommend adding a Thread.sleep(100); (10 updates per second) in your while, or even Thread.sleep(1000); (1 update per second) since it's really CPU intensive to update that text field on every CPU cycle and usually you don't need to..
Secondly (and probably the reason of your exceptions) the call remainingTimeTF.setText(); MUST happen IN the FX Thread, try this code instead:
Platform.runLater(new Runnable() {
#Override public void run() {
remainingTimeTF.setText(Long.toString(timer.getRemainingTimeMillis()));
}
});
Right now you are setting the text outside the FX Thead which might lead to several exceptions since update requests are happening in a worker thread and the actual UI modifications are happening in the FX thread. You need to make sure that every time you need to modify the UI it happens in the correct thread, in this case the FX Thread with the Platform.runLater() call.
Also since you are already using the Task class why not bind the text property and use the updateMessage() or updateTitle() methods instead?
Take a look at this article, it has good examples for the correct usage of Task and updating the UI from worker threads.
Hope this helps!

JNI byteArray passing help

I have been running into issues with my Android app closing (no errors or anything) when trying to execute the following code:
JNIEXPORT void Java_teamjeff_oggstreamtest_MainTest_audioFunc(JNIEnv* env, jobject obj) {
//<REMOVED VARIABLE INITIALIZATION>
jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID writeDataFunc = (*env)->GetMethodID(env, cls, "writeToAudioTrack", "([B)V");
if (!writeDataFunc) return;
jmethodID readDataFunc = (*env)->GetMethodID(env, cls, "readFromBuffer", "([B)I");
if (!readDataFunc) return;
rawDataRead = (*env)->NewByteArray(env, 4096);
bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead);
char* carr = (*env)->GetByteArrayElements(env, rawDataRead, NULL);
memcpy(buffer, carr, bytes);
(*env)->DeleteLocalRef(env, rawDataRead);
//<REMOVED REST OF FUNCTION>
}
I've tracked the "trouble" code to the bytes = (*env)->CallIntMethod(env, obj,readDataFunc, &rawDataRead); line. If I return before this line, my app doesn't close, but if I return immediately after this line, my app closes randomly without even an error.
Here is the JAVA code:
package teamjeff.oggstreamtest;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Bundle;
import android.os.Handler;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import com.Ostermiller.util.CircularByteBuffer;
public class MainTest extends Activity {
public static Handler mHandler = new Handler();
private final CircularByteBuffer cbb = new CircularByteBuffer(1024*512, true);
public AudioTrack mAudioTrack;
static {
System.loadLibrary("vorbis-decoder");
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
try {
final Socket test = new Socket(InetAddress.getByName(<HOME SERVER URL>), <PORT>);
new Thread(
new Runnable(){
public void run(){
try {
while(!test.isClosed()) {
byte[] temp = new byte[4096];
int bytes = test.getInputStream().read(temp, 0, 4096);
cbb.getOutputStream().write(temp, 0, bytes);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
).start();
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
44100,
AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT,
1024*64,
AudioTrack.MODE_STREAM);
mAudioTrack.play();
new Thread(new Runnable() {
public void run() {
audioFunc();
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
public native void audioFunc();
#SuppressWarnings("unused")
private void writeToAudioTrack(final byte[] media) {
mHandler.post(new Runnable() {
public void run() {
mAudioTrack.write(media, 0, media.length);
}
});
}
#SuppressWarnings("unused")
private int readFromBuffer(byte[] buffer) {
try {
return cbb.getInputStream().read(buffer, 0, buffer.length);
} catch (IOException e) {
e.printStackTrace();
}
return -1;
}
}
I have searched for days here and on Google on how to accomplish what I want to do. My code above is the gluing together of various code snippets I've found around the internet with tweaks to fit my use-case.
What I'm trying to accomplish:
I will read in data from a socket in my Android App, pass this data to my C code for decoding (though the algorithm reads it in piece by piece during the algorithm, meaning I can't pass in the byteArray from Java to C and call my C function multiple times since the decoder sometimes uses data from previous read-in bytes). My C code does the decoding, and passes the PCM data back to my Android app to be played on an AudioTrack.
I am using a circular buffer to buffer in the data from the socket.
When I try to debug my Android App, I set break points at the entries to both the read and write functions and they never seem to be called.
Am I doing something wrong when I pass the byteArray from my C code to JAVA to be filled with data? Should I be doing this an alternative way?
A few notes that might help.
&rawDataRead is wrong. Lose the &. You just pass the ref that you get, not the address of it.
you don't need to delete that local ref. All local refs are deleted when a native function returns. I'm fairly confident that this is true in java, but the android situation may be different.
You don't have to keep retrieving the method ids. You can get them once and hang onto them.

Resources