android - 颤振 | 如何从 Native 到 Flutter 端获取带有 Event Channel 的数据流?
问题描述
我想使用事件通道从 Spotify SDK 获取数据流。在原生端,我可以通过订阅我的 PlayerState 来自动显示当前歌曲的状态。我的目标是能够使用我的 Flutter 应用程序访问此数据流。但是,我没有得到任何真实数据,只是一个 MapStream:
Instance of '_MapStream<dynamic, double>'
根据我的 StreamBuilder,这个 MapStream 没有数据。错误在哪里?如何将数据从 Native 推送到 Flutter 端?
本机代码:
package test.test.spotifysdk04
import com.spotify.android.appremote.api.ConnectionParams
import com.spotify.android.appremote.api.Connector
import com.spotify.android.appremote.api.SpotifyAppRemote
import com.spotify.protocol.types.PlayerState
import com.spotify.sdk.android.authentication.AuthenticationClient
import com.spotify.sdk.android.authentication.AuthenticationRequest
import com.spotify.sdk.android.authentication.AuthenticationResponse
import io.flutter.Log
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
import com.spotify.protocol.types.Track
class Spotifysdk04Plugin(private var registrar: Registrar): MethodCallHandler, EventChannel.StreamHandler {
private val clientId = "65fd9b2b0ee74575a6d26223a1675917"
private val redirectUri = "spotify-flutter://callback"
private var spotifyAppRemote: SpotifyAppRemote? = null
private val REQUEST_CODE = 1337
private var mEventSink: EventChannel.EventSink? = null
companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "spotifysdk")
channel.setMethodCallHandler(Spotifysdk04Plugin(registrar))
val eventChannel = EventChannel(registrar.messenger(), "timerStream")
eventChannel.setStreamHandler(Spotifysdk04Plugin(registrar))
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "loginAppRemote") {
val connectionParams = ConnectionParams.Builder(clientId)
.setRedirectUri(redirectUri)
.showAuthView(true)
.build()
SpotifyAppRemote.connect(registrar.context(), connectionParams, object : Connector.ConnectionListener {
override fun onConnected(appRemote: SpotifyAppRemote) {
spotifyAppRemote = appRemote
Log.d("Spotify App Remote Login", "Connected!")
result.success(true)
}
override fun onFailure(throwable: Throwable) {
Log.e("Spotify App Remote Login", "Error!", throwable)
result.success(false)
}
})
} else if(call.method == "loginSpotifyAuthentication") {
try {
AuthenticationClient.openLoginActivity(
registrar.activity(), REQUEST_CODE,
AuthenticationRequest.Builder(clientId,AuthenticationResponse.Type.TOKEN,redirectUri)
.setScopes(arrayOf("user-modify-playback-state")).build())
}catch (err:Throwable){
Log.v("getAuthTokenError",err.message.toString())
}
registrar.addActivityResultListener { requestCode, resultCode, intent ->
if (requestCode == REQUEST_CODE){
val response = AuthenticationClient.getResponse(resultCode, intent).accessToken
result.success(response)
}
true
}
} else {
result.notImplemented()
}
}
override fun onCancel(arguments: Any?) {
mEventSink = null
}
override fun onListen(arguments: Any?, eventSink: EventChannel.EventSink?) {
createListener(eventSink)
}
fun createListener(event: EventChannel.EventSink?) {
if (spotifyAppRemote != null) {
spotifyAppRemote!!.playerApi.subscribeToPlayerState()
.setEventCallback { playerState: PlayerState? ->
var position = playerState!!.playbackPosition.toDouble()
Log.d("playbackPosition", position.toString())
event?.success(position)
}
}
}
}
飞镖插件代码:
import 'dart:async';
import 'package:flutter/services.dart';
class Spotifysdk04 {
static const MethodChannel _channel = const MethodChannel('spotifysdk');
static const EventChannel _timerEventChannel = const EventChannel('timerStream');
static Stream<double> _timerStream;
static Future<bool> get loginAppRemote async {
final bool connected = await _channel.invokeMethod('loginAppRemote');
return connected;
}
static Future<String> get loginSpotifyAuthentication async {
final String accessToken =
await _channel.invokeMethod('loginSpotifyAuthentication');
return accessToken;
}
static Stream<double> get timerStream {
_timerStream =
_timerEventChannel.receiveBroadcastStream().map<double>((value) => value);
print(_timerStream);
return _timerStream;
}
}
颤振代码:
//...
StreamBuilder(
stream: Spotifysdk04.timerStream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
print(snapshot);
if (snapshot.hasData) {
return Text(
'Pressure Stream ${snapshot.data}',
style: TextStyle(
color: Colors.white,
),
);
}
return Text(
'No data',
style: TextStyle(
color: Colors.white,
),
);
}),
//...
解决方案
您快到了。
_timerStream = _timerEventChannel.receiveBroadcastStream();
这已经足够了。通常你会使用它的StreamSubscription<T> listen(void onData(T))
方法来监听一个流:
_timerStream = _timerEventChannel.receiveBroadcastStream();
var subscription = _timerStream.listen(onData);
void onData(dynamic d) {
print("Data: $d");
}
然而,StreamBuilder 已经为您处理了所有的监听逻辑。
推荐阅读
- asp.net-core-3.1 - ZipArchive 不会立即刷新 zip 项目
- c# - How to access DataGridCell Binding Value in Style Resource
- postgresql - postgresql pg_import_system_collations 不导入操作系统添加的语言环境
- android - findViewById 如何返回与 View 不同的东西并且程序仍将编译?
- neo4j - 更新到 neo4j 4.2 后,阅读器角色无法使用 apoc 功能
- javascript - 需要帮助在 SquareSpace 上引用 DOM 元素
- html - 为什么孩子的“空白:pre;” 更改其父表的“宽度”?
- sql - 子查询在获取过去 X 周的数据时出现太多列错误?
- xamarin - 将数据/文本传递到另一个页面
- c# - iOS 14.2 更新后打开模式时 KeyWindow NavigationController 为空