我编写了一个Android BLE样本。我想让它显示它刚刚在我的列表视图中扫描的外围女巫。为什么我必须放
mLeScanListAdpter.addDevice(device);
mLeScanListAdpter.notifyDataSetChanged();
在runOnUiThread()
方法中?
如果我不使用此方法,列表视图在我的程序发现设备时不会显示设备信息,只是在我触摸手机屏幕几秒钟后显示它。
我认为,onLeScan()
方法在主线程上运行。所以,
mLeScanListAdpter.addDevice(device);
mLeScanListAdpter.notifyDataSetChanged();
在主线程上运行,即使我没有将它放在runOnUiThread()
方法中。并且,主要thread = UI thread
,不是吗?
所以,我认为,即使我没有将它放在runOnUiThread()
方法中,也可以在ui Thread上运行。但事实上,它不起作用,我必须把它放在runOnUiThread()
方法中。
我很困惑,为什么?
这是我的代码。
public class MainActivity extends ListActivity {
BluetoothManager bluetoothManager;
BluetoothAdapter bluetoothAdapter;
static final int REQUEST_ENABLE_BT = 0;
private Handler mHandler = new Handler();
LeScanListAdpter mLeScanListAdpter = new LeScanListAdpter();
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
/*------------!!!!!!!!Pay attention!!!!!!!---------------
------------There is the question--------------------*/
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeScanListAdpter.addDevice(device);
mLeScanListAdpter.notifyDataSetChanged();
Log.w("scan",
"name:" + device.getName() + " address:"
+ device.getAddress());
}
});
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setListAdapter(mLeScanListAdpter);
// 1.获取manager
bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
// 2.获取adapter
bluetoothAdapter = bluetoothManager.getAdapter();
// 3.开启蓝牙
/*
* 调用isEnabled())去检测蓝牙当前是否开启。 如果该方法返回false,蓝牙被禁用。
* 如果没有开启,将显示错误提示用户去设置开启蓝牙。
*/
if (!bluetoothAdapter.isEnabled()) {
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent, REQUEST_ENABLE_BT);
}
// 4.扫描ble设备
LeScan();
}
private void LeScan() {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
bluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, 10000);
bluetoothAdapter.startLeScan(mLeScanCallback);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private class LeScanListAdpter extends BaseAdapter {
private ArrayList<BluetoothDevice> allDevices;
public LeScanListAdpter() {
super();
allDevices = new ArrayList<BluetoothDevice>();
}
@Override
public int getCount() {
return allDevices.size();
}
public void addDevice(BluetoothDevice d) {
if(allDevices.contains(d)){
return;
}
allDevices.add(d);
}
@Override
public Object getItem(int position) {
return allDevices.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
BluetoothDevice d = allDevices.get(position);
// 如果view为null
if (convertView == null) {
convertView = MainActivity.this.getLayoutInflater().inflate(
R.layout.activity_main, null);
}
if (d.getName() == null) {
((TextView) convertView.findViewById(R.id.name_text_view))
.setText("unknown");
((TextView) convertView
.findViewById(R.id.device_address_text_view)).setText(d
.getAddress());
} else {
((TextView) convertView.findViewById(R.id.name_text_view))
.setText(d.getName());
((TextView) convertView
.findViewById(R.id.device_address_text_view)).setText(d
.getAddress());
}
return convertView;
}
}
}
答案 0 :(得分:0)
UI可以在主线程上更改,而不是仅线程&#39;主线程&#39;
也许onLeScan()方法在线程上运行,而不是主线程,
你可以检查......if(Looper.myLooper() == Looper.getMainLooper()) {
you are on ui thread
} else {
you are not on ui thread
}