【发布时间】:2016-07-17 09:11:38
【问题描述】:
由于尚未实现 javafxports Media,我希望改用 Android Native MediaPlayer。有谁知道如何做到这一点。
【问题讨论】:
标签: android javafx android-mediaplayer javafxports
由于尚未实现 javafxports Media,我希望改用 Android Native MediaPlayer。有谁知道如何做到这一点。
【问题讨论】:
标签: android javafx android-mediaplayer javafxports
如果您查看 GoNative 示例 here(docs 和 code),您会找到一种将 Android 本机代码添加到 JavaFX 项目的方法。
这是一个使用 Gluon 插件将 android.media.MediaPlayer 添加到 JavaFX 项目的简单示例。
基于 Single View 项目,我们先添加一个带有所需音频方法签名的接口:
public interface NativeAudioService {
void play();
void pause();
void resume();
void stop();
}
现在在我们的视图中,我们可以创建按钮来调用这些方法,基于实现NativeAudioService 接口的AndroidNativeAudio 类的实例:
public class BasicView extends View {
private NativeAudioService service;
private boolean pause;
public BasicView(String name) {
super(name);
try {
service = (NativeAudioService) Class.forName("com.gluonhq.nativeaudio.AndroidNativeAudio").newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
System.out.println("Error " + ex);
}
if (service != null) {
final HBox hBox = new HBox(10,
MaterialDesignIcon.PLAY_ARROW.button(e -> service.play()),
MaterialDesignIcon.PAUSE.button(e -> {
if (!pause) {
service.pause();
pause = true;
} else {
service.resume();
pause = false;
}
}),
MaterialDesignIcon.STOP.button(e -> service.stop()));
hBox.setAlignment(Pos.CENTER);
setCenter(new StackPane(hBox));
} else {
setCenter(new StackPane(new Label("Only for Android")));
}
}
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MUSIC_NOTE.button());
appBar.setTitleText("Native Audio");
}
}
现在,我们在 Android 文件夹下创建原生类。它将使用 android API。它将尝试找到我们必须放在/src/android/assets 文件夹下的音频文件audio.mp3:
package com.gluonhq.nativeaudio;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import java.io.IOException;
import javafxports.android.FXActivity;
public class AndroidNativeAudio implements NativeAudioService {
private MediaPlayer mp;
private int currentPosition;
public AndroidNativeAudio() { }
@Override
public void play() {
currentPosition = 0;
try {
if (mp != null) {
stop();
}
mp = new MediaPlayer();
AssetFileDescriptor afd = FXActivity.getInstance().getAssets().openFd("audio.mp3");
mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
mp.setAudioStreamType(AudioManager.STREAM_RING);
mp.setOnCompletionListener(mp -> stop());
mp.prepare();
mp.start();
} catch (IOException e) {
System.out.println("Error playing audio resource " + e);
}
}
@Override
public void stop() {
if (mp != null) {
if (mp.isPlaying()) {
mp.stop();
}
mp.release();
mp = null;
}
}
@Override
public void pause() {
if (mp != null) {
mp.pause();
currentPosition = mp.getCurrentPosition();
}
}
@Override
public void resume() {
if (mp != null) {
mp.start();
mp.seekTo(currentPosition);
}
}
}
最后,我们可以将项目部署到运行gradlew androidInstall的Android设备上。
【讨论】:
compile 'org.javafxports:jfxdvk:8.60.8',但不明白,还需要什么。我猜是android.jar,对吧?但具体在哪里? (顺便说一句:我正在使用 Eclipse 插件,如果这很重要的话。)
compile files('libs/android-22.jar')(其中数字 22 标记了目标 SDK)。但我明确需要在构建应用程序之前评论这一行,因为否则 Retrolambda 会崩溃......此外,我听不到任何声音,音量按钮事件似乎不会触发通常的音量增大/减小行为。 #edit:我在设置中提高了音量,但仍然听不到任何声音。我没有收到任何错误,所以一切似乎都很好,但无论如何都无法正常工作......
FXActivity.getInstance().setVolumeControlStream(AudioManager.STREAM_MUSIC); 另外您需要更改mp.setAudioStreamType(AudioManager.STREAM_RING); 到 mp.setAudioStreamType(AudioManager.STREAM_MUSIC);。
本机音频播放器用于以下示例:
https://gist.github.com/bgmf/d87a2bac0a5623f359637a3da334f980
除了一些先决条件之外,代码如下所示:
package my.application;
import my.application.Constants;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import org.robovm.apple.avfoundation.AVAudioPlayer;
import org.robovm.apple.foundation.NSErrorException;
import org.robovm.apple.foundation.NSURL;
import org.robovm.apple.foundation.NSURLScheme;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
public class NativeAudioServiceIOS extends PathHelperIOS implements NativeAudioService {
private static final Logger LOG = Logger.getLogger(NativeAudioServiceIOS.class.getName());
private static final String DIR_NAME = Constants.OBJECTS_BASE_PATH;
private final ReadOnlyObjectWrapper<Status> status = new ReadOnlyObjectWrapper<>(this, "status", Status.STOP);
private String filename = null;
private AVAudioPlayer player = null;
public NativeAudioServiceIOS() {
super();
}
@Override
public void init(String filename) throws NativeServiceException {
this.filename = filename.startsWith("/") ? filename.substring(1) : filename;
LOG.warning("Called with file: " + filename);
status.set(Status.STOP);
try {
if(!filename.startsWith("/")) filename = "/" + filename;
File fullfile = new File(pathBase.getAbsolutePath() + filename);
if(fullfile.exists()) {
NSURL fullurl = new NSURL(NSURLScheme.File, "", fullfile.getAbsolutePath());
LOG.log(Level.SEVERE, "Loading URL: " + fullurl);
// Create audio player object and initialize with URL to sound
player = new AVAudioPlayer(fullurl);
LOG.log(Level.SEVERE, "Player initialized: " + player);
status.set(Status.STOP);
} else {
LOG.log(Level.WARNING, String.format("Audiofile doesn't exist: %s (%s / %s)",
fullfile.getAbsolutePath(),
pathBase.getAbsolutePath(),
filename));
player = null;
status.set(Status.ERROR);
}
} catch(NSErrorException error) {
LOG.log(Level.SEVERE, "Audio Setup Failed: " + error.toString(), error);
status.set(Status.ERROR);
}
}
@Override
public void play() throws NativeServiceException {
if(player == null) return;
player.play();
status.set(Status.PLAY);
}
@Override
public void pause() throws NativeServiceException {
if(player == null) return;
player.pause();
status.set(Status.PAUSE);
}
@Override
public void resume() throws NativeServiceException {
if(player == null) return;
player.play();
status.set(Status.PLAY);
}
@Override
public void stop() throws NativeServiceException {
if(player == null) return;
player.stop();
player.setCurrentTime(0.0);
status.set(Status.STOP);
}
@Override
public ReadOnlyObjectProperty<Status> statusProperty() {
return status.getReadOnlyProperty();
}
@Override
public Status getStatus() {
return status.get();
}
}
【讨论】: