├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── mrntlu
│ │ └── websocketguide
│ │ ├── MainActivity.kt
│ │ ├── service
│ │ └── WebSocketListener.kt
│ │ ├── ui
│ │ └── MainFragment.kt
│ │ └── viewmodels
│ │ └── MainViewModel.kt
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── ic_send.xml
│ ├── layout
│ ├── activity_main.xml
│ └── fragment_main.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-mdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.webp
│ └── ic_launcher_round.webp
│ ├── values-night
│ └── themes.xml
│ ├── values
│ ├── colors.xml
│ ├── strings.xml
│ └── themes.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 |
22 | # Log/OS Files
23 | *.log
24 |
25 | # Android Studio generated files and folders
26 | captures/
27 | .externalNativeBuild/
28 | .cxx/
29 | *.apk
30 | output.json
31 |
32 | # IntelliJ
33 | .idea/
34 | misc.xml
35 | deploymentTargetDropDown.xml
36 | render.experimental.xml
37 |
38 | # Keystore files
39 | *.jks
40 | *.keystore
41 |
42 | # Google Services (e.g. APIs or Firebase)
43 | google-services.json
44 |
45 | # Android Profiling
46 | *.hprof
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # WebSocket-Guide
2 |
3 | ### WebSockets in Android with OkHttp and ViewModel
4 | https://medium.com/@burakdev/websockets-in-android-with-okhttp-and-viewmodel-776a9eed67b5
5 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
3 | /src/main/java/com/mrntlu/websocketguide/Constants.kt
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | namespace 'com.mrntlu.websocketguide'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | applicationId "com.mrntlu.websocketguide"
12 | minSdk 26
13 | targetSdk 33
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 | compileOptions {
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 | kotlinOptions {
31 | jvmTarget = '1.8'
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation 'androidx.core:core-ktx:1.9.0'
37 | implementation 'androidx.appcompat:appcompat:1.6.0'
38 | implementation 'com.google.android.material:material:1.7.0'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
40 | implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
41 | implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
42 |
43 | implementation("com.squareup.okhttp3:okhttp:4.10.0")
44 |
45 | debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
46 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mrntlu/websocketguide/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.mrntlu.websocketguide
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import com.mrntlu.websocketguide.ui.MainFragment
6 |
7 | class MainActivity : AppCompatActivity() {
8 |
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | setContentView(R.layout.activity_main)
12 | if (savedInstanceState == null) {
13 | supportFragmentManager.beginTransaction()
14 | .replace(R.id.container, MainFragment.newInstance())
15 | .commitNow()
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrntlu/websocketguide/service/WebSocketListener.kt:
--------------------------------------------------------------------------------
1 | package com.mrntlu.websocketguide.service
2 |
3 | import android.util.Log
4 | import com.mrntlu.websocketguide.viewmodels.MainViewModel
5 | import okhttp3.Response
6 | import okhttp3.WebSocket
7 | import okhttp3.WebSocketListener
8 |
9 | class WebSocketListener(
10 | private val viewModel: MainViewModel
11 | ): WebSocketListener() {
12 |
13 | private val TAG = "Test"
14 |
15 | override fun onOpen(webSocket: WebSocket, response: Response) {
16 | super.onOpen(webSocket, response)
17 | viewModel.setStatus(true)
18 | webSocket.send("Android Device Connected")
19 | Log.d(TAG, "onOpen:")
20 | }
21 |
22 | override fun onMessage(webSocket: WebSocket, text: String) {
23 | super.onMessage(webSocket, text)
24 | viewModel.addMessage(Pair(false, text))
25 | Log.d(TAG, "onMessage: $text")
26 | }
27 |
28 | override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
29 | super.onClosing(webSocket, code, reason)
30 | Log.d(TAG, "onClosing: $code $reason")
31 | }
32 |
33 | override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
34 | super.onClosed(webSocket, code, reason)
35 | viewModel.setStatus(false)
36 | Log.d(TAG, "onClosed: $code $reason")
37 | }
38 |
39 | override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
40 | Log.d(TAG, "onFailure: ${t.message} $response")
41 | super.onFailure(webSocket, t, response)
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mrntlu/websocketguide/ui/MainFragment.kt:
--------------------------------------------------------------------------------
1 | package com.mrntlu.websocketguide.ui
2 |
3 | import androidx.lifecycle.ViewModelProvider
4 | import android.os.Bundle
5 | import androidx.fragment.app.Fragment
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import android.view.ViewGroup
9 | import android.widget.Button
10 | import android.widget.EditText
11 | import android.widget.ImageButton
12 | import android.widget.TextView
13 | import com.mrntlu.websocketguide.Constants
14 | import com.mrntlu.websocketguide.R
15 | import com.mrntlu.websocketguide.service.WebSocketListener
16 | import com.mrntlu.websocketguide.viewmodels.MainViewModel
17 | import okhttp3.OkHttpClient
18 | import okhttp3.Request
19 | import okhttp3.WebSocket
20 |
21 | class MainFragment : Fragment() {
22 |
23 | companion object {
24 | fun newInstance() = MainFragment()
25 | }
26 |
27 | private lateinit var viewModel: MainViewModel
28 |
29 | private lateinit var webSocketListener: WebSocketListener
30 | private val okHttpClient = OkHttpClient()
31 | private var webSocket: WebSocket? = null
32 |
33 | override fun onCreate(savedInstanceState: Bundle?) {
34 | super.onCreate(savedInstanceState)
35 | viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
36 | webSocketListener = WebSocketListener(viewModel)
37 | }
38 |
39 | override fun onCreateView(
40 | inflater: LayoutInflater, container: ViewGroup?,
41 | savedInstanceState: Bundle?
42 | ): View {
43 | return inflater.inflate(R.layout.fragment_main, container, false)
44 | }
45 |
46 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
47 | super.onViewCreated(view, savedInstanceState)
48 |
49 | val messageET = view.findViewById(R.id.messageET)
50 | val sendMessageButton = view.findViewById(R.id.sendButton)
51 | val connectButton = view.findViewById