이전 회에 알아본 내용을 실제로 코드로 구현 해 보자

 

1. ViewModel에 observer 추가

    1) ViewModel의 observer에 publishDiscoverSession, subscribeSession에 대한 observer 를 추가하고

    2) btnSendViaSession 을 disable 및 enable 시키는 부분 구현

private fun initViewModel(){
    viewModel = ViewModelProvider(this)[MainViewModel::class.java]

    .................

        viewModel.publishDiscoverySession.observe(this){
            var strDisplay = "publishDiscoverySession : "
            strDisplay += it?.toString() ?: "null"
            bindMain.tvPublishDiscoverySession.text = strDisplay
            bindMain.btnConnect.isEnabled = (
                viewModel.publishDiscoverySession.value == null
                    && viewModel.subscribeDiscoverySession.value == null)
            bindMain.btnSendViaSession.isEnabled = (
                    viewModel.publishDiscoverySession.value != null
                            || viewModel.subscribeDiscoverySession.value != null)
        }

        viewModel.subscribeDiscoverySession.observe(this){
            var strDisplay = "subscribeDiscoverySession : "
            strDisplay += it?.toString() ?: "null"
            bindMain.tvSubscribeDiscoverySession.text = strDisplay
            bindMain.btnConnect.isEnabled = (
                    viewModel.publishDiscoverySession.value == null
                            && viewModel.subscribeDiscoverySession.value == null)
            bindMain.btnSendViaSession.isEnabled = (
                    viewModel.publishDiscoverySession.value != null
                            || viewModel.subscribeDiscoverySession.value != null)
        }
}

 

2. setWifiAwareSession 구현

이전 회의 내용 그대로 순서대로 구현 하였다

fun setWifiAwareSession(wifiAwareSession: WifiAwareSession?){

    Log.i(">>>>", "setting wifiAwareSession")
    if(wifiAwareSession == null) Log.i(">>>>", "wifiAwareSession null")
    removeCurrentWifiAwareSession()
    viewModel.setWifiAwareSession(wifiAwareSession)

    if(asServer == null || bindMain.editServiceName.text.isEmpty()) return

    if(asServer!!) {
        val config: PublishConfig = PublishConfig.Builder()
            .setServiceName(bindMain.editServiceName.text!!.toString())
            .setTtlSec(0)
            .build()
        viewModel.wifiAwareSession.value?.publish(config, object : DiscoverySessionCallback() {
            override fun onPublishStarted(session: PublishDiscoverySession) {
                Log.i(">>>>", "onPublishStarted... $session")
                viewModel.setPublishDiscoverySession(session)
            }
            @RequiresApi(Build.VERSION_CODES.Q)
            override fun onMessageReceived(peerHandle: PeerHandle, message: ByteArray) {
                viewModel.setPeerHandle(peerHandle)
                val receivedMessage = String(message, Charsets.UTF_8)
                Log.i(">>>>", "onMessageReceived...$peerHandle, $receivedMessage")
                val strDispay = bindMain.tvChattingArea.text.toString() + "\n" + receivedMessage
                bindMain.tvChattingArea.text = strDispay
                //initServerSocket()
            }
            override fun onSessionTerminated() {
                Log.i(">>>>", "onSessionTerminated")
                removeCurrentWifiAwareSession()
                Toast.makeText(this@MainActivity, "fail to connect to server", Toast.LENGTH_SHORT).show()
                super.onSessionTerminated()
            }
            override fun onServiceLost(peerHandle: PeerHandle, reason: Int) {
                super.onServiceLost(peerHandle, reason)
                Log.i(">>>>", "onServiceLost $peerHandle, $reason")
            }
        }, null)
    } else {
        val config: SubscribeConfig = SubscribeConfig.Builder()
            .setServiceName(bindMain.editServiceName.text!!.toString())
            .setTtlSec(0)
            .build()
        viewModel.wifiAwareSession.value?.subscribe(config, object : DiscoverySessionCallback() {
            override fun onSubscribeStarted(session: SubscribeDiscoverySession) {
                Log.i(">>>>", "onSubscribeStarted... $session")
                viewModel.setSubscribeDiscoverySession(session)
            }
            override fun onServiceDiscovered(
                peerHandle: PeerHandle,
                serviceSpecificInfo: ByteArray,
                matchFilter: List<ByteArray>
            ) {
                Log.i(">>>>", "onServiceDiscovered... $peerHandle, $serviceSpecificInfo")
                val messageToSend = "hello...connected"
                viewModel.setPeerHandle(peerHandle)
                sendMessageViaSession(messageToSend)
                Toast.makeText(this@MainActivity, "Connected to server", Toast.LENGTH_SHORT).show()
            }
            @RequiresApi(Build.VERSION_CODES.Q)
            override fun onMessageReceived(peerHandle: PeerHandle, message: ByteArray) {
                viewModel.setPeerHandle(peerHandle)
                val receivedMessage = String(message, Charsets.UTF_8)
                Log.i(">>>>", "onMessageReceived...$peerHandle, $receivedMessage")
                val strDisplay = bindMain.tvChattingArea.text.toString() + "\n" + receivedMessage
                bindMain.tvChattingArea.text = strDisplay
                //connectToServerSocket()
            }
            override fun onSessionTerminated() {
                removeCurrentWifiAwareSession()
                Toast.makeText(this@MainActivity, "fail to connect to server", Toast.LENGTH_SHORT).show()
                super.onSessionTerminated()
            }
            override fun onServiceLost(peerHandle: PeerHandle, reason: Int) {
                super.onServiceLost(peerHandle, reason)
                Log.i(">>>>", "onServiceLost $peerHandle, $reason")
            }
        }, null)
    }   
    
    fun sendMessageViaSession(message : String){
        if(asServer!!) {
            val strToSend = "server : $message"
            viewModel.publishDiscoverySession.value?.sendMessage(
                viewModel.peerHandle.value!!,101, strToSend.toByteArray(Charsets.UTF_8))
        } else {
            val strToSend = "client : $message"
            viewModel.subscribeDiscoverySession.value?.sendMessage(
                viewModel.peerHandle.value!!,101, strToSend.toByteArray(Charsets.UTF_8))
        }
        val strDisplay = bindMain.tvChattingArea.text.toString() + "\n" + message
        bindMain.tvChattingArea.text = strDisplay
    }

 

3. 실행 결과

두개의 device로 실행 시켜 보았다.

하나는 Galaxy S9으로 이전 글에서 살펴 본 최소한의 사양은 만족하지만, 권장 사양은 만족하지 못하지만 일단 정상적인 작동은 하는 것으로 확인 되었다

 

4.  전송 버튼 작동 시키기

전송 버튼에 리스너를 달고 message를 서로 보내 보았다

@RequiresApi(Build.VERSION_CODES.S)
fun initUIListener() {
    ..........
    bindMain.btnSendViaSession.setOnClickListener{
        if(bindMain.editMessage.text.isEmpty()) return@setOnClickListener
        sendMessageViaSession(bindMain.editMessage.text.toString())
        bindMain.editMessage.text.clear()
    }
}

 

이제 서로 서로 메시지를 주고 받을 수 있게 되었다

 

정상 작동 한다

 

5. Socket을 통한 연결

앞에 살펴 보았던 개발자 페이지 내용을 보면 이 방법은 안정적이지 못하고(데이터의 전달이 안 되는 경우도 있다라고 했다), 256 byte까지의 데이터만 전달 가능하다

 

따라서 만들어진 Session을 이용한 Socket 연결 방법이 있다고 하여 다음 회에는 그 것을 구현 해 보겠다

 

+ Recent posts