我正在尝试使用Activity.runOnUiThread(Runnable),但Android Studio似乎认为该功能不存在。我确保已导入“ android.app.Activity”。
我正在尝试使用线程连接到蓝牙设备并读取数据。我已经列出了已配对的设备,单击已配对的设备中的一个会带我进入第二个屏幕,然后可以在该屏幕中连接/断开所选设备的插座。连接和断开连接正常。
我现在正尝试将数据流从readThread内部类发送回UI线程,但是我无法使runOnUiThread正常工作。不管我做什么,runOnUiThread都无法识别。
package com.example.idxdatalogger
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import android.view.View
import android.app.Activity
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_second.*
import java.io.IOException
import java.io.InputStream
import java.util.*
class SecondActivity : AppCompatActivity() {
var btAdapter: BluetoothAdapter? = null
var data = arrayListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
btAdapter = BluetoothAdapter.getDefaultAdapter()
val position = (intent.getStringExtra("position"))!!.toInt()
val uuid = UUID.fromString(intent.getStringExtra("UUID"))
//textView.text = position.toString()
//textView2.text = uuid.toString()
val pairedDevices: Set<BluetoothDevice> = btAdapter!!.bondedDevices
btDeviceLabel.text = pairedDevices.elementAt(position).name.toString()
var inStream = connectStream(uuid, position, pairedDevices.elementAt(position), btAdapter)
conStat(inStream)
connectButton.setOnClickListener {
inStream.start()
conStat(inStream)
}
cancelButton.setOnClickListener {
inStream.cancel()
conStat(inStream)
inStream = connectStream(uuid, position, pairedDevices.elementAt(position), btAdapter)
}
}
/*
change text and button visiblity for connect/disconnect buttons
*/
fun conStat(inStream: connectStream) {
if (inStream.socket!!.isConnected) {
socketStatus.text = getString(R.string.connectionOpened)
connectButton.visibility = View.INVISIBLE
cancelButton.visibility = View.VISIBLE
} else {
socketStatus.text = getString(R.string.connectionClosed)
connectButton.visibility = View.VISIBLE
cancelButton.visibility = View.INVISIBLE
}
}
class connectStream(
private val uuid: UUID,
private val position: Int,
private val device: BluetoothDevice,
private val adapter: BluetoothAdapter?
) : Thread() {
val socket: BluetoothSocket? = device.createRfcommSocketToServiceRecord(uuid)
override fun run() {
adapter?.cancelDiscovery()
try {
socket?.connect()
manageConnection().readThread(socket!!).start()
} catch (e: IOException) {
Log.i("SOCKET: ", "Failed to connect")
Log.i("UUID: ", uuid.toString())
Log.i("Device: ", device.name)
Log.i("Address: ", device.address)
}
}
fun cancel() {
try {
socket?.close()
} catch (e: IOException) {
Log.i("SOCKET: ", "Could not close socket")
}
}
}
class manageConnection() {
private val MESSAGE_READ: Int = 0
inner class readThread(socket: BluetoothSocket) : Thread() {
private val inStream: InputStream = socket.inputStream
private val inBuffer: ByteArray = ByteArray(1024)
override fun run() {
var readBytes: Int
while (true) {
readBytes = try { inStream.read(inBuffer)
} catch (e: IOException) {
Log.d("IN_STREAM: ", "Input stream disconnected")
break
}
SecondActivity.runOnUiThread(Runnable {
})
}
}
}
}
}
编辑:
将我的程序重新编写为使用Thread(Runnable {}),而不是为每个线程使用单独的类实例。 runOnUiThread现在可以正常工作了。我已经在下面发布了更新的代码,但这还没有完全正常运行。现在,我们可以考虑解决问题了。
package com.example.idxdatalogger
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothSocket
import android.util.Log
import android.view.View
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.os.*
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_second.*
import java.io.IOException
import java.io.InputStream
import java.util.*
/*
*/
class SecondActivity : AppCompatActivity() {
var btAdapter: BluetoothAdapter? = null
var data = arrayListOf<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
btAdapter = BluetoothAdapter.getDefaultAdapter()
val position = (intent.getStringExtra("position"))!!.toInt()
val uuid = UUID.fromString(intent.getStringExtra("UUID"))
val pairedDevices: Set<BluetoothDevice> = btAdapter!!.bondedDevices
val device = pairedDevices.elementAt(position)
btDeviceLabel.text = pairedDevices.elementAt(position).name.toString()
val socket: BluetoothSocket? = device.createRfcommSocketToServiceRecord(uuid)
//var inStream = connectStream(uuid, position, pairedDevices.elementAt(position), btAdapter)
conStat(socket!!)
val inStream: InputStream = socket.inputStream
val inBuffer: ByteArray = ByteArray(1024)
var readBytes : Int
connectButton.setOnClickListener {
//connect to device
Thread(Runnable {
kotlin.run {
btAdapter?.cancelDiscovery()
try {
socket.connect()
runOnUiThread(Runnable { conStat(socket) })
//read stream
Thread(Runnable{
while(true) {
readBytes = try {
inStream.read(inBuffer)
} catch (e: IOException) {
Log.d("IN_STREAM: ", "input stream disconnected")
break
}
//return stream information to UI thread
runOnUiThread(Runnable {
data.add(inBuffer.toString())
dataList.adapter = dataListAdapter(this,data)
dataList.visibility = View.VISIBLE
})
}
}).start()
} catch (e: IOException) {
Log.i("SOCKET: ", "Failed to connect")
Log.i("UUID: ", uuid.toString())
Log.i("Device: ", pairedDevices.elementAt(position).name)
Log.i("Address: ", pairedDevices.elementAt(position).address)
}
}
}).start()
}
cancelButton.setOnClickListener {
//close socket connection
Thread(Runnable {
try {
socket.close()
} catch (e: IOException) {
Log.i("SOCKET: ", "Could not close socket")
}
runOnUiThread(Runnable {
conStat(socket)
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
})
}).start()
}
}
/*
change text and button visiblity for connect/disconnect buttons
*/
fun conStat(socket : BluetoothSocket) {
if (socket.isConnected) {
socketStatus.text = getString(R.string.connectionOpened)
connectButton.visibility = View.INVISIBLE
cancelButton.visibility = View.VISIBLE
} else {
socketStatus.text = getString(R.string.connectionClosed)
connectButton.visibility = View.VISIBLE
cancelButton.visibility = View.INVISIBLE
}
}
答案 0 :(得分:0)
您必须将inner
添加到manageConnection
类中,然后才可以使用runOnUiThread {}
答案 1 :(得分:0)
SecondActivity.runOnUiThread(...)
是不正确的,因为您在类上调用方法,而runOnUiThread()
方法不是静态的。 您需要在Activity
类的实例上调用此方法,而不是在类本身上调用。
答案 2 :(得分:0)
请在此处查看runOnUiThread签名:
/**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
*
* @param action the action to run on the UI thread
*/
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
很明显,它不是静态方法,因此您不能将这种方法称为静态方法,如下所示:
SomeActivity.runOnUiThread {}
一种解决方法是将SecondActivity作为实例传递,然后轻松地对活动实例进行任何操作。
class myClass(val activity : Activity){
fun someMethod(){
activity.runOnUithread{}
}
}
答案 3 :(得分:0)
如果您想从后台线程运行runOnUiThread,可以使用此
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = new Runnable() {
@Override
public void run() {....}
};
mainHandler.post(myRunnable);
在这种情况下,您不需要活动,因为Thread
类不必在活动中。
另外,请尝试使用Couroutines,RxKotlin,Google.Tasks和AsyncTask来更好地处理线程。