【发布时间】:2021-03-17 15:03:46
【问题描述】:
在我的应用程序中,我正在扫描广告 BLE 设备,我想在回收站视图中显示结果。我可以很好地扫描设备,但它们没有被添加到 recyclerview 中。我在主要活动中创建了一个对话框片段:
public static class BleConnDialogFragment extends DialogFragment {
private RecyclerView bleRecycler;
private ScanListAdapter mScanAdapter;
private void loadScanResults() {
Log.w(LOG_TAG, "results: ");
for (final BluetoothDevice device : mScanResults) {
Log.w(LOG_TAG, device.getName());
}
mScanAdapter.notifyDataSetChanged();
}
@Override
@NonNull
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.w(LOG_TAG,"bledialog onactivitycreated");
}
@Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
Log.w(LOG_TAG, "ble dialog oncreatedialog");
LayoutInflater layoutInflater = getActivity().getLayoutInflater();
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
View view = layoutInflater.inflate(R.layout.dialog_ble_config, null);
builder.setView(view);
Button scanForDevices = view.findViewById(R.id.btn_scan_for_devices);
mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, @NonNull ScanResult result) {
Log.w(LOG_TAG, "onScanResult: " + result.getDevice().getName() + " " + result.getDevice().getAddress());
}
@Override
public void onBatchScanResults(@NonNull List<ScanResult> results) {
Log.w(LOG_TAG, "onBatchScanResults ");
for (final ScanResult result : results) {
boolean add = true;
Log.w(LOG_TAG, "batch scan device: " + result.getDevice().getName() + " " + result.getDevice().getAddress());
for (final BluetoothDevice device : mScanResults) {
if (result.getDevice().getAddress().toString().equals(device.getAddress().toString())) {
add = false;
}
}
if (add == false || result.getDevice().getName() == null) continue;
((MainActivity)getActivity()).mScanResults.add(result.getDevice());
}
}
@Override
public void onScanFailed(int errorCode) {
Log.w(LOG_TAG, "scan failed");
}
};
bleScanTimer = new Runnable() {
@Override
public void run() {
Log.w(LOG_TAG,"blescantimer");
if (scanTimeOut) {
Log.w(LOG_TAG, "stopping scan; devices found: " + mScanResults.size());
mScanner.stopScan(mScanCallback);
mProgressDialog.dismiss();
scanTimeOut = false;
loadScanResults();
} else {
bleHandler.postDelayed(this::run, 10000);
scanTimeOut = true;
}
}
};
scanForDevices.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.w(LOG_TAG, "scanning for devices...");
mScanner = BluetoothLeScannerCompat.getScanner();
ScanSettings settings = new ScanSettings.Builder()
.setLegacy(false)
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(1000)
.setUseHardwareBatchingIfSupported(true)
.build();
List<ScanFilter> filters = new ArrayList<>();
filters.add(new ScanFilter.Builder().setServiceUuid(null).build());
mScanner.startScan(filters, settings, mScanCallback);
bleHandler.post(bleScanTimer);
mProgressDialog = MyUtilities.createDialog(getContext());
}
});
((MainActivity)getActivity()).bleConnDialog = builder.create();
return ((MainActivity)getActivity()).bleConnDialog;
}
@Override
@NonNull
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.w(LOG_TAG, "ble dialog oncreateview");
View view = inflater.inflate(R.layout.dialog_ble_config, container, false);
bleRecycler = view.findViewById(R.id.rv_scan_devices);
mScanAdapter = new ScanListAdapter(this.getContext(), mScanResults);
bleRecycler.setAdapter(mScanAdapter);
bleRecycler.setLayoutManager(new LinearLayoutManager(this.getContext()));
return view;
}
}
这是包含recyclerview的片段的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dialog_padding"
android:paddingEnd="@dimen/dialog_padding">
<TextView
android:id="@+id/ble_config_title_tv"
style="@style/TextAppearance.AppCompat.Headline"
android:layout_width="400dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/dialog_content_margin_between"
android:gravity="center"
android:text="@string/wifi_setup_ble" />
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rv_scan_devices"/>
<Button
android:id="@+id/btn_scan_for_devices"
style="@style/MyFlatButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_height"
android:layout_weight="1"
android:layout_gravity="center"
android:text="@string/scan_for_devices" />
</LinearLayout>
</LinearLayout>
这是扫描结果项的布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/scan_item_tv"/>
</LinearLayout>
这里是 recyclerview 适配器:
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
public class ScanListAdapter extends RecyclerView.Adapter<ScanListAdapter.ResultViewHolder> {
private LayoutInflater mInflater;
private final ArrayList<BluetoothDevice> mScanResults;
@NonNull
@Override
public ScanListAdapter.ResultViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View mItemView = mInflater.inflate(R.layout.ble_scan_item, parent,false);
return new ResultViewHolder(mItemView, this);
}
@Override
public void onBindViewHolder(@NonNull ScanListAdapter.ResultViewHolder holder, int position) {
String mCurrent = mScanResults.get(position).getName().toString();
holder.resultItemView.setText(mCurrent);
}
@Override
public int getItemCount() {
return mScanResults.size();
}
class ResultViewHolder extends RecyclerView.ViewHolder {
public final TextView resultItemView;
final ScanListAdapter mAdapter;
public ResultViewHolder(View itemView, ScanListAdapter adapter) {
super(itemView);
resultItemView = itemView.findViewById(R.id.scan_item_tv);
this.mAdapter = adapter;
}
}
public ScanListAdapter(Context context, ArrayList<BluetoothDevice> devices) {
mInflater = LayoutInflater.from(context);
this.mScanResults = devices;
}
}
在函数 loadScanResults 中,我可以使用此日志输出确认扫描结果:
W/MainActivity: onBatchScanResults
W/MainActivity: batch scan device: null 61:12:97:F8:1E:77
W/MainActivity: batch scan device: null 61:9D:C3:3F:7D:66
W/MainActivity: batch scan device: null 42:4C:D1:37:14:68
W/MainActivity: batch scan device: null FB:04:CD:76:F3:D1
W/MainActivity: batch scan device: xb-14332525 30:AE:A4:76:F2:42
W/MainActivity: batch scan device: null 70:D1:E7:26:FC:8F
W/MainActivity: batch scan device: null 52:1B:AA:91:BC:85
W/MainActivity: blescantimer
stopping scan; devices found: 1
D/BluetoothAdapter: STATE_ON
D/BluetoothAdapter: STATE_ON
D/BluetoothAdapter: STATE_ON
D/BluetoothAdapter: STATE_ON
D/BluetoothLeScanner: Stop Scan
D/ViewRootImpl@d460417[MainActivity]: mHardwareRenderer.destroy()#4
D/ViewRootImpl@d460417[MainActivity]: dispatchDetachedFromWindow
D/InputTransport: Input channel destroyed: fd=74
W/MainActivity: results:
W/MainActivity: xb-14332525
D/ViewRootImpl@294cfa4[MainActivity]: MSG_WINDOW_FOCUS_CHANGED 1
D/ViewRootImpl@294cfa4[MainActivity]: mHardwareRenderer.initializeIfNeeded()#2 mSurface={isValid=true 547575401984}
E/ViewRootImpl: sendUserActionEvent() returned.
在我看来,应该就是在onCreateView中配置recycler,然后在loadScanResults中调用notifyDataSetChanged那么简单。我的 ScanListAdapter 代码基本上是直接从谷歌代码实验室改编而来的。我不明白为什么扫描结果没有出现在 UI 中。
提前感谢您提供任何指导或提示。
【问题讨论】:
标签: java android android-layout android-recyclerview