Android Bluetooth Service to Transfer data between devices - android

Hello am new in Android development I was reading about android bluetooth Here on Android development documentation.
I was able to setup bluetooth, find the bonded device and to connect but am having an issue on transfer data between them
Here is the bluetooth server socket code that listen to bluetooth connection request.
class BluetoothActivity : AppCompatActivity() {
private lateinit var listen: Button
private lateinit var msgBox:TextView
private lateinit var status:TextView
private lateinit var sendButton: Button
private lateinit var writeMsg:EditText
private lateinit var listDevice:Button
private lateinit var listView: ListView
private val handler = Handler()
private var bluetoothDevices = arrayListOf<BluetoothDevice>()
private var deviceName = arrayListOf<String>()
private inner class ServerAcceptThread:Thread(){
private val mmServerSocket:BluetoothServerSocket? by lazy(LazyThreadSafetyMode.NONE){
bluetoothAdapter?.listenUsingInsecureRfcommWithServiceRecord(myName,myUUID)
}
override fun run() {
//Keep listen until error occured or socket is returned
var shouldKeepListen = true
while (shouldKeepListen){
val socket:BluetoothSocket? = try {
mmServerSocket?.accept()
}catch (e:IOException){
Log.e("bluetoothSocket","ServerSocket failde",e)
shouldKeepListen = false
null
}
if (socket!= null){
val connected = ConnectedThread(socket)
connected.start()
}
}
}
//Close server socket and cause the thread to finish
fun cancel(){
try {
mmServerSocket?.close()
}catch (e:IOException){
Log.e("ConnectionFailed!", "Connection close failed",e)
}
}
}
And down below is the code for Bluetooth client that connect to bluetooth server socket.
private inner class ClientConnectThread(device: BluetoothDevice):Thread(){
private val mmSocket:BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE){
device.createRfcommSocketToServiceRecord(myUUID)
}
public override fun run() {
//Cancel the discovery process because it slow down the connection
bluetoothAdapter?.cancelDiscovery()
mmSocket?.let { socket ->
socket.connect()
}
}
fun cancel(){
try {
mmSocket?.close()
}catch (e:IOException){
Log.e("Socket", "Could not close the client socket",e)
}
}
}
And Then I have bluetooth service that read and write data to send to remote device (client). which take BluetoothSocket as parameter, were the server is listening to
private inner class ConnectedThread(private val mmSocket:BluetoothSocket):Thread(){
private val mmInPutStream:InputStream = mmSocket.inputStream
private val mmOutPutStream:OutputStream = mmSocket.outputStream
private val mmBuffer:ByteArray = ByteArray(1024)
override fun run() {
var numByte:Int //number of bytes returns from read()
//keep listen to the InputStream until an error occured
while (true){
//Read from inputStream
numByte = try {
mmInPutStream.read(mmBuffer)
}catch (e:IOException){
Log.e(TAG,"InputStream was disconnected",e)
break
}
//Send the message to Ui activity
val readMsg = handler.obtainMessage(
MESSAGE_READ,numByte,-1,mmBuffer
)
readMsg.sendToTarget()
}
}
//Call this function to mainActivity to send data to remote device
fun write(byte:ByteArray){
try {
mmOutPutStream.write(byte)
}catch (e:IOException){
Log.e(TAG,"Error occured during send messge",e)
//Send the failed message back to activity
val writeErrorMessage = handler.obtainMessage(MESSAGE_TOAST)
val bundle = Bundle().apply {
putString("Toast","could not send the data")
}
writeErrorMessage.data = bundle
handler.sendMessage(writeErrorMessage)
return
}
//Share the sent message with UI activity
val writtenMsg = handler.obtainMessage(
MESSAGE_WRITE, -1,-1,mmBuffer
)
writtenMsg.sendToTarget()
}
//Call this method to activity to shut socket
fun cancle(){
try {
mmSocket.close()
}catch (e:IOException){
Log.e(TAG,"Connection closed failed!")
}
}
}
}
And I have also implement the listener for UI to start listen to a connection request, list Bonded device and connect to remote device and transfer data through each other.
fun implementsListeners(){
listDevice.setOnClickListener {
val pairedDevice: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
var index:Int = 0
val pairedDevice: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
if (pairedDevice != null){
var listDeviceName = arrayListOf<String>()
try {
pairedDevice.forEachIndexed { index, device ->
listDeviceName.add(index, device.name)
bluetoothDevices.add(device)
}
}catch (e:IndexOutOfBoundsException){
Log.e(TAG, "indexOutOfBond",e)
}
val arrayAdapter:ArrayAdapter<String> = ArrayAdapter(
this,android.R.layout.simple_list_item_1,listDeviceName
)
listView.adapter =arrayAdapter
}
listen.setOnClickListener {
val serverClass = ServerAcceptThread()
serverClass.start()
}
listView.setOnItemClickListener { parent, view, position, id ->
val client = ClientConnectThread(bluetoothDevices[position])
client.start()
status.text = "Connecting..."
}
sendButton.setOnClickListener {
val client = BluetoothService(Handler())
//Call the write() method to write data
}
My Question is how can I access the write() method and read() that is on ConnectedThread. I have tried to Instantiate ConnectedThread but it's take BluetoothSocket as parameter I can't access the socket outside client or server class. Method Any help or suggestion on. I would Appreciate

Related

How to use socket in Android with Kotlin

I want to achieve something in Android using Kotlin to do:
If I click a button on the app, the app sends a word to a TCP server (which I wrote with python). The server will send back another word, and the app will show a toast message.
Here is what I have done so far, I can figure out the sending part but I can't manage to make it keep listening to the socket to hear from the server.
I am trying to use coroutine but after finding all the resources online, this is as best as I can get.
Also, I am not sure if I am setting the IP address in the correct manner.
Thank you in advance for your help!
'''
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val sendBtn = findViewById<Button>(R.id.sendBtn )
val ipBtn = findViewById<Button>(R.id.ipBtn)
val ipInput = findViewById<TextView>(R.id.ipInput)
var ipAddress: String = "192.168.0.101"
// Below is my attempt to keep listening to the socket, if commented, the sending would work.
// My guess is the IO thread is caught in the while loop so the other coroutines cannot use
// IO thread to send to the server.
CoroutineScope(IO).launch{
val socket = Socket(ipAddress, 9999)
var text = ""
while (true) {
text = BufferedReader(InputStreamReader(socket.inputStream)).readLine()
// if text is not null
// Toast.makeText(this#MainActivity, "Set IP", Toast.LENGTH_SHORT).show()
}
}
suspend fun sendMessage(message:String){
val socket = Socket(ipAddress, 9999)
socket.outputStream.write(message.toByteArray())
socket.close()
}
ipBtn.setOnClickListener {
Toast.makeText(this#MainActivity, "Set IP", Toast.LENGTH_SHORT).show()
ipAddress = ipInput.text.toString()
}
sendBtn .setOnClickListener {
CoroutineScope(IO).launch {
Log.d("TAG", "message")
sendMessage("record")
}
}
'''
To send a Data from P2P Fist we required a Server and Client . Here the Socket act as end point for sending and receiving data across the network .
Create a Server Class like this
class ServerClass() :Thread(){
lateinit var serverSocket:ServerSocket
lateinit var inputStream: InputStream
lateinit var outputStream: OutputStream
lateinit var socket: Socket
override fun run() {
try {
serverSocket = ServerSocket(8888)
socket = serverSocket.accept()
inputStream =socket.getInputStream()
outputStream = socket.getOutputStream()
}catch (ex:IOException){
ex.printStackTrace()
}
val executors = Executors.newSingleThreadExecutor()
val handler = Handler(Looper.getMainLooper())
executors.execute(Runnable{
kotlin.run {
val buffer = ByteArray(1024)
var byte:Int
while (true){
try {
byte = inputStream.read(buffer)
if(byte > 0){
var finalByte = byte
handler.post(Runnable{
kotlin.run {
var tmpMeassage = String(buffer,0,finalByte)
Log.i("Server class","$tmpMeassage")
}
})
}
}catch (ex:IOException){
ex.printStackTrace()
}
}
}
})
}
fun write(byteArray: ByteArray){
try {
Log.i("Server write","$byteArray sending")
outputStream.write(byteArray)
}catch (ex:IOException){
ex.printStackTrace()
}
}
}
Create a client Class where we need to pass hostaddress
class ClientClass(hostAddress: InetAddress): Thread() {
var hostAddress: String = hostAddress.hostAddress
lateinit var inputStream: InputStream
lateinit var outputStream: OutputStream
lateinit var socket: Socket
fun write(byteArray: ByteArray){
try {
outputStream.write(byteArray)
}catch (ex:IOException){
ex.printStackTrace()
}
}
override fun run() {
try {
socket = Socket()
socket.connect(InetSocketAddress(hostAddress,8888),500)
inputStream = socket.getInputStream()
outputStream = socket.getOutputStream()
}catch (ex:IOException){
ex.printStackTrace()
}
val executor = Executors.newSingleThreadExecutor()
var handler =Handler(Looper.getMainLooper())
executor.execute(kotlinx.coroutines.Runnable {
kotlin.run {
val buffer =ByteArray(1024)
var byte:Int
while (true){
try{
byte = inputStream.read(buffer)
if(byte>0){
val finalBytes = byte
handler.post(Runnable{
kotlin.run {
val tmpMeassage = String(buffer,0,finalBytes)
Log.i("client class", tmpMeassage)
}
})
}
}catch (ex:IOException){
ex.printStackTrace()
}
}
}
})
}
}
make sure server and client port should be same , this is two way communication where we can transfer data in both sides .

Data received from Android Bluetooth socket is getting plotted in the line chart only after socket's termination

I have recently started working on Android, Kotlin and MPAndroidChart. I am developing an Android application that receives data from a bluetooth server and the data obtained should be plotted in real time using MPAndroidChart.
Here is the Kotlin code:
package com.example.flowsensor
import ...
class ConnectionActivity:AppCompatActivity() {
companion object{
val TAG = "FlowSensor"
val APP_NAME = "FlowSensor"
var myUUID: UUID = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66")
var mBluetoothSocket: BluetoothSocket? = null
lateinit var mProgress: ProgressDialog
lateinit var mBluetoothAdapter: BluetoothAdapter
var mIsConnected: Boolean = false
lateinit var mAddress: String
lateinit var editText:EditText
lateinit var mChart:LineChart
var xVal:Int = 0
var yVal:Int = 0
}
override fun onCreate(savedInstanceState: Bundle?) {
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_connection)
mChart = findViewById<LineChart>(R.id.line_chart)
receive_button.setOnClickListener{
ReceiveData()
}
}
//1 parameters missing
private fun mAddEntry() {
Log.d(TAG, "yVal : $yVal")
var mData = mChart.data
if(mData != null){
var mDataSet = mData.getDataSetByIndex(0)
if(mDataSet == null){
mDataSet = createDataSet()
mData.addDataSet(mDataSet)
}
var mEntry:Entry = Entry( xVal.toFloat(), yVal.toFloat())
xVal++
mData.addEntry(mEntry, 0)
//Notify chart data has changed
mChart.notifyDataSetChanged()
//Limit no of visible entries
// mChart.setVisibleXRange(1f, 6f)
mChart.setVisibleXRangeMaximum(6f)
//Scroll to the last entry
mChart.moveViewToX(xVal.toFloat())
}
}
//1 parameter missing
private fun createDataSet(): LineDataSet? {
var mDataSet = LineDataSet(null, "Data vals")
//mDataSet.setDrawCubic
mDataSet.cubicIntensity = 0.2f
mDataSet.axisDependency = YAxis.AxisDependency.LEFT
mDataSet.setColor(ColorTemplate.getHoloBlue())
mDataSet.setCircleColor(ColorTemplate.getHoloBlue())
mDataSet.lineWidth = 2f
mDataSet.circleSize = 4f
mDataSet.fillAlpha = 65
mDataSet.fillColor = ColorTemplate.getHoloBlue()
mDataSet.highLightColor = Color.rgb(244, 117, 177)
mDataSet.valueTextColor = Color.WHITE
mDataSet.valueTextSize = 10f
return mDataSet
}
private fun ReceiveData() {
val buffer = ByteArray(1024) // buffer store for the stream
var bytes: Int // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
Log.d(TAG, "Inside ReceiveData()")
while (true) { // Read from the InputStream
if(mBluetoothSocket != null)
{
try {
bytes = mBluetoothSocket!!.inputStream.read(buffer)
val incomingMessage = String(buffer, 0, bytes)
Log.d(TAG, "InputStream: $incomingMessage")
yVal = incomingMessage.toInt()
mAddEntry()
} catch (e: IOException) {
Log.e(TAG, "write: Error reading Input Stream. " + e.message)
break
}
}
}
}
}
Here is the logcat log logged in verbose mode.
App starts in the Main Activity(code not attached here), looks for paired devices then using
val intent = Intent(this, ConnectionActivity::class.java)
intent.putExtra(EXTRA_ADDRESS, address)
startActivity(intent) code, control reaches Connection Activity (code attached above).
App is successfully receiving data from server; verified by observing logcat. In ReceiveData(), I am trying to pass the received data to mAddEntry() which is responsible for drawing the graph. But the problem is, data is plotted only after I terminate the socket, so after Line no 112 in the attached logcat log, all the data is plotted at once (no data loss). I want to plot data in real time, and this is the problem I am facing.
Note: graph plotting has been independently verified by passing dummy data in real-time inside onCreate() in ConnectionActivity class using the timer.scheduleAtFixedRate. This is working as expected.
by calling the reciveData() inside the receive_button onClickListner you are executing while loop that will run until Bluetooth socket is connected and it is runing on the MainThread (UIThread) and it will block the UI thread and doesn't let any other ui updateto happen you should execute the reciveData() function on the background and when you want the plot the data in chart you should pass the data in ui thread or call the mAddEntry() function in ui thread

Android WebRTC doesn't work on Different network - No Video

I am trying to stream video from Raspberry Pi to android device via webrtc. I am using firebase (firestore) as signalling. I am able to run the setup while connected to same wifi but it fails when different networks are being used.
Device - RPI
Client
1) Web client (hosted on firebase)
2) Android App
On same network (wifi) between device and clients, both clients are able to play video and audio.
But when device and client are on different network, web client is able to show video but Android App is not able to show video.
Signalling is working correctly and on device, camera and microphone are started and ice candidates are exchanged successfully. I also get remote stream added (onAddStream called) on android. But no video and audio is playing.
Android PeerConnectionClient
class PeerConnectionClient(private val activity: MainActivity, private val fSignalling: FSignalling) {
internal var isVideoRunning = false
private val rootEglBase by lazy {
EglBase.create()
}
private val peerConnectionFactory: PeerConnectionFactory by lazy {
val initializationOptions = PeerConnectionFactory.InitializationOptions.builder(activity).createInitializationOptions()
PeerConnectionFactory.initialize(initializationOptions)
val options = PeerConnectionFactory.Options()
val defaultVideoEncoderFactory = DefaultVideoEncoderFactory(rootEglBase.eglBaseContext, true, true)
val defaultVideoDecoderFactory = DefaultVideoDecoderFactory(rootEglBase.eglBaseContext)
PeerConnectionFactory.builder()
.setOptions(options)
.setVideoEncoderFactory(defaultVideoEncoderFactory)
.setVideoDecoderFactory(defaultVideoDecoderFactory)
.createPeerConnectionFactory()
}
private val iceServersList = mutableListOf("stun:stun.l.google.com:19302")
private var sdpConstraints: MediaConstraints? = null
private var localAudioTrack: AudioTrack? = null
private var localPeer: PeerConnection? = null
private var gotUserMedia: Boolean = false
private var peerIceServers: MutableList<PeerConnection.IceServer> = ArrayList()
init {
peerIceServers.add(PeerConnection.IceServer.builder(iceServersList).createIceServer())
// activity.surface_view.release()
activity.surface_view.init(rootEglBase.eglBaseContext, null)
activity.surface_view.setZOrderMediaOverlay(true)
createPeer()
}
private fun createPeer() {
sdpConstraints = MediaConstraints()
val audioconstraints = MediaConstraints()
val audioSource = peerConnectionFactory.createAudioSource(audioconstraints)
localAudioTrack = peerConnectionFactory.createAudioTrack("101", audioSource)
gotUserMedia = true
activity.runOnUiThread {
if (localAudioTrack != null) {
createPeerConnection()
// doCall()
}
}
}
/**
* Creating the local peerconnection instance
*/
private fun createPeerConnection() {
val constraints = MediaConstraints()
constraints.mandatory.add(MediaConstraints.KeyValuePair("offerToReceiveAudio", "true"))
constraints.mandatory.add(MediaConstraints.KeyValuePair("offerToReceiveVideo", "true"))
constraints.optional.add(MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"))
val rtcConfig = PeerConnection.RTCConfiguration(peerIceServers)
// TCP candidates are only useful when connecting to a server that supports
// ICE-TCP.
rtcConfig.enableDtlsSrtp = true
rtcConfig.enableRtpDataChannel = true
// rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED
// rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE
// rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE
// rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY
// Use ECDSA encryption.
// rtcConfig.keyType = PeerConnection.KeyType.ECDSA
localPeer = peerConnectionFactory.createPeerConnection(rtcConfig, constraints, object : PeerObserver {
override fun onIceCandidate(p0: IceCandidate) {
super.onIceCandidate(p0)
onIceCandidateReceived(p0)
}
override fun onAddStream(p0: MediaStream) {
activity.showToast("Received Remote stream")
super.onAddStream(p0)
gotRemoteStream(p0)
}
})
addStreamToLocalPeer()
}
/**
* Adding the stream to the localpeer
*/
private fun addStreamToLocalPeer() {
//creating local mediastream
val stream = peerConnectionFactory.createLocalMediaStream("102")
stream.addTrack(localAudioTrack)
localPeer!!.addStream(stream)
}
/**
* This method is called when the app is initiator - We generate the offer and send it over through socket
* to remote peer
*/
/*private fun doCall() {
localPeer!!.createOffer(object : mySdpObserver {
override fun onCreateSuccess(p0: SessionDescription) {
super.onCreateSuccess(p0)
localPeer!!.setLocalDescription(object: mySdpObserver {}, p0)
Log.d("onCreateSuccess", "SignallingClient emit ")
}
}, sdpConstraints)
}*/
private fun onIceCandidateReceived(iceCandidate: IceCandidate) {
//we have received ice candidate. We can set it to the other peer.
if (localPeer == null) {
return
}
val message = JSONObject()
message.put("type", "candidate")
message.put("label", iceCandidate.sdpMLineIndex)
message.put("id", iceCandidate.sdpMid)
message.put("candidate", iceCandidate.serverUrl)
fSignalling.doSignalingSend(message.toString())
}
private fun gotRemoteStream(stream: MediaStream) {
isVideoRunning = true
//we have remote video stream. add to the renderer.
val videoTrack = stream.videoTracks[0]
videoTrack.setEnabled(true)
activity.runOnUiThread {
try {
// val remoteRenderer = VideoRenderer(surface_view)
activity.surface_view.visibility = View.VISIBLE
// videoTrack.addRenderer(remoteRenderer)
videoTrack.addSink(activity.surface_view)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun onReceivePeerMessage(data: JSONObject) {
if (data.getString("type") == "offer") {
// val sdpReturned = SdpUtils.forceChosenVideoCodec(data.getString("sdp"), "H264")
val sdpReturned = data.getString("sdp")
// data.remove("sdp")
// data.put("sdp", sdpReturned)
val sessionDescription = SessionDescription(SessionDescription.Type.OFFER, sdpReturned)
localPeer?.setRemoteDescription(object: mySdpObserver { }, sessionDescription)
localPeer?.createAnswer(object : mySdpObserver {
override fun onCreateSuccess(p0: SessionDescription) {
super.onCreateSuccess(p0)
localPeer!!.setLocalDescription( object : mySdpObserver {}, p0)
val description = JSONObject()
description.put("type", p0.type.canonicalForm())
description.put("sdp", p0.description)
this#PeerConnectionClient.fSignalling.doSignalingSend(description.toString())
}
override fun onCreateFailure(p0: String) {
super.onCreateFailure(p0)
activity.showToast("Failed to create answer")
}
}, MediaConstraints())
} else if (data.getString("type") == "candidate") {
val iceCandidates = IceCandidate(data.getString("id"), data.getInt("label"), data.getString("candidate"))
localPeer?.addIceCandidate(iceCandidates)
}
}
internal fun close() {
isVideoRunning = false
localPeer?.close()
localPeer = null
}
}
I am under the impression that if web client is able to display video on different network (mobile hotspot), android client on same internet used by web client should be able to display video as well. Is it wrong?
Why won't android display video (onAddStream is called)
Is it required to use Turn server? My assumption again is the if web client works, so should android. The service i am using on RPI do not have support for turn server.
Additional info:
Device is behind double natted ISP (i guess) (but since web client can connect, it won't be an issue i guess).
I have found a solution to the issue
I was using
private fun onIceCandidateReceived(iceCandidate: IceCandidate) {
//we have received ice candidate. We can set it to the other peer.
if (localPeer == null) {
return
}
val message = JSONObject()
message.put("type", "candidate")
message.put("label", iceCandidate.sdpMLineIndex)
message.put("id", iceCandidate.sdpMid)
message.put("candidate", iceCandidate.serverUrl)
fSignalling.doSignalingSend(message.toString())
}
Instead was required to use
message.put("candidate", iceCandidate.sdp) // iceCandidate.serverUrl)

Android - Initiate Bluetooth Socket - connection timeout

I need to connect to a bluetooth device which acts as a server. I know its UUID (at least the device's documentation contains it). However, I get an exception when I try to connect to it. The discovery part takes place successfully.
In the following, I cite the relevant code parts.
Here is the discovery. After I successfully found my device, I try to connect to it.
private val bluetoothAdapter: BluetoothAdapter? = BluetoothAdapter.getDefaultAdapter()
private val bluetoothReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action: String = intent.action
when (action) {
BluetoothDevice.ACTION_FOUND -> {
val foundDevice: BluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
Log.i("NAME", foundDevice.name)
if (foundDevice.name.startsWith("RN487")) {
bluetoothAdapter?.cancelDiscovery()
device = foundDevice
val connectThread = ConnectThread(device)
connectThread.start()
}
}
}
}
}
private lateinit var device: BluetoothDevice
The ConnectThread class is here:
private inner class ConnectThread(device: BluetoothDevice) : Thread() {
private val mSocket: BluetoothSocket? by lazy(LazyThreadSafetyMode.NONE) {
device.createRfcommSocketToServiceRecord(UUID)
}
override fun run() {
bluetoothAdapter?.cancelDiscovery()
mSocket?.use { socket ->
socket.connect()
toast("Connected!")
}
}
fun cancel() {
try {
mSocket?.close()
} catch (e: IOException) {
Log.e(TAG, "Could not close the client socket", e)
}
}
}
The UUID was given as
private val UUID = nameUUIDFromBytes("49535343-...".toByteArray())
Thanks for your time and expertise!
As one of my eagle-eyed colleagues pointed out, the bluetooth description begins with the "oldschool" version on the official android developers site. Later, the bluetooth low energy is described, which I need for my project.

RxKotlin with Socket.io in Android

What I trying to do is listen to socket data and convert into an observable string that my UI can Subscribe this event and do Change on UI
So far I created a class SocketConnection maintain in dagger connection happen properly and received data and able to do with interface correctly, but want to apply with rxkotlin.
Using Socket.io,kotlin
SocketConnection class
class SocketConnection : SocketStreamListener {
private var socket: Socket? = null
var responseSocket :ResponseHandler?= null
companion object {
var instance = SocketConnection()
}
override fun createSocket(socketQuery: SocketQuery): Socket? {
try {
val okHttpClient = UnsafeOkHttpClient.getUnsafeOkHttpClient()
IO.setDefaultOkHttpWebSocketFactory(okHttpClient)
IO.setDefaultOkHttpCallFactory(okHttpClient)
val opts = IO.Options()
opts.reconnection = false
opts.callFactory = okHttpClient
opts.webSocketFactory = okHttpClient
opts.query = "userID=" + socketQuery.userID + "&token=" + socketQuery.token
socket = IO.socket(CommonContents.BASE_API_LAYER, opts)
L.d("Socket object created")
} catch (e: URISyntaxException) {
L.e("Error creating socket", e)
}
return socket
}
override fun createSocketListener(socket: Socket) {
L.d("inside the socket Listner")
socket.connect()?.on(Socket.EVENT_CONNECT, {
L.d("connected")
listenSocketEvents()
//socketDataListener()
createMessageListener()
})?.on(Socket.EVENT_DISCONNECT,
{
L.d("disconnected")
return#on
})
}
/**
* function used to listen a socket chanel data
*/
private fun listenSocketEvents() {
/* socket?.on("1502", { args ->
// This Will Work
L.d("Socket market depth event successfully")
val socketData = args[0] as String
L.d(socketData)
// instance.data = Observable.just(socketData)
//data!!.doOnNext({ socketData })
*//*
data = args[0] as String
for (i in 0 until arr.size) {
arr[i].socketStreamingData(data)
}*//*
})*/
}
// This Will Not Work
fun socketDataListener(): Observable<String>{
return Observable.create({
subscibe ->
// L.d("Socket market depth event successfully")
socket?.on("1502", { args ->
L.d("Socket market depth event successfully")
val socketData = args[0] as String
subscibe.onNext(socketData)
})
})
}
}
Repository
fun getSocketData(): Observable<String> {
// L.e("" + SocketConnection.instance.socketDataListener())
return SocketConnection.instance.createMessageListener()
}
ViewModel
fun getSocketData(): Observable<String>{
return groupRepository.getSocketData()
}
OnFragement (UI)
private fun getSocketUpdate(){
subscribe(watchlistViewModel.getSocketData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
L.d("SocketData : " + it.count())
}, {
L.e("Error")
}))
}
In this UI using disposable subscribe method into base class.
Please let me know what i doing wrong thanx in advance
Instead of creating an Observable every time a message is sent, I suggest using a Subject for that, since it has a similar "nature" as the Socket connection.
val subject = PublishSubject.create<String>()
...
fun listenSocketEvents() {
socket?.on("1502") { args ->
val socketData = args[0] as String
subject.onNext(socketData)
}
}
fun observable(): Observable<String>{
return subject
}
You can then listen to the changes on the subject via (repository layer etc not included, you'd have to do that yourself)
private fun getSocketUpdate() {
disposable = socketConnection.observable()
.subscribeOn(Schedulers.io())
.observeOn(...)
.subscribe({...}, {...})
}
As a side note, your singleton instance is not how you'd do that in kotlin.
Instead of having an instance field in a companion object, you should make the declare the class as object SocketConnection.
This will automatically give you all singleton features. (I do not know whether it is smart to use a singleton with socket.io, but I assume that you know what you're doing :-) )

Categories

Resources