Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $YECBGYFECGEAFWHA as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2

Deprecated: imwpcache\f884414bce24ee67f\f73723ec7b1919fa5::__construct(): Implicitly marking parameter $BBWFDDBHHYHDXXAB as nullable is deprecated, the explicit nullable type must be used instead in /www/wwwroot/www.chuangxiangniao.com/wp-content/plugins/imwpcache-dist/build/f884414bce24ee67ff73723ec7b1919fa5.php on line 2
高效更新RecyclerView:解决软键盘输入时列表不刷新的问题_创想鸟

高效更新RecyclerView:解决软键盘输入时列表不刷新的问题

高效更新RecyclerView:解决软键盘输入时列表不刷新的问题

本文旨在解决Android应用中RecyclerView在软键盘输入时无法实时更新的问题。通过分析现有代码中数据加载与UI更新的异步冲突,我们将介绍如何利用Android的Filterable接口和Filter机制,实现高效、实时的列表过滤与UI刷新,确保用户在输入过程中能即时看到搜索结果,提升用户体验。

问题背景与分析

在android应用开发中,当用户需要搜索或筛选列表数据时,通常会结合edittext和recyclerview来实现。一个常见的问题是,当用户使用软键盘输入时,recyclerview无法实时更新搜索结果,但在软键盘关闭后或使用物理键盘时却能正常工作。

现有代码中的问题根源在于数据加载和UI更新的异步处理方式。在原始实现中:

TextWatcher的afterTextChanged方法中,每次文本变化都会创建一个新的JTAdapter实例。JTAdapter的构造函数内部启动了一个新的线程来查询和过滤应用列表。这是一个耗时操作。在创建新JTAdapter后,立即调用recyclerView.setAdapter(jtAdapter)和jtAdapter.notifyDataSetChanged()。

由于应用列表的查询和过滤是在后台线程中异步进行的,当setAdapter和notifyDataSetChanged被调用时,新创建的jtAdapter内部的jtList可能尚未被后台线程填充完毕。这导致RecyclerView显示的是一个空列表或旧数据。当软键盘关闭时,可能由于某些系统事件(如布局重绘)或后台线程最终完成数据加载,UI才得以更新。而使用物理键盘时,由于输入速度可能更快,或者事件处理机制不同,可能不会出现相同的延迟感知。

解决方案:利用Filterable接口实现高效过滤

为了解决上述问题,Android提供了一个标准的Filterable接口,结合Filter类,可以优雅地处理列表数据的过滤和UI更新。这种方法的核心思想是:

Adapter维护一个完整的原始数据集。当需要过滤时,Filter的performFiltering方法在后台线程执行过滤逻辑。过滤完成后,Filter的publishResults方法在UI线程更新Adapter的当前数据集并通知RecyclerView刷新。

1. 修改Adapter实现Filterable接口

首先,我们需要修改JTAdapter类,使其实现Filterable接口。这将要求我们实现getFilter()方法。

import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.graphics.drawable.Drawable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.Filter;import android.widget.Filterable;import android.widget.ImageView;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.Comparator;import java.util.List;import java.util.Locale;public class JTAdapter extends RecyclerView.Adapter implements Filterable {    private List jtList; // 当前显示的数据列表    private List jtListAll; // 完整的原始数据列表    private Context context;    public JTAdapter(Context c) {        this.context = c;        this.jtList = new ArrayList();        this.jtListAll = new ArrayList();        // 初始加载所有应用,并在后台线程处理        loadAllAppsAsync();    }    // 异步加载所有应用    private void loadAllAppsAsync() {        new Thread(() -> {            PackageManager pm = context.getPackageManager();            Intent i = new Intent(Intent.ACTION_MAIN, null);            i.addCategory(Intent.CATEGORY_LAUNCHER);            List allApps = pm.queryIntentActivities(i, 0);            List tempAllApps = new ArrayList();            for (ResolveInfo ri : allApps) {                AppInfo app = new AppInfo();                app.label = ri.loadLabel(pm);                app.packageName = ri.activityInfo.packageName;                app.icon = ri.activityInfo.loadIcon(pm);                tempAllApps.add(app);            }            // 排序            Collections.sort(tempAllApps, Comparator.comparing(o -> o.label.toString()));            // 更新原始列表和当前列表,并在UI线程通知刷新            ((android.app.Activity) context).runOnUiThread(() -> {                jtListAll.clear();                jtListAll.addAll(tempAllApps);                jtList.clear();                jtList.addAll(tempAllApps); // 初始显示所有应用                notifyDataSetChanged();            });        }).start();    }    @Override    public int getItemCount() {        return jtList.size();    }    @Override    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    @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);    }    @Override    public Filter getFilter() {        return new Filter() {            @Override            protected FilterResults performFiltering(CharSequence charSequence) {                String charString = charSequence.toString().toLowerCase(Locale.getDefault());                List filteredList = new ArrayList();                if (charString.isEmpty()) {                    filteredList.addAll(jtListAll); // 如果搜索框为空,显示所有应用                } else {                    for (AppInfo app : jtListAll) {                        if (app != null && app.label.toString().toLowerCase(Locale.getDefault()).startsWith(charString)) {                            filteredList.add(app);                        }                    }                }                // 过滤结果排序                Collections.sort(filteredList, Comparator.comparing(o -> o.label.toString()));                FilterResults filterResults = new FilterResults();                filterResults.values = filteredList;                return filterResults;            }            @Override            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {                jtList.clear();                jtList.addAll((Collection) filterResults.values);                notifyDataSetChanged(); // 在UI线程通知数据已更新            }        };    }    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);                    }                }            });        }    }    // 假设AppInfo类定义如下    public static class AppInfo {        public CharSequence label;        public CharSequence packageName;        public Drawable icon;    }}

关键改动点:

jtList和jtListAll: jtList用于存储当前RecyclerView显示的数据,jtListAll存储所有应用的完整列表。构造函数: 接收Context,并调用loadAllAppsAsync()在后台线程异步加载所有应用到jtListAll和jtList,并在加载完成后在UI线程调用notifyDataSetChanged()。getFilter()方法: 返回一个Filter实例。performFiltering(CharSequence charSequence):这个方法在后台线程执行。它根据charSequence(用户输入)从jtListAll中过滤数据,并将过滤后的结果封装在FilterResults中返回。publishResults(CharSequence charSequence, FilterResults filterResults):这个方法在UI线程执行。它接收performFiltering返回的FilterResults,清空jtList,添加新的过滤结果,然后调用notifyDataSetChanged()通知RecyclerView刷新。

2. 修改Fragment中的TextWatcher

接下来,我们需要修改Fragment中的TextWatcher,使其在文本变化后调用Adapter的filter.filter()方法,而不是重新创建Adapter。

import android.content.Context;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.text.Editable;import android.text.TextWatcher;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.inputmethod.InputMethodManager;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.annotation.Nullable;import androidx.core.content.ContextCompat;import androidx.fragment.app.Fragment;import androidx.recyclerview.widget.GridLayoutManager;import androidx.recyclerview.widget.RecyclerView;import java.util.ArrayList;import java.util.Comparator;import java.util.List;public class MySearchFragment extends Fragment { // 假设Fragment名为MySearchFragment    private RecyclerView recyclerView;    private GridLayoutManager layoutManager;    private EditText jt;    private JTAdapter jtAdapter; // 声明为成员变量    @Nullable    @Override    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        return inflater.inflate(R.layout.fragment_my_search, container, false); // 假设布局文件名为fragment_my_search    }    @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);            if (imm != null) {                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());        recyclerView.setAdapter(jtAdapter);        // 初始加载完成后,显示RecyclerView        // jtAdapter的构造函数中会调用notifyDataSetChanged,此时可以根据jtList是否为空决定显示或隐藏        // 或者在jtAdapter的loadAllAppsAsync()完成回调中设置setVisibility        // 这里简化处理,假设初始加载后会显示        recyclerView.setVisibility(View.VISIBLE);        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) {                // 当文本变化时,调用Adapter的filter方法进行过滤                jtAdapter.getFilter().filter(s.toString());                // 根据搜索结果决定RecyclerView的可见性                if (s.length() > 0) {                    recyclerView.setVisibility(View.VISIBLE);                } else {                    // 如果搜索框为空,Filter会显示所有应用,所以也应该可见                    recyclerView.setVisibility(View.VISIBLE);                }                // textChange(view); // 如果有其他UI更新逻辑,可以在这里调用            }        });    }}

关键改动点:

jtAdapter作为成员变量: 确保JTAdapter只被创建一次。TextWatcher: 在afterTextChanged方法中,不再创建新的Adapter,而是直接调用jtAdapter.getFilter().filter(s.toString())来触发过滤过程。RecyclerView可见性: 初始时可以隐藏RecyclerView,待Adapter加载完初始数据后(在loadAllAppsAsync的回调中)再设置为可见。在afterTextChanged中,根据搜索文本长度决定可见性,但由于空字符串也会显示所有应用,所以通常保持可见。

注意事项与最佳实践

UI线程安全: Filter机制已经确保performFiltering在后台线程运行,publishResults在UI线程运行,因此无需手动处理线程切换。数据完整性: 确保jtListAll(原始数据列表)在整个生命周期中保持不变,这样每次过滤都能基于完整的数据集。性能优化:避免在onBindViewHolder中执行耗时操作。对于大量数据的过滤,可以考虑引入延迟(debounce)机制,即用户停止输入一段时间后再触发过滤,以减少不必要的频繁计算。如果数据量特别大,可以考虑使用DiffUtil来优化RecyclerView的局部更新,而不是每次都调用notifyDataSetChanged()。错误处理: 在数据加载和过滤过程中,应加入适当的错误处理机制,例如网络请求失败、权限不足等。内存管理: 确保AppInfo对象和相关资源(如Drawable)在不再需要时能被正确释放,避免内存泄漏。特别是对于Drawable,如果应用图标数量很多,需要注意其内存占用。用户体验: 在数据加载或过滤时,可以显示一个加载指示器(如ProgressBar),告知用户正在进行操作,提升用户体验。

总结

通过采用Filterable接口和Filter机制,我们能够以一种更规范、高效且线程安全的方式处理RecyclerView的实时搜索和过滤功能。这种方法避免了在每次文本变化时重复创建Adapter的性能开销和潜在的UI更新问题,确保了软键盘输入时RecyclerView能够实时、流畅地更新,从而显著提升了应用的用户体验。

以上就是高效更新RecyclerView:解决软键盘输入时列表不刷新的问题的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/80698.html

赞 (0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
客户策略管理软件哪个好
上一篇 2025年11月15日 17:17:24
crm客户管理软件哪个最好
下一篇 2025年11月15日 17:17:35

相关推荐

  • 神马搜索App用户反馈处理教程_神马搜索App问题解决技巧

    首先通过App内“帮助与反馈”提交问题,其次针对负面信息访问官网进行侵权投诉,最后定期清理缓存以解决卡顿或显示异常问题。 如果您在使用神马搜索App时遇到问题或希望反馈体验,可以通过官方渠道提交信息以获得处理。以下是针对不同问题的解决步骤: 本文运行环境:iPhone 15 Pro,iOS 18 一…

    2026年9月22日
    000
  • 如何判断网络延迟(Ping值)过高是由运营商问题还是自身设备引起的?

    先重启设备并检查本地连接,若有线网络延迟降低则问题在无线信号;通过ping网关和外部DNS判断故障范围,结合tracert追踪路径,前几跳异常指向运营商问题,最后用官方测速工具验证并联系客服解决。 判断网络延迟高是运营商还是自身设备的问题,关键在于逐步隔离排查。从最接近你的设备开始测试,向外层层推进…

    2026年9月22日
    100
  • AdobeIllustrator如何导出AI生成的图片?矢量图像保存的步骤

    首先明确输出需求,再选择“文件>导出>导出为…”或“文件>存储为…”,根据用途选取合适格式如SVG、PDF或AI,确保矢量信息保留,参数设置需匹配目标平台要求。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ Adob…

    2026年9月22日
    000
  • PHP面向对象开发:解决父类构造器参数在嵌套子对象方法中丢失的问题

    在PHP面向对象编程中,我们经常会遇到类继承和对象组合的场景。一个常见的问题是,当父类构造函数接收参数并用于初始化内部的子对象时,该子对象的方法在后续调用中可能无法正确访问到这些参数,甚至显示为null。本文将深入探讨这一问题,并提供两种有效的解决方案。 引言与问题阐述 考虑一个典型的web应用架构…

    2026年9月22日
    000
  • 悟空浏览器下载速度慢怎么解决_悟空浏览器下载速度慢提升技巧

    下载慢可优化缓存、网络、后台、多线程及版本。1、清理缓存与数据;2、检查Wi-Fi并优化信号;3、关闭后台应用释放资源;4、开启多线程加速下载;5、更新浏览器至最新版本。 如果您在使用悟空浏览器下载文件时遇到速度缓慢的情况,这可能是由于网络连接不稳定、浏览器缓存堆积或后台资源被大量占用所致。优化相关…

    2026年9月22日
    600
  • 使用MockWebServer对FeignClient进行单元测试

    本文详细阐述了如何利用Spring Cloud LoadBalancer和MockWebServer对FeignClient进行高效单元测试。通过在测试配置中动态注册MockWebServer实例,并将其作为FeignClient的服务发现目标,开发者可以精确模拟后端API的行为,包括各种HTTP响…

    2026年9月22日
    000
  • Sublime快速定位MySQL死锁与阻塞问题_提高系统稳定性与并发处理能力

    Sublime快速定位MySQL死锁与阻塞问题_提高系统稳定性与并发处理能力Sublime快速定位MySQL死锁与阻塞问题_提高系统稳定性与并发处理能力Sublime快速定位MySQL死锁与阻塞问题_提高系统稳定性与并发处理能力Sublime快速定位MySQL死锁与阻塞问题_提高系统稳定性与并发处理能力

    mysql死锁和阻塞问题可通过sublime分析日志排查。1.使用关键词搜索及正则匹配快速定位死锁信息块;2.通过查找waiting状态事务并折叠无关内容聚焦阻塞链;3.结合general log与事务id查找sql执行顺序;4.利用语法高亮、列选择等功能提升日志可读性。这些方法能有效提高排查效率。…

    2026年9月22日 • 用户投稿
    100
  • win11平板模式无法自动切换怎么办_win11平板模式自动切换异常修复方法

    首先检查设备形态和设置,确保键盘分离或屏幕翻转到位,并在“平板电脑”设置中启用自动切换;若无效,重启Windows资源管理器、更新传感器驱动或重装感应式旋转锁驱动;最后通过sfc /scannow命令修复系统文件,恢复平板模式自动切换功能。 如果您发现Windows 11的平板模式无法根据设备形态自…

    2026年9月22日
    100
  • 豫事办的密码怎么改

    首先通过个人中心修改密码或使用忘记密码功能重置。记得密码时,进入豫事办APP我的→设置→修改密码,输入原密码和新密码即可;忘记密码则在登录页点击“忘记密码”,输入手机号获取验证码后设置新密码完成重置。 如果您需要更新您的豫事办账户密码以确保账户安全,可以通过应用内设置直接修改,或在忘记密码时通过身份…

    2026年9月22日
    400
  • Canva中AI生成图片如何导出?教你快速保存设计作品的方法

    答案:Canva中导出AI生成图片的操作与普通图片相同,点击右上角“分享”按钮,选择“下载”,可选PNG、JPG、PDF、SVG、MP4或GIF等格式;为保证画质,建议优先选用PNG格式,避免有损压缩,同时选择高分辨率和合适尺寸,Pro用户可进一步调整质量与透明背景设置;除下载外,还可通过分享链接、…

    2026年9月22日
    800
  • windows怎么用命令行删除顽固文件_命令行删除顽固文件的方法

    使用命令行可强制删除顽固文件,先以管理员身份运行cmd或PowerShell,通过del /f /q或Remove-Item -Force命令删除文件,若被占用则用taskkill终止进程,或进入安全模式删除,也可用rd /s /q删除整个目录。 如果您尝试删除某个文件时,发现资源管理器无法完成操作…

    2026年9月22日
    200
  • VSCode安全更新机制解析

    VSCode通过自动检查、数字签名验证和用户可控策略确保更新安全。启动时后台定期HTTPS请求检查新版本,每日一次;安装包经平台特定签名(Windows Authenticode、macOS代码签名、Linux GPG)验证完整性;用户可选自动更新、提示或关闭,企业可集中管控;微软通过安全入口响应漏…

    2026年9月22日
    100
  • Linux系统中文件属性和权限实战操作

    Linux系统中文件属性和权限实战操作Linux系统中文件属性和权限实战操作Linux系统中文件属性和权限实战操作Linux系统中文件属性和权限实战操作

    —–原本今天的文章是昨天晚上就要更新的,但是由于昨天晚上下班回到住的地方,发现停电了,所以就没写成。今天是在上一篇文章–linux系统中文件类型的基础上,继续进行深入的学习。好了,直接开干。 一、文件的操作权限: 1、在这之前我想还是很有必要介绍对文件的操作权限(…

    2026年9月22日 • 用户投稿
    000
  • PHP中为数组元素设置默认值的最佳实践:使用Null合并运算符

    本教程将介绍如何在PHP中为数组元素设置默认值,尤其当源数据可能为空或缺失时。通过利用PHP 7+提供的Null合并运算符(??),可以简洁高效地实现这一需求,避免冗长的条件判断,提高代码可读性和健壮性。 引言:处理缺失或空值时的数组赋值 在Web开发中,我们经常需要从用户请求、数据库查询或其他外部…

    2026年9月22日
    000
  • Hazelcast缓存数据未显示:排查与解决指南

    本文旨在解决在使用Spring Cache结合Hazelcast时,通过@CachePut等注解成功将数据放入缓存,但无法通过HazelcastInstance获取缓存数据的问题。文章将深入探讨可能的原因,并提供详细的配置步骤和代码示例,帮助开发者正确配置和使用Hazelcast缓存。 在使用Spr…

    2026年9月22日
    000
  • VSCode快速配置Dart:Flutter开发、中文提示、热加载

    安装vscode并下载flutter sdk,解压至无中文或特殊字符的路径;2. 将flutter sdk的bin目录添加到系统环境变量path中;3. 打开新终端执行flutter doctor,根据提示安装缺失的依赖;4. 在vscode扩展商店安装dart和flutter扩展;5. 确保在调试…

    2026年9月22日
    200
  • Inkscape如何导出AI生成的矢量图片?教你快速保存图像的步骤

    答案:在Inkscape中导出矢量图需根据用途选择格式,网页用优化SVG并转文本为路径,印刷则导出为PDF/EPS、转文字为路径、确保高分辨率位图,同时注意颜色模式与出血设置。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 在Inkscap…

    2026年9月22日
    700
  • Laravel 8 登录后重定向至仪表盘的策略与实践

    本教程详细阐述了在 Laravel 8 中实现用户登录后重定向到仪表盘的多种策略。我们将探讨如何通过配置 LoginController 的 $redirectTo 属性、利用 RouteServiceProvider 定义常量以及在自定义登录方法中进行精确控制来管理重定向流程。文章还涵盖了相关中间…

    2026年9月22日
    000
  • 如何在iPhone情侣模式中启用视频通话?快速连接彼此的设置方法

    如何在iPhone情侣模式中启用视频通话?快速连接彼此的设置方法如何在iPhone情侣模式中启用视频通话?快速连接彼此的设置方法如何在iPhone情侣模式中启用视频通话?快速连接彼此的设置方法如何在iPhone情侣模式中启用视频通话?快速连接彼此的设置方法

    iPhone虽无官方“情侣模式”,但可通过FaceTime或微信、WhatsApp等第三方应用实现高质量视频通话。首选FaceTime,操作便捷、画质清晰,支持SharePlay共享影音,仅限苹果设备;跨平台可选微信、WhatsApp等,注重隐私可用Telegram。优化体验需稳定网络、良好光线与背…

    2026年9月22日 • 用户投稿
    200
  • windows8怎么更改锁屏界面的图片_windows8修改锁屏壁纸的方法

    1、可通过“电脑设置”或“控制面板”更换Windows 8.1锁屏图片;2、在“个性化”中选择“锁屏”并浏览自定义图像完成设置。 如果您希望个性化您的Windows 8设备,更改锁屏界面的图片是一个简单而有效的方法。系统提供了多种途径来设置您喜欢的图像作为锁屏背景。 本文运行环境:Surface P…

    2026年9月22日
    000

发表回复

登录后才能评论
关注微信