You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

软键盘开启时应用列表RecyclerView无法实时更新问题

问题描述

应用支持搜索已安装应用,软键盘关闭时搜索结果正常,但软键盘开启时RecyclerView无法实时更新;使用模拟器物理键盘则能正常刷新。预期软键盘输入时列表能实时更新,实际输入时列表空白,关闭键盘后才显示结果。


提供的代码

Fragment类代码

public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    recyclerView = view.findViewById(R.id.justtype_view);
    layoutManager = new GridLayoutManager(getContext(), 4);
    recyclerView.setLayoutManager(layoutManager);
    jt = view.findViewById(R.id.jtInput);
    jt.requestFocus();
    jt.isFocusableInTouchMode();
    jt.setFocusable(true);
    if (jt.requestFocus()) {
        InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(jt, InputMethodManager.SHOW_IMPLICIT);
    }

    Window w = requireActivity().getWindow();
    w.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.status));
    recyclerView.setVisibility(View.INVISIBLE);
    jtAdapter = new JTAdapter(requireContext(), jt.getText().toString());
    recyclerView.setAdapter(jtAdapter);


    new Thread(this::contactsSearch).start();

    jt.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {
            if (jt.getText().toString().length()>0) {
                jtAdapter = new JTAdapter(requireContext(), s.toString());
                recyclerView.setAdapter(jtAdapter);
                jtAdapter.notifyDataSetChanged();
                recyclerView.setVisibility(View.VISIBLE);
                textChange(view);
            } else {
                recyclerView.setVisibility(View.INVISIBLE);
            }
        }
    });
}

JTAdapter类代码

public class JTAdapter extends RecyclerView.Adapter<JTAdapter.ViewHolder> {

    public static List<AppInfo> jtList;

    public JTAdapter(Context c, String q) {
        new Thread(() -> {
            PackageManager pm = c.getPackageManager();
            jtList = new ArrayList<>();
            Intent i = new Intent(Intent.ACTION_MAIN, null);
            i.addCategory(Intent.CATEGORY_LAUNCHER);
            List<ResolveInfo> allApps = pm.queryIntentActivities(i, 0);
            if(q.length() == 0) {
                for (ResolveInfo ri : allApps) {
                    AppInfo app = new AppInfo();
                    app.label = ri.loadLabel(pm);
                    app.packageName = ri.activityInfo.packageName;
                    app.icon = ri.activityInfo.loadIcon(pm);
                    jtList.add(app);
                }
                jtList.sort(Comparator.comparing(o -> o.label.toString()));
            } else {
                for (ResolveInfo ri : allApps) {
                    AppInfo app = new AppInfo();
                    app.label = ri.loadLabel(pm);
                    app.packageName = ri.activityInfo.packageName;
                    app.icon = ri.activityInfo.loadIcon(pm);
                    if(app.label.toString().toLowerCase().startsWith(q)) {
                        jtList.add(app);
                    }
                }

                jtList.sort(Comparator.comparing(o -> o.label.toString()));

            }

        }).start();
    }

    @Override
    public int getItemCount() {
        return jtList.size();
    }

    public void onBindViewHolder(@NonNull JTAdapter.ViewHolder viewHolder, int i) {
        try {
            String appLabel = jtList.get(i).label.toString();
            Drawable appIcon = jtList.get(i).icon;
            TextView textView = viewHolder.textView;
            textView.setText(appLabel);
            ImageView imageView = viewHolder.img;
            imageView.setImageDrawable(appIcon);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @NonNull
    public JTAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.jt_item_row_layout, parent, false);
        return new ViewHolder(view);
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        public ImageView img;

        public ViewHolder(View itemView) {

            super(itemView);
            textView = itemView.findViewById(R.id.jt_app_name);
            img = itemView.findViewById(R.id.jt_app_icon);

            itemView.setOnClickListener(v -> {
                int pos = getAdapterPosition();
                Context context = v.getContext();
                Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(jtList.get(pos).packageName.toString());
                context.startActivity(launchIntent);
            });
        }
    }
}

修复方案

1. 重构JTAdapter,解决线程更新与静态列表问题

public class JTAdapter extends RecyclerView.Adapter<JTAdapter.ViewHolder> {

    private List<AppInfo> jtList;
    private Context context;
    private String query;

    public JTAdapter(Context c, String q) {
        context = c;
        query = q;
        jtList = new ArrayList<>();
        loadAppData();
    }

    private void loadAppData() {
        new Thread(() -> {
            PackageManager pm = context.getPackageManager();
            Intent i = new Intent(Intent.ACTION_MAIN, null);
            i.addCategory(Intent.CATEGORY_LAUNCHER);
            List<ResolveInfo> allApps = pm.queryIntentActivities(i, 0);
            jtList.clear();

            if(query.length() == 0) {
                for (ResolveInfo ri : allApps) {
                    AppInfo app = new AppInfo();
                    app.label = ri.loadLabel(pm);
                    app.packageName = ri.activityInfo.packageName;
                    app.icon = ri.activityInfo.loadIcon(pm);
                    jtList.add(app);
                }
                jtList.sort(Comparator.comparing(o -> o.label.toString()));
            } else {
                String lowerQuery = query.toLowerCase();
                for (ResolveInfo ri : allApps) {
                    AppInfo app = new AppInfo();
                    app.label = ri.loadLabel(pm);
                    app.packageName = ri.activityInfo.packageName;
                    app.icon = ri.activityInfo.loadIcon(pm);
                    if(app.label.toString().toLowerCase().startsWith(lowerQuery)) {
                        jtList.add(app);
                    }
                }
                jtList.sort(Comparator.comparing(o -> o.label.toString()));
            }

            // 回到UI线程通知Adapter更新数据
            ((Activity) context).runOnUiThread(this::notifyDataSetChanged);
        }).start();
    }

    @Override
    public int getItemCount() {
        return jtList.size();
    }

    @Override
    public void onBindViewHolder(@NonNull JTAdapter.ViewHolder viewHolder, int i) {
        try {
            AppInfo app = jtList.get(i);
            viewHolder.textView.setText(app.label.toString());
            viewHolder.img.setImageDrawable(app.icon);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @NonNull
    @Override
    public JTAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        View view = inflater.inflate(R.layout.jt_item_row_layout, parent, false);
        return new ViewHolder(view);
    }

    // 新增更新查询的方法,避免频繁创建Adapter实例
    public void updateQuery(String newQuery) {
        query = newQuery;
        loadAppData();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        public TextView textView;
        public ImageView img;

        public ViewHolder(View itemView) {
            super(itemView);
            textView = itemView.findViewById(R.id.jt_app_name);
            img = itemView.findViewById(R.id.jt_app_icon);

            itemView.setOnClickListener(v -> {
                int pos = getAdapterPosition();
                if(pos != RecyclerView.NO_POSITION) {
                    Context context = v.getContext();
                    Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(jtList.get(pos).packageName.toString());
                    if(launchIntent != null) {
                        context.startActivity(launchIntent);
                    }
                }
            });
        }
    }
}

2. 修改Fragment逻辑,复用Adapter实例

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    recyclerView = view.findViewById(R.id.justtype_view);
    layoutManager = new GridLayoutManager(getContext(), 4);
    recyclerView.setLayoutManager(layoutManager);
    jt = view.findViewById(R.id.jtInput);
    jt.requestFocus();
    jt.setFocusableInTouchMode(true);
    jt.setFocusable(true);
    
    if (jt.requestFocus()) {
        InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(jt, InputMethodManager.SHOW_IMPLICIT);
    }

    Window w = requireActivity().getWindow();
    w.setStatusBarColor(ContextCompat.getColor(requireActivity(), R.color.status));
    recyclerView.setVisibility(View.INVISIBLE);
    
    // 仅初始化一次Adapter
    jtAdapter = new JTAdapter(requireContext(), jt.getText().toString());
    recyclerView.setAdapter(jtAdapter);

    new Thread(this::contactsSearch).start();

    jt.addTextChangedListener(new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {}

        @Override
        public void afterTextChanged(Editable s) {
            String query = s.toString().trim();
            if (query.length() > 0) {
                // 复用现有Adapter,更新查询条件
                jtAdapter.updateQuery(query);
                recyclerView.setVisibility(View.VISIBLE);
                textChange(view);
            } else {
                recyclerView.setVisibility(View.INVISIBLE);
            }
        }
    });
}

问题根源说明

  • 静态列表竞态:原代码中jtList为静态变量,每次新建Adapter都会覆盖列表,线程加载数据时出现数据混乱。
  • 未在UI线程更新:数据加载完成后未回到UI线程调用notifyDataSetChanged(),软键盘输入时UI未收到更新通知,不会刷新列表;关闭键盘后UI重绘,此时数据已加载完成,才显示结果。
  • 频繁创建Adapter:每次输入都新建Adapter,导致RecyclerView重复初始化,且数据加载滞后于Adapter设置,造成列表空白。

内容的提问来源于stack exchange,提问作者Andrew Hunt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 20:40:26