我想在带有 Java Midlet 的诺基亚手机上反复捕获音频片段。我目前的经验是使用 Sun 文档中的代码(参见:http: //java.sun.com/javame/reference/apis/jsr135/javax/microedition/media/control/RecordControl.html)并将其包装在“ while(true)" 循环有效,但应用程序会慢慢消耗手机上的所有内存,程序最终会抛出异常并且无法启动进一步的录制。
消耗的内存不是 Java 堆内存——我的示例程序(如下)显示 Java 内存大致保持静态,大约为 185,000 字节——但诺基亚提供的底层支持库中存在某种内存泄漏;我相信会发生内存泄漏,因为如果您在运行 Java 应用程序一段时间后尝试启动另一个(非 Java)应用程序(例如 Web 浏览器),手机会终止该应用程序并发出有关内存不足的警告。
我已经尝试了几种不同的方法,这些方法与 Sun 在文档中的规范示例所采用的方法不同(每次循环初始化所有内容,尽可能只初始化一次,调用尽可能多的解除分配风格的函数,这些函数不应该是绝对必要的ETC。)。似乎没有一个是成功的。下面是一个简单的示例程序,我认为它应该可以工作,但在 N80(尽管有固件更新)和 N95 上运行 15 分钟左右后崩溃。其他论坛也报告了这个问题,但那里提出的解决方案似乎不起作用(例如,参见:http ://discussion.forum.nokia.com/forum/showthread.php?t=129876 )。
import javax.microedition.media.*;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
import java.io.*;
public class Standalone extends MIDlet {
protected void startApp() {
final Form form = new Form("Test audio recording");
final StringItem status = new StringItem("Status","");
form.append(status);
final Command exit = new Command("Exit", Command.EXIT, 1);
form.addCommand(exit);
form.setCommandListener(new CommandListener() {
public void commandAction(Command cmd, Displayable disp) {
if (cmd == exit) {
destroyApp(false);
notifyDestroyed();
}
}
});
Thread t = new Thread(){
public void run() {
int counter = 0;
while(true) {
//Code cut 'n' paste from Sun JSR135 javadocs for RecordControl:
try {
Player p = Manager.createPlayer("capture://audio");
p.realize();
RecordControl rc = (RecordControl)p.getControl("RecordControl");
ByteArrayOutputStream output = new ByteArrayOutputStream();
rc.setRecordStream(output);
rc.startRecord();
p.start();
Thread.currentThread().sleep(5000);
rc.commit();
p.close();
} catch (Exception e) {
status.setText("completed "+counter+
" T="+Runtime.getRuntime().totalMemory()+
" F="+Runtime.getRuntime().freeMemory()+
": Error: "+e);
break;
}
counter++;
status.setText("completed "+counter+
" T="+Runtime.getRuntime().totalMemory()+
" F="+Runtime.getRuntime().freeMemory());
System.gc(); //One forum post suggests this, but doesn't help
this.yield();
}
}
};
t.start();
final Display display = Display.getDisplay(this);
display.setCurrent(form);
}
protected void pauseApp() {}
protected void destroyApp(boolean bool) {}
}