【问题标题】:can you help me understand why my recyclerview is not being populated with data?你能帮我理解为什么我的 recyclerview 没有填充数据吗?
【发布时间】: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


    【解决方案1】:

    据此我认为在 UI 中只显示一个您可以滚动的项目然后显示另一个项目请检查此解决方案请将布局高度更改为包装内容

    <?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="wrap_content">
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/scan_item_tv"/>
    
    </LinearLayout>
    

    还请确保授予和实施运行时权限。 谢谢

    【讨论】:

    • 我进行了更改,recyclerview 的扫描结果仍然没有显示在 UI 中
    【解决方案2】:

    你能检查一下这个功能日志打印吗?

    private void loadScanResults() {
            Log.w(LOG_TAG, "results: ");
            for (final BluetoothDevice device : mScanResults) {
                Log.w(LOG_TAG, device.getName());
            }
    
            mScanAdapter.notifyDataSetChanged();
        }
    

    【讨论】:

    • 我编辑了我的帖子并添加了日志输出以进行澄清
    【解决方案3】:

    我使用 DialogFragment 作为 AlertDialog 的方式肯定有一些冲突。

    我最终在一个单独的文件中重新实现了 BleConnDialogFragment,并在 MainActivity 中注释掉了我原来的那个。我的方法是在片段的 onCreateDialog 中什么都不做,并在 onCreateView 中实现所有内容。为了测试,我将在适配器中填充 ViewHolders 的 ArrayList 的类型更改为仅字符串,在 onCreateDialog 中初始化字符串,并看到它出现在 UI 中。然后我恢复到原来的 ScanAdapter,它工作了。这里是 onCreateDialog 和 onCreateView

    @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            Log.w(LOG_TAG, "onCreateDialog");
            return new Dialog(getContext());
        }
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            Log.w(LOG_TAG, "onCreateView");
    
            View view = inflater.inflate(R.layout.fragment_ble_conn,container,false);
    
            view.findViewById(R.id.btn_scan_for_devices).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.w(LOG_TAG, "scan started");
    
                    startBleScan();
                    bleHandler.post(bleScanTimer);
    
                    pd = new ProgressDialog(getContext());
                    pd.setTitle("Scanning...");
                    pd.setMessage("Please wait...");
                    pd.setCancelable(true);
                    pd.show();
                }
            });
            view.findViewById(R.id.btn_scan_select).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                }
            });
    
            mRecycler = view.findViewById(R.id.rv_scan_devices);
            mScanAdapter = new ScanListAdapter((MainActivity)getActivity(), mDevices);
            mRecycler.setLayoutManager(new LinearLayoutManager((MainActivity)getActivity()));
            mRecycler.setAdapter(mScanAdapter);
    
            return view;
        }
    

    这里是我调用 notifyDataSetChanged() 的地方

    private Runnable bleScanTimer = new Runnable() {
            @Override
            public void run() {
                Log.w(LOG_TAG,"blescantimer");
                if (scanTimeOut) {
                    Log.w(LOG_TAG, "stopping scan; devices found: " + mDevices.size());
                    mScanner.stopScan(mScanCallback);
                    scanTimeOut = false;
                    pd.dismiss();
                    mScanAdapter.notifyDataSetChanged();
    
                } else {
                    bleHandler.postDelayed(this::run, 10000);
                    scanTimeOut = true;
                }
            }
        };
    

    【讨论】:

      猜你喜欢
      • 2011-04-02
      • 1970-01-01
      • 2021-08-01
      • 2021-06-11
      • 1970-01-01
      • 2011-08-18
      • 2014-10-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多