Android通用列表Adapter封装:ListView与RecyclerView复用实践

自打开始做Android客户端,列表控件这东西就绕不开。早年写代码最常用的就是ListView,后来Google推出了RecyclerView,大家慢慢都切了过去。但不管用哪一个,有个问题始终存在:项目里的列表页面越来越多,每个页面都重新写一套Adapter,声明ViewHolder、处理item点击、填充数据,代码大量重复。我这个封装项目就是把RecyclerView和ListView的这部分共性问题抽出来,形成一套通用的快速开发基类,让业务方不再重复造轮子。

这套封装的核心价值有几点:第一,把ViewHolder从手工书写变成泛型自动创建;第二,把多类型item的判断逻辑收敛到一处;第三,把列表点击事件和安全头尾视图(Header/Footer)的添加全部统一;第四,配合分页加载和刷新机制,实现列表页的“一套代码,多处复用”。文章会结合实际的封装思路、代码片段和踩坑记录来讲,适合对RecyclerView和ListView已经有基础使用经验、希望提升开发效率的Android开发者参考,新手也能通过这篇文章理解列表控件背后的设计思路。

1. 整体设计:从ListView迁移到RecyclerView的封装思路

1.1 为什么还要回头封装ListView

很多新项目早就用了RecyclerView,但存量老项目和新项目共存的情况在不少团队里很常见。老项目的历史包袱里,ListView高居榜首,因为早期Android开发基本离不开它,再加上部分第三方库和老业务代码都建立在ListView体系之上,短期内没法全部推翻。

而且ListView本身有个非常好的特性:addHeaderView和addFooterView是体系内建支持的,用起来特别顺手。做列表页时经常要加一个Banner、加一个加载更多的底部视图,ListView直接往头部和底部塞View就行,RecyclerView原生的Adapter里却没有这个能力,必须自己写逻辑。这就导致封装时不能只盯着一套控件,得同时处理好两套体系,让业务层尽量感知不到差异。

我的封装思路是这样:以“通用Adapter基类”为核心,ListView和RecyclerView各自实现自己的适配器子类,对外暴露一致的接口。业务方只需要继承基类,实现绑数据和创建ViewHolder的抽象方法,剩下的交给基类处理。这种做法避免了两套控件各自为政,也让后续把老页面从ListView迁到RecyclerView时,业务代码改动量降到最低。

1.2 封装前必须想清楚的三个问题

动手封装之前,有三件事必须想透,不然后面越改越乱。

第一,Adapter的生命周期归谁管。列表控件销毁时,Adapter持有的数据、监听器都要跟着释放。尤其自定义监听器里如果引用了Activity/Fragment,处理不当就是内存泄漏的隐患。

第二,多类型item的判定方式。这个决定了Adapter的扩展性。初期可能只有两三种item类型,到后期可能膨胀到七八种,判定逻辑写死在getItemViewType里就是灾难。封装时应该把“类型判定”作为子类可覆写的扩展点,并提供默认实现。

第三,list数据的增删改查入口。业务代码里最频繁的操作就是更新数据源和刷新界面,这部分接口是否统一、是否支持占位和空态,直接影响List页面开发的效率。

把这三件事定好,封装的大框架就出来了。接下来就是具体到类和方法的落地。

2. 核心封装实现:基类设计、ViewHolder与多类型Item

2.1 抽象ListView适配器:ViewHolder自动创建与绑定

ListView的经典写法里,getView方法要自己判断convertView是否为null,是则加载布局并new ViewHolder,否则复用;然后再执行bindData。每个Adapter都要重复这套模板代码。封装的目标就是消灭这套样板逻辑。

我设计了一个抽象基类CommonListAdapter<T>,核心代码如下:

public abstract class CommonListAdapter<T> extends BaseAdapter { protected List<T> mDataList; private OnItemClickListener mItemClickListener; private OnItemLongClickListener mItemLongClickListener; public CommonListAdapter(List<T> dataList) { this.mDataList = dataList == null ? new ArrayList<T>() : dataList; } @Override public int getCount() { return mDataList == null ? 0 : mDataList.size(); } @Override public T getItem(int position) { return mDataList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = createViewHolder(parent); convertView = holder.itemView; convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.position = position; bindData(holder, getItem(position), position); return convertView; } // 子类实现:创建ViewHolder,内含布局inflate protected abstract ViewHolder createViewHolder(ViewGroup parent); // 子类实现:绑定数据到ViewHolder protected abstract void bindData(ViewHolder holder, T item, int position); }

ViewHolder是一个简单的内部静态类:

public static class ViewHolder { public View itemView; public int position; private SparseArray<View> views = new SparseArray<>(); public ViewHolder(View itemView) { this.itemView = itemView; } public <V extends View> V getView(int viewId) { View view = views.get(viewId); if (view == null) { view = itemView.findViewById(viewId); views.put(viewId, view); } return (V) view; } }

这样做的好处是View查找不再反复调用findViewById,通过SparseArray缓存起来,滑动时的性能开销比原始findViewById循环低不少。把这个SparseArray缓存机制用到RecyclerView里同样成立,甚至RecyclerView官方推荐的ViewHolder写法本身就隐含了类似的意图。

2.2 RecyclerView版封装:ViewHolder范式与DiffUtil的引入

RecyclerView的Adapter强制要求使用ViewHolder,天然消灭了convertView判断,封装起来更省心。但官方写法里,createViewHolder和onBindViewHolder的套路仍然重复。基类CommonRecyclerAdapter<T>的结构就更简洁:

public abstract class CommonRecyclerAdapter<T> extends RecyclerView.Adapter<CommonRecyclerAdapter.VH> { protected List<T> mDataList; public CommonRecyclerAdapter(List<T> dataList) { this.mDataList = dataList == null ? new ArrayList<T>() : dataList; } @Override public VH onCreateViewHolder(ViewGroup parent, int viewType) { return createViewHolder(parent, viewType); } @Override public void onBindViewHolder(VH holder, int position) { holder.position = position; bindData(holder, mDataList.get(position), position); } @Override public int getItemCount() { return mDataList.size(); } public abstract VH createViewHolder(ViewGroup parent, int viewType); public abstract void bindData(VH holder, T item, int position); public static class VH extends RecyclerView.ViewHolder { public int position; public VH(View itemView) { super(itemView); } } }

这里有一处容易踩坑的地方:RecyclerView的onCreateViewHolder里传进来的viewType,默认永远是0。所以子类里如果要支持多类型item,一定要同时覆写getItemViewType。我在基类里留了默认实现,返回值恒为0,并提供了业务可覆写的钩子。为了性能,业务覆写时建议直接返回数据bean里的type字段,不要去new对象。

DiffUtil的引入是这个阶段的另一个关键点。列表页刷新数据时,旧做法是notifyDataSetChanged()一下,简单但粗暴,不仅有闪烁问题,还会丢失RecyclerView的动画效果。DiffUtil则帮你计算新旧列表的差异,只更新变化的部分。实践下来,数据量几百条时差异计算耗时可忽略,收益非常明显。

2.3 多类型Item的收敛方案:TypeKey映射模式

多类型item常见于信息流、订单列表这类页面。一条数据里有个type字段,标识它渲染成哪种视图。如果写if-else摆在Adapter里,每加一种类型就要改一遍Adapter,违背开闭原则。

我的做法是定义一个ItemViewFactory,专门负责根据item生成对应的View。Adapter里只维护一个LinkedList ,注册顺序就是优先级顺序:

public interface ItemViewFactory<T> { boolean isMatch(T item, int position); View createView(ViewGroup parent); void bindView(View view, T item, int position); }

然后在Adapter里对外暴露一个registerFactory(ItemViewFactory<T> factory)方法。业务侧用起来像这样:

mAdapter.registerFactory(new TextItemFactory()); mAdapter.registerFactory(new ImageItemFactory()); mAdapter.registerFactory(new VideoItemFactory());

新增加一种条目时,不影响已有代码,只追加工厂类。这个东西本质上是策略模式的变体,实际效果不错,尤其适合展示类条目特别多的页面。如果条目类型固定不超过三种,if-else其实也够用,不用过度设计,这点要有清醒认识。

3. 实操落地:封装基类的完整实现过程

3.1 环境选择与项目结构规划

实战中我用的是Gradle构建的Android项目,minSdkVersion 21,targetSdkVersion 33,RecyclerView版本用的AndroidX库1.2.1。这种封装类不挑版本,也不依赖特殊API,AndroidX和support库都能用,老项目迁移也友好。

项目结构分成三层:base包放通用基类,adapter包放ListView和RecyclerView的具体实现,listener包放点击监听、加载更多回调等接口。跟业务相关的工厂、Holder都放到业务模块自己的代码里,保持通用层零业务依赖。

这样的好处是后期如果要把某项能力单独做成库,直接复制base包就能用,不用连带一堆业务代码。库的边界清楚了,复用才顺理成章。

3.2 ListView封装:从BaseAdapter到ViewHolder的完整对齐

ListView场景下,我的封装的完整类图关系是:CommonListAdapter继承自BaseAdapter,内部管理数据源和监听器,对外提供数据操作入口。调用方需要覆写的只有onCreateViewHolder和onBindViewHolder两个方法。

业务层写起来是这样:

mListView.setAdapter(new CommonListAdapter<String>(dataList) { @Override protected ViewHolder onCreateViewHolder(ViewGroup parent) { View itemView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_simple_text, parent, false); return new ViewHolder(itemView); } @Override protected void onBindViewHolder(ViewHolder holder, String item, int position) { TextView tv = holder.getView(R.id.tv_text); tv.setText(item); } });

同时,列表数据变更接口统一为:

public void setDataList(List<T> newList) { mDataList.clear(); mDataList.addAll(newList); notifyDataSetChanged(); } public void addDataList(List<T> newList) { mDataList.addAll(newList); notifyDataSetChanged(); }

这里有个细节:notifyDataSetChanged()在数据变化频繁时会丢掉ListView的平滑效果,甚至触发整个列表重建。所以封装里单独提供了notifyItemInserted(int position)式的细粒度方法,把新数据批量插入的位置裸露出来,业务方可以按需调用。

3.3 RecyclerView封装:添加Header/Footer与加载更多

RecyclerView原生没有addHeaderView的能力,封装时需要在Adapter上做文章。我的做法是维护一个内部列表mHeaders和mFooters,在getItemCount里把它们的数量加进去,同时通过getItemViewType区分,避免业务数据和尾布局相互混淆。

private static final int TYPE_HEADER = Integer.MIN_VALUE; private static final int TYPE_FOOTER = Integer.MAX_VALUE; @Override public int getItemCount() { return mDataList.size() + mHeaders.size() + mFooters.size(); } @Override public int getItemViewType(int position) { if (position < mHeaders.size()) { return TYPE_HEADER + position; } if (position >= mHeaders.size() + mDataList.size()) { return TYPE_FOOTER + (position - mHeaders.size() - mDataList.size()); } return super.getItemViewType(position); }

加载更多逻辑封装成一个可插拔的OnLoadMoreListener,当列表滚动到底部、且满足“当前数据未空”和“没有正在加载”两个条件时自动触发加载,加载完成后调用loadMoreComplete()解锁下一轮加载。这块最容易踩的坑是重复回调——快速滑动到底部时会触发多次加载请求。我经验里的稳妥做法是通过一个isLoadingMore布尔位加锁,在回调里置true,加载完成后置false。

3.4 点击事件的统一分发与参数传递

列表点击是最高频的交互,如果每个页面都单独写setOnItemClickListener,代码会越来越乱。封装的点击事件统一封装成两个接口:OnItemClickListener和OnItemLongClickListener,在Adapter内部完成position映射和数据传递。

public interface OnItemClickListener { void onItemClick(int position, Object item); }

点击区域如果涉及item内部多个子View的区分,比如点赞按钮和卡片区域,可以在Holder的bind阶段单独给子View设置监听,用position去数据源拿对象。我的建议是不要试图用一个通用回调覆盖所有场景,Adapter层的职责边界是分发,不是业务处理。

4. 核心细节:参数计算、ViewHolder复用与性能调优

4.1 嵌套滑动的性能取舍

列表页里最常见的性能坑是RecyclerView嵌套RecyclerView。比如首页外层是一个纵向列表,里面内嵌一个横向滚动的RecyclerView展示推荐内容。这种嵌套如果处理不好,两个方向同时滚动会导致事件冲突、卡顿、甚至OOM。

我的封装里对嵌套场景有两个处理手段。

第一个是内层RecyclerView必须设置setNestedScrollingEnabled(false),阻止内层消费嵌套滑动事件,减少事件冲突。第二个是内层RecyclerView的LayoutManager在onMeasure里尽量使用固定高度,避免反复测量。实测下来,内层列表数据条数不多(一般二三十条)时这样处理后,滑动帧率能保持在接近满帧的水平。

4.2 LayoutManager的局部刷新生效条件

DiffUtil最大的优势是局部刷新。但很多开发者用了它后说页面没有变化,或者闪了一下。问题往往出在两个地方。

第一,DiffUtil比较的是item内容,要求bean类必须正确实现equals和hashCode,否则每一项都被判定为“内容不同”,仍然全量刷新。第二,DiffUtil只对相同position的item做差异对比,如果列表顺序变化很大,新增删除的动画就不会生效。

我在基类里对DiffUtil做了薄封装,把calculateDiff放到后台线程执行,主线程只负责notifyDataSetChanged:

DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() { // 回调实现,关键是areItemsTheSame和areContentsTheSame }); diffResult.dispatchUpdatesTo(mAdapter);

结果就是列表更新后滑动位置保持稳定、动画流畅。实测数据量5000条时,DiffUtil计算时间也就几毫秒到几十毫秒,完全可接受。

4.3 数据量大时避免anr的异步加载策略

列表初始化和分页加载的数据量一旦大起来,直接丢到主线程解析会卡界面。封装里单独提供了一套DataDispatcher的接口,专用于大数据量的异步加载回调:

public interface DataDispatcher<T> { void dispatchData(List<T> dataList, int pageIndex); }

业务侧实现时,网络请求和本地数据库查询都放到子线程执行,拿到结果后切回主线程调用setDataList。这样即使一页加载几百条数据,界面也不会掉帧。这套思路实际上是AsyncListUtil和PagedList的简化版,精度上不如它们细腻,但胜在简单直接,不引入额外依赖。

5. 常见问题与排查技巧实录

5.1 Header/Footer误触与布局错乱的修复

列表加了Header后,点击监听里的position会比业务数据的position大。很多新手在onItemClick里直接用position去数据源取数据,结果发现取错了。封装里我统一做了position偏移计算,监听器回调出去的position永远是对应业务数据的下标,Headers和Footers的点击单独走各自的监听回调,互不干扰。

另一个高频问题是Footer通过GridView或者复杂布局实现时,根布局高度算不对,导致Footer显示不全。解决办法是给Footer根View设置合适的高度,或者使用ViewGroup.LayoutParams.WRAP_CONTENT,并在onBindViewHolder阶段根据内容动态调整。

5.2 复用混乱:Item类型冲突与findViewById缓存失效

多类型复用最经典的崩溃就是ClassCastException。原因在于RecyclerView的ViewHolder缓存是按viewType区分的,如果两个类型的viewType返回值相同,就会复用错对象。排查经验是检查getItemViewType里返回的值是否出现一致,尤其当type字段是负数或常量重复时最容易出问题。修复方案是把类型标识升级为int型唯一键,或者直接使用object.hashCode()做兜底,但要注意hashCode冲突概率极低但不为零,工程上可以接受。

SparseArray缓存View的坑在于,如果自定义View里对相同的viewId重复使用(比如同一个布局里两个TextView的id一样),缓存的键就冲突。我自己就给自定义组合控件踩过这坑,解决方式是不用holder.getView(id),而是直接通过holder.itemView.findViewById(id)动态拿,这在特殊View结构里反而是最稳的。

5.3 内存泄漏高发区:监听器与Context的隐形引用

Adapter里如果用了匿名内部类持有Activity的Context,Activity退出时Adapter还没释放,就会导致内存泄漏。常见场景是Adapter内部创建了Handler或者Runnable,比如分页加载失败后自动重试。

我的规避做法:第一,通用层不直接持Context,只在onCreateViewHolder里通过LayoutInflater临时取用parent的Context;第二,所有监听器都设置成static内部类,或者用弱引用包装宿主;第三,列表销毁时主动调用destroy()释放数据源和监听器引用。这套组合拳下来,LeakCanary再没报过这个泄漏。

5.4 空布局与加载失败的UI兜底方案

列表为空时总不能白屏。封装里加入了setEmptyView(View emptyView)的能力,列表数据为空时自动把空View显示到ListView或RecyclerView的父容器里。加载失败时也有setErrorView(View errorView),点击后可以触发重新加载。这部分的实现不复杂,但要考虑布局层级,不能因为空View的添加导致原有列表位置跳动。

实际项目里我见过不少同学在Activity里写一堆if-else去控制空态和错误态的显示隐藏,一旦有多个地方要展示列表就处处重复。封装之后,这些状态切换在Adapter内部统一处理,业务侧只看数据和结果。这个体验差异,用过的人才会懂。

6. 使用明细与项目落地效果

6.1 接入步骤:从依赖到第一个页面的最小路径

第一步,在项目的build.gradle里引入RecyclerView,如果是老项目继续用ListView则不需要额外依赖。第二步,把通用基类代码复制到base目录,去掉业务相关的注释和示例。第三步,新列表页面继承CommonRecyclerAdapter或者CommonListAdapter,实现两个抽象方法。第四步,把列表控件和Adapter绑定。

完整接入一个简单列表页面的耗时大概在15分钟以内。我这里所指的15分钟是包括写布局、写bean和调试的时间,纯写Adapter代码其实五六分钟就能完成。

6.2 三个实际场景的效果数据

场景一:某订单列表页面,原先Adapter代码300多行,封装后缩到90行,其中大部分是业务赋值和点击跳转。

场景二:某信息流页面,原先有6种条目类型,改动频繁。引入工厂模式后,新增一种条目只需要新增一个工厂类,平均改动时间从1小时缩到20分钟。

场景三:某搜索历史页面,数据量不大但更新频繁。使用DiffUtil后,列表刷新不再闪白,用户反馈的视觉问题消除,前后端联调时的查询体验也更流畅。

这组数据说明,封装的收益不是单一维度的代码量减少,而是混合了维护成本、视觉体验、开发效率的综合提升。

6.3 封装之外的扩展方向

如果后续项目演进到Jetpack架构,可以考虑把这套Adapter和ViewModel、LiveData进一步结合。比如数据源来自LiveData时,让Adapter自动订阅数据变化,定义DataBinding的通用ViewHolder,这样布局和数据绑定都能在XML里完成,代码量还能再降一层。

如果数据量继续增长到万级,建议切换到Paging 3库,那套东西在分页加载和生命周期上做得更深入。我的封装可以和Paging 3共存,Adapter照样能用,DataSource变化时只需要替换数据填充的方式。

7. 写代码之外的经验

折腾这套封装前前后后也有两个多月,期间踩过不少坑,也验证了不少设计决策。有一句话想送给做同样事情的开发者:封装一定要从“能解决当前问题的程度”开始,不要一步到位。我第一版设计里想支持所有场景,结果类越来越复杂,业务方反而不敢用。后来砍掉三分之一的接口,只保留真正高频的能力,使用率反而上来了。

另一个重要心得是,工具要在代码库里“活”起来,必须有真实的业务场景来验证和打磨。只靠闭门造车的Demo,永远发现不了真实页面里的数据更新、空态展示、点击穿透这些细节问题。我现在再动工这类通用组件,一定会先找两个不同形态的业务页面作为验收标准,通过之后才会推广到全项目。

最后分享一个实际的小技巧:封装类里统一加日志输出开关。平时用BuildConfig.DEBUG控制,运行时如果列表数据与预期不符,打开日志就能看到每一条item的类型、position、是否复用、耗时多少。这个开关在排查列表问题时帮了我不少,也推荐大家加上。

相关新闻

GitHub热榜观察:AI应用落地与开发者工具新风向

GitHub热榜观察:AI应用落地与开发者工具新风向

每天上午十点左右&#xff0c;我都会习惯性打开 GitHub 的热榜页面&#xff0c;先扫一眼当天的趋势榜单。这个习惯我保持了快十年&#xff0c;早年是为了找好用的轮子&#xff0c;后来慢慢变成一种技术风向的感知方式——热榜上的项目&#xff0c;往往代表着一批开发者正在集中…

2026/10/19 20:08:44 阅读更多 →
SuperTrend+ADX双指标趋势跟随策略原理与Python实现详解

SuperTrend+ADX双指标趋势跟随策略原理与Python实现详解

做趋势交易的人一定绕不开那两个经典问题&#xff1a;趋势到底走没走出来&#xff1f;现在进场是顺势还是接飞刀&#xff1f;我做过一段时间CTA实盘&#xff0c;也把市面上的趋势指标挨个试了个遍&#xff0c;最后长期留在策略里的组合&#xff0c;就是SuperTrend配ADX。这篇文…

2026/10/19 20:08:44 阅读更多 →
YashanDB部署前检查清单:从环境准备到参数调优的完整指南

YashanDB部署前检查清单:从环境准备到参数调优的完整指南

拿到 YashanDB 安装包之后&#xff0c;别急着初始化。我见过太多次这种场景&#xff1a;环境参数没调好&#xff0c;数据库装上去了&#xff0c;跑两周业务量一大就出各种问题&#xff0c;最后排查一圈发现根子都在部署前那半天准备工作上。这篇就来聊聊 YashanDB 部署前必须确…

2026/10/19 20:07:43 阅读更多 →

最新新闻

菲涅尔衍射模型解析WiFi呼吸检测:从原理到工程实践

菲涅尔衍射模型解析WiFi呼吸检测:从原理到工程实践

1. 从光学衍射到无线感知&#xff1a;这个项目到底在做什么 菲涅尔衍射和WiFi呼吸检测&#xff0c;乍一看是两个八竿子打不着的领域。一个是光学课本里的经典波动光学内容&#xff0c;一个是近几年火起来的无线感知应用。但把这两个东西放在一起&#xff0c;恰恰说明了一个很有…

2026/10/19 20:48:59 阅读更多 →
西门子1200与FactoryIO机械手仿真:状态机实现虚拟调试全流程

西门子1200与FactoryIO机械手仿真:状态机实现虚拟调试全流程

做工业自动化调试&#xff0c;最怕设备还没到场、程序就得交付&#xff1b;最怕机械没接线、电气没上电&#xff0c;写好的逻辑只能在脑子里跑。我前阵子捣鼓的一套FactoryIO机械手仿真取料程序&#xff0c;算是把这个困局撕开了一个口子&#xff1a;FactoryIO提供虚拟车间&…

2026/10/19 20:48:59 阅读更多 →
图表设计实战指南:从认知到维护的完整方法论

图表设计实战指南:从认知到维护的完整方法论

1. 从"diagram-design"这个标题能读出什么 第一次看到"diagram-design"这个标题&#xff0c;我的直觉是&#xff1a;这大概率不是一个单纯的"画图工具推荐"或者"设计规范文档"&#xff0c;而是一个把 图表设计 这件事当成一个完整工…

2026/10/19 20:46:54 阅读更多 →
图表设计方法论:从沟通逻辑到视觉规范的完整实践指南

图表设计方法论:从沟通逻辑到视觉规范的完整实践指南

1. 图表设计&#xff1a;从“画出来”到“讲清楚”这些年我看了不少技术文档、项目方案和系统说明&#xff0c;发现一个共性问题&#xff1a;大部分人根本不把图表当“设计”来做&#xff0c;而是当“画图”来应付。打开绘图工具&#xff0c;拖几个方框&#xff0c;连几条线&am…

2026/10/19 20:43:51 阅读更多 →
Python+Vue游戏装备交易商城系统:架构设计与实战全解析

Python+Vue游戏装备交易商城系统:架构设计与实战全解析

“基于PythonVue的游戏装备交易商城系统”这个标题&#xff0c;我太熟了。这几乎是每一届想做点东西但又不想只写个管理系统的同学都会碰到的题&#xff0c;也是后台私信里被问得最多的项目类型之一。但说句实话&#xff0c;真正把“交易”两个字做明白的&#xff0c;十个里可能…

2026/10/19 20:42:50 阅读更多 →
Java授权实战:TrueLicense密钥管理与License验证全解析

Java授权实战:TrueLicense密钥管理与License验证全解析

开头&#xff1a;从一次授权失效事故说起 做Java桌面应用授权这块&#xff0c;很多团队第一反应就是找个现成的License库&#xff0c;生成个密钥文件塞进去&#xff0c;完事。我早年也这么干过&#xff0c;结果用户改了系统时间&#xff0c;软件直接罢工&#xff1b;换台机器&a…

2026/10/19 20:42:50 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介&#xff1a;本资源为电源技术方向的学术研究文档&#xff0c;聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略&#xff0c;面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址&#xff1a; https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集&#xff0c;共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →