I use implementation 'com.microsoft.signalr:signalr:6.0.8' for android (kotlin) and backend is .Net 6
but the emulator cannot connect to the server (localhost). I try to code a function to check hubConnection.connectionState, it is DISCONNECTED.
no error happened. Can anyone guide me to find the error, here is the code:
import com.microsoft.signalr.Action1
import com.microsoft.signalr.HubConnection
import com.microsoft.signalr.HubConnectionBuilder
import com.microsoft.signalr.HubConnectionState
import io.reactivex.rxjava3.core.Single
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class SignalRListener private constructor(){
private var hubConnection: HubConnection
private var logger: Logger
init {
logger = LoggerFactory.getLogger(HubConnection::class.java)
// define in constructor
hubConnection = HubConnectionBuilder.create("http://10.0.2.2:5291/hubs/presence")
.withAccessTokenProvider(Single.defer { Single.just("${Constanst.TOKEN}") })
.build()
hubConnection.on("UserIsOnline",
Action1 { member: Member -> println(member.DisplayName + "online") },
Member::class.java
)
hubConnection.on("UserIsOffline",
Action1 { username: String -> println(username+" offline") },
String::class.java
)
hubConnection.on(
"GetOnlineUsers",
Action1 { usersOnline : List<Member> ->
for (item in usersOnline) {
println(item.DisplayName)
}
},
List::class.java
)
hubConnection.start().doOnError({ logger.info("Client connected error.") })
}
private object Holder { val INSTANCE = SignalRListener() }
companion object {
#JvmStatic
fun getInstance(): SignalRListener{
return Holder.INSTANCE
}
}
fun stopHubConnection(){
if(hubConnection.connectionState == HubConnectionState.CONNECTED){
hubConnection.stop()
}
}
fun getConnectionState(){
println(hubConnection.connectionState.toString())
}
fun log(){
logger.info("Debug infor siganlR {}", hubConnection.connectionId)
}
}
Web (React) runs well with the backend.
class MainActivity : AppCompatActivity() {
lateinit var signalR: SignalRListener;
var btnCheck: Button? = null
var btnLog: Button? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
signalR = SignalRListener.getInstance()
btnCheck = findViewById(R.id.btnCheck)
btnCheck?.setOnClickListener {
signalR.getConnectionState()
}
btnLog = findViewById(R.id.btnLog)
btnLog?.setOnClickListener {
signalR.log()
}
}
}
As you are in the android emulator, You have to access your localhost so that it reaches your server. If you need internet through proxy you can also set it from the Settings and Proxy and there you can define your proxy settings.
I fixed the problem with the following:
in BE(.Net Core) remove this line:
app.UseHttpsRedirection();
and the client calls http not https:
hubConnection = HubConnectionBuilder.create("http://10.0.2.2:5291/hubs/presence")
hubConnection.start().blockingAwait()
It worked fine
Related
I'm trying to create a BLE service that will scan for devices and using rxKotlin create an observable that will allow another class to observe when a device is found. I'm confused on how to create the observable that will allow another class to subscribe and tutorials are all over the place. Can someone give me a pointer on how to do so or a good tutorial.
Bluetoothservice class callback where devices are discovered
var foundDeviceObservable: Observable<BluetoothDevice> = Observable.create { }
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
with(result.device) {
var foundName = if (name == null) "N/A" else name
foundDevice = BluetoothDevice(
foundName,
address,
address,
result.device.type.toString()
)
foundDeviceObservable.subscribe {
//Update Observable value?
}
}
}
}
class DeviceListViewModel(application: Application) : AndroidViewModel(application) {
private val bluetoothService = BLEService()
//Where I am trying to do logic with device
fun getDeviceObservable(){
bluetoothService.getDeviceObservable().subscribe{ it ->
}
}
Solution
Was able to find the solution after reading user4097210's reply. Just had to change the found device to
var foundDeviceObservable: BehaviorSubject<BluetoothDevice> = BehaviorSubject.create()
and then call the next method in the callback
private val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
with(result.device) {
var foundName = if (name == null) "N/A" else name
foundDevice = BluetoothDevice(
foundName,
address,
address,
result.device.type.toString()
)
foundDeviceObservable.onNext(foundDevice)
}
}
}
use BehaviorSubject
// create a BehaviorSubject
var foundDeviceObservable: BehaviorSubject<BluetoothDevice> = BehaviorSubject()
// call onNext() to send new found device
foundDeviceObservable.onNext(foundDevice)
// do your logic use foundDeviceObservable
foundDeviceObservable.subscribe(...)
I am trying to use mysql data in my basic Kotlin app and i use Android Studio. I've retrieved data and printed them into console with running only "Test.kt" file. But i want to use it in textView and stuff.
test.kt
When i want to run whole app, i'm facing "No suitable driver found" error.
MainActivity.kt
Here is my code:
MainActivity.kt
package com.example.dbtest
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
var list = ArrayList<DataModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
list = DBCon.connection()
for (i in 0 until list.size){
if (i == list.size){
textView.text = list[list.size].firstName + list[list.size].lastName
}
}
}
}
}
DBCon.kt
package com.example.dbtest
import java.sql.DriverManager
import java.sql.ResultSet
import java.sql.SQLException
object DBCon {
#JvmStatic
fun connection(): ArrayList<DataModel> {
var list = ArrayList<DataModel>()
try {
val connection = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/testdb",
"root",
""
)
val statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)
val result = statement.executeQuery("SELECT `id`, `firstName`, `lastName` FROM `testtable`")
while (result.next()){
list.add(DataModel(result.getInt("id"), result.getString("firstName"),result.getString("lastName")))
}
} catch (e: SQLException) {
e.printStackTrace()
}
return list
}
}
Test.kt
package com.example.dbtest
fun main(){
var list = ArrayList<DataModel>()
list = DBCon.connection()
for (i in 0 until list.size){
println(list[i].id.toString() + "- " + list[i].firstName + " " + list[i].lastName)
}
}
DataModel.kt
package com.example.dbtest
data class DataModel(val id: Int, val firstName: String, val lastName: String)
I'm new to Kotlin and i learned a lot new things to figure this out but i couldn't. Please lead my way to work this out. Thanks in advance.
P.S. Here is some things i did based on my search in order to solve this:
added jar file -> mysql-connector-java-8.0.21 and used as library // Done already
tried to add -> Class.forName("com.mysql.jdbc.Driver") // Not worked
tried to add -> Class.forName("com.mysql.cj.jdbc.Driver") // Not worked
added permission -> "android.permission.INTERNET" // Not worked
even tried to use -> AsyncTask // Not worked
I have a confusion about how Dispatchers work in Kotlin
Task
In my Application class I intend to access my database via Room, take out the user , take out his JWT accessToken and set it in another object that my retrofit Request inteceptor uses.
However I want all this code to be blocking , so that when the Application class has ran to its completion , the user has been extracted and set in the Inteceptor.
Problem
My application class runs to completion BEFORE the user has been picked from the database.
Session class is the one which accesses Room
This is how my session class looks
class Session(private val userRepository: UserRepository, private var requestHeaders: RequestHeaders) {
var authenticationState: AuthenticationState = AuthenticationState.UNAUTHENTICATED
var loggedUser: User? by Delegates.observable<User?>(null) { _, _, user ->
if (user != null) {
user.run {
loggedRoles = roleCsv.split(",")
loggedRoles?.run {
if (this[0] == "Employer") {
employer = toEmployer()
} else if (this[0] == "Employee") {
employee = toEmployee()
}
}
authenticationState = AuthenticationState.AUTHENTICATED
requestHeaders.accessToken = accessToken
}
} else {
loggedRoles = null
employer = null
employee = null
authenticationState = AuthenticationState.UNAUTHENTICATED
requestHeaders.accessToken = null
}
}
var loggedRoles: List<String>? = null
var employee: Employee? = null
var employer: Employer? = null
init {
runBlocking(Dispatchers.IO) {
loggedUser = userRepository.loggedInUser()
Log.d("Session","User has been set")
}
}
// var currentCity
// var currentLanguage
}
enum class AuthenticationState {
AUTHENTICATED, // Initial state, the user needs to secretQuestion
UNAUTHENTICATED, // The user has authenticated successfully
LOGGED_OUT, // The user has logged out.
}
This is my Application class
class MohreApplication : Application()
{
private val session:Session by inject()
private val mohreDatabase:MohreDatabase by inject() // this is integral. Never remove this from here. This seeds the data on database creation
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this#MohreApplication)
modules(listOf(
platformModule,
networkModule,
....
))
}
Log.d("Session","Launching application")
}
My Koin module which creates the session
val platformModule = module {
// single { Navigator(androidApplication()) }
single { Session(get(),get()) }
single { CoroutineScope(Dispatchers.IO + Job()) }
}
In my Logcat first "Launching Application" prints out and THEN "User has been set"
Shouldn't it be reverse? . This is causing my application to launch without the Session having the user and my MainActivity complains.
by inject() is using kotlin lazy initialization. Only when session.loggedUser is queried will the init block be fired.
In your case, when you call session.loggedUser in the MainActivity, the init block will fire and block the calling thread.
What you can do is.
import org.koin.android.ext.android.get
class MohreApplication : Application()
{
private lateinit var session: Session
private lateinit var mohreDatabase: MohreDatabase // this is integral. Never remove this from here. This seeds the data on database creation
override fun onCreate() {
super.onCreate()
startKoin {
androidLogger()
androidContext(this#MohreApplication)
modules(listOf(
platformModule,
networkModule,
....
))
}
session = get()
mohreDatabase = get()
Log.d("Session","Launching application")
}
In my application i want use Socket.io and for this i add below library and write below codes.
But when run application and click on button not show me any event!
I used kotlin for write android application.
After click on button, should show me socket state in textView, but not show any state!
Socket library :
compile 'com.github.nkzawa:socket.io-client:0.5.2'
My Codes:
class SocketActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_socket)
val opts = IO.Options()
opts.query = "token=${Constants.BIDZILA_TOKEN}"
var socket = IO.socket(Constants.BIDZILA_SOCKET, opts)
btnSend.setOnClickListener {
socket.connect()
Handler(Looper.getMainLooper()).postDelayed(
{ socket?.on(Socket.EVENT_CONNECT) {
Log.d("SocketLog", "==============================CONNECTED")
socket_stateTxt.text = socket.connected().toString()
}?.on(Socket.EVENT_DISCONNECT) {
Log.d("SocketLog", "==============================OFF")
socket_stateTxt.text = socket.connected().toString()
} },
2000
)
}
}
}
How can i fix it?
I'm establishing the connection like this:
private var socket = IO.socket("<YOUR_URL>")
socket.let {
it!!.connect()
.on(Socket.EVENT_CONNECT) {
Log.d("SignallingClient", "Socket connected!!!!!")
}
}
Hello I'm using RxAndroidBLE to detect a BLE device. On android 6 >= everything seems to work okay but not on a 4.3 device.
My app can only discover the desirable BLE device only once at start. After the device has been discovered no more new discoveries at all until I restart the app. Any advice would be highly appreciated.
Below minimum (not)working code example:
MainActivity
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.exceptions.BleScanException
import com.polidea.rxandroidble.scan.ScanResult
import com.polidea.rxandroidble.scan.ScanSettings
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import java.util.*
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startLeScan(applicationContext)
}
private var rxBleClient: RxBleClient? = null
private var scanSubscription: Subscription? = null
private var handler: Handler? = null
private var timer: Timer? = null
private var timerTask: TimerTask? = null
private var delay: Int = 0
private fun isScanning(): Boolean {
return scanSubscription != null
}
fun startLeScan(context: Context) {
rxBleClient = MyaPP.getRxBleClient(context)
if (isScanning()) {
scanSubscription?.unsubscribe()
} else {
scanSubscription = rxBleClient?.scanBleDevices(
com.polidea.rxandroidble.scan.ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build())
?.observeOn(AndroidSchedulers.mainThread())
//?.doOnNext(this::newDevicesFound)
?.doOnUnsubscribe(this::clearSubscription)
?.subscribe(this::newDevicesFound, this::onScanFailure)
}
if(handler == null) {
handler = Handler()
timer = Timer(false)
timerTask = object : TimerTask() {
override fun run() {
handler?.post {
if (delay > 7) {
delay = 0
val service = Executors.newSingleThreadExecutor()
service.submit(Runnable {
//startLeScan(context)
})
} else {
delay = delay + 1
}
}
}
}
timer?.scheduleAtFixedRate(timerTask, 0, 300)
}
}
private fun newDevicesFound(devices: ScanResult) {
Log.d("WHYY??", devices.bleDevice.name)
}
fun stopScan() {
scanSubscription?.unsubscribe()
destroy()
}
private fun clearSubscription() {
scanSubscription = null
}
private fun onScanFailure(throwable: Throwable) {
if (throwable is BleScanException) {
handleBleScanException(throwable)
}
}
private fun handleBleScanException(bleScanException: BleScanException) {
val text: String
when (bleScanException.reason) {
BleScanException.BLUETOOTH_NOT_AVAILABLE -> text = "Bluetooth is not available"
BleScanException.BLUETOOTH_DISABLED -> text = "Enable bluetooth and try again"
BleScanException.LOCATION_PERMISSION_MISSING -> text = "On Android 6.0 location permission is required. Implement Runtime Permissions"
BleScanException.LOCATION_SERVICES_DISABLED -> text = "Location services needs to be enabled on Android 6.0"
BleScanException.SCAN_FAILED_ALREADY_STARTED -> text = "Scan with the same filters is already started"
BleScanException.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> text = "Failed to register application for bluetooth scan"
BleScanException.SCAN_FAILED_FEATURE_UNSUPPORTED -> text = "Scan with specified parameters is not supported"
BleScanException.SCAN_FAILED_INTERNAL_ERROR -> text = "Scan failed due to internal error"
BleScanException.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES -> text = "Scan cannot start due to limited hardware resources"
BleScanException.UNDOCUMENTED_SCAN_THROTTLE -> text = String.format(
Locale.getDefault(),
"Android 7+ does not allow more scans. Try in %d seconds",
secondsTill(bleScanException.retryDateSuggestion)
)
BleScanException.UNKNOWN_ERROR_CODE, BleScanException.BLUETOOTH_CANNOT_START -> text = "Unable to start scanning"
else -> text = "Unable to start scanning"
}
Log.w("EXCEPTION", text, bleScanException)
}
private fun secondsTill(retryDateSuggestion: Date?): Long {
if (retryDateSuggestion != null) {
return TimeUnit.MILLISECONDS.toSeconds(retryDateSuggestion.time - System.currentTimeMillis())
}
return 0
}
private fun destroy() {
timer?.cancel()
handler?.removeCallbacks(timerTask)
handler = null
timerTask = null
timer = null
}
}
MyaPP
import android.app.Application
import android.content.Context
import com.polidea.rxandroidble.RxBleClient
import com.polidea.rxandroidble.internal.RxBleLog
class MyaPP: Application() {
private var rxBleClient: RxBleClient? = null
companion object {
fun getRxBleClient(context: Context): RxBleClient? {
val application = context.applicationContext as MyaPP
return application.rxBleClient
}
}
override fun onCreate() {
super.onCreate()
rxBleClient = RxBleClient.create(this)
RxBleClient.setLogLevel(RxBleLog.DEBUG)
}
}
build.gradle
compile "com.polidea.rxandroidble:rxandroidble:1.5.0"
implementation 'io.reactivex:rxandroid:1.2.1'
manifest
<application
android:name=".MyaPP"
Your code looks a lot like the library's sample app (version 1.5.0, branch master-rxjava1). I have checked that recently on Android 4.4.4 which is the oldest I have and it worked fine. There were no API changes between 4.3 and 4.4.
What you may be experiencing is a behaviour specific to your device (feel free to share your phone model) in which it only callbacks for the first time it scans a particular peripheral. There are some threads about this topic already like this one.