当前位置: 首页 > news >正文

【Android Framework系列】第15章 Fragment+ViewPager与Viewpager2相关原理

1 前言

上一章节【Android Framework系列】第14章 Fragment核心原理(AndroidX版本)我们学习了Fragment的核心原理,本章节学习常用的Fragment+ViewPager以及Fragment+ViewPager2的相关使用和一些基本的源码分析。

在这里插入图片描述

2 Fragment+ViewPager

我们常用的两个PagerAdapter的实现类,也就是FragmentStatePagerAdapterFragmentPagerAdapter,今天,我们就来学习一下它们的使用方法,并进行对比。

2.1 FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别

1. fragments对象的处理:
FragmentPagerAdapter:范围外fragments会保存在内存中(detach),但是fragment对应的View会被销毁
FragmentStatePagerAdapter:范围外fragments不会保存在内存中(remove),View也会被销毁。
2. 状态的处理:
FragmentPagerAdapter:范围外fragments对应的SavedState会保存
FragmentStatePagerAdapter:只保存范围内fragments对应的SavedState。这个SavedStateFragment的生命周期回调中供外部传参数,和Activity类似。
3. 适用场景:相同数量的fragmentsFragmentPagerAdapter内存较大,但页面切换更友好;FragmentStatePagerAdapter内存占用少,页面切换稍差。

因此FragmentPagerAdapter适用于Fragment数量少的情况,FragmentStatePagerAdapter适用于Fragment数量多的情况。

我们首先来看下FragmentPagerAdapter

	@Overridepublic Object instantiateItem(ViewGroup container, int position) {if (mCurTransaction == null) {mCurTransaction = mFragmentManager.beginTransaction();}final long itemId = getItemId(position);// Do we already have this fragment?//判断请求的Fragment是否已经被生成过String name = makeFragmentName(container.getId(), itemId);Fragment fragment = mFragmentManager.findFragmentByTag(name);if (fragment != null) {if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);// 当前缓存有则直接使用mCurTransaction.attach(fragment);} else {fragment = getItem(position); //调用这个方法来生成新的Fragmentif (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);// 将新生成的Fragment存储起来,以便以后再次用到时,直接attach()mCurTransaction.add(container.getId(), fragment,makeFragmentName(container.getId(), itemId)); }if (fragment != mCurrentPrimaryItem) {fragment.setMenuVisibility(false);if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);} else {fragment.setUserVisibleHint(false);}}return fragment;}@Overridepublic void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {Fragment fragment = (Fragment) object;if (mCurTransaction == null) {mCurTransaction = mFragmentManager.beginTransaction();}if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object+ " v=" + fragment.getView());mCurTransaction.detach(fragment);if (fragment.equals(mCurrentPrimaryItem)) {mCurrentPrimaryItem = null;}}

FragmentPagerAdapterdestroyItem方法中调用了detach()只是改变Fragment状态,说明只有消除整个adapter时候,才能将生成的Fragment都消除掉,不然就会直接在内存中。

接下来我们对比FragmentStatePagerAdapter

  @Overridepublic Object instantiateItem(@NonNull ViewGroup container, int position) {// If we already have this item instantiated, there is nothing// to do.  This can happen when we are restoring the entire pager// from its saved state, where the fragment manager has already// taken care of restoring the fragments we previously had instantiated.// mFragments中对应位置有Fragment的情况下直接返回if (mFragments.size() > position) {Fragment f = mFragments.get(position);if (f != null) {return f;}}if (mCurTransaction == null) {mCurTransaction = mFragmentManager.beginTransaction();}Fragment fragment = getItem(position);if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);if (mSavedState.size() > position) {Fragment.SavedState fss = mSavedState.get(position);if (fss != null) {fragment.setInitialSavedState(fss);}}while (mFragments.size() <= position) {mFragments.add(null);}fragment.setMenuVisibility(false);if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {fragment.setUserVisibleHint(false);}mFragments.set(position, fragment);mCurTransaction.add(container.getId(), fragment);if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);}return fragment;}@Overridepublic void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {Fragment fragment = (Fragment) object;if (mCurTransaction == null) {mCurTransaction = mFragmentManager.beginTransaction();}if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object+ " v=" + ((Fragment)object).getView());while (mSavedState.size() <= position) {mSavedState.add(null);}mSavedState.set(position, fragment.isAdded()? mFragmentManager.saveFragmentInstanceState(fragment) : null);mFragments.set(position, null);// 缓存中移除fragment,下次使用得重新创建mCurTransaction.remove(fragment);if (fragment.equals(mCurrentPrimaryItem)) {mCurrentPrimaryItem = null;}}

FragmentStatePagerAdapterdestroyItem方法调用的时候把Fragment移除了,因此下次使用需要重新创建Fragment

3 Fragment+ViewPager2

ViewPager2Android Jetpack库中的一个组件,是用于在应用程序中实现页面切换和滑动效果的容器。其实ViewPager2本身继承自RecyclerView。可以复习下我们的【Android Framework系列】第12章 RecycleView相关原理及四级缓存策略分析

3.1 ViewPager2的作用和用途

3.1.1 ViewPager2使用场景

是一个功能强大的滑动容器,可以应用于多种场景中,提供了灵活的页面切换和布局定制功能,使得应用程序界面更加丰富和交互性强,可以用于以下场景:

  1. 实现引导页或欢迎页
    ViewPager2可以用于创建引导页或欢迎页,让用户通过滑动浏览介绍应用程序功能或展示欢迎内容。

  2. 创建图片浏览器
    ViewPager2可以用于创建图片浏览器,允许用户通过滑动来切换不同的图片,并支持缩放和手势交互。

  3. 构建轮播图
    ViewPager2非常适合构建轮播图功能,可以通过适配器动态加载不同的轮播项,并提供自动循环滚动的功能。

  4. 实现选项卡式布局
    结合TabLayoutViewPager2可以用于创建选项卡式布局,让用户通过滑动选项卡来切换不同的内容页面。

  5. 创建垂直滑动页面
    ViewPager不同,ViewPager2支持垂直方向的滑动,因此可以用于创建垂直滑动的页面布局,例如垂直滑动的导航菜单或垂直的新闻列表。

  6. 实现分页数据展示
    ViewPager2可以用于展示分页数据,例如将大量数据按页加载并在每一页中展示一部分内容。

  7. 嵌套滑动布局
    ViewPager2可以与其他滑动组件(如RecyclerView)嵌套使用,实现复杂的滑动布局结构。

  8. 实现自定义的滑动效果
    通过使用自定义的转换器(Transformer),可以实现各种炫酷的页面切换效果,例如渐变、缩放、旋转等。

3.1.2 ViewPager2相较于ViewPager的改进和优势

ViewPager2是对ViewPager的改进版本,提供了更好的性能、更灵活的适配器和更丰富的功能。它是构建滑动页面布局的首选组件,可以在应用程序中实现各种滑动页面的需求,并提供更好的用户体验,大致有以下几点改进和优势:

  1. 支持垂直滑动
    ViewPager2是在ViewPager的基础上进行改进的,最显著的改进之一是支持垂直滑动。而在ViewPager中,只支持水平滑动。这使得ViewPager2在创建垂直布局或特定场景下的垂直滑动功能更加方便和灵活。

  2. 更好的性能和稳定性
    ViewPager2内部实现使用了RecyclerView作为容器,而不再依赖于ViewPager的实现方式。这使得ViewPager2具有RecyclerView的优势,例如更好的性能和内存管理更流畅的滑动体验及更好的布局回收和复用机制。同时,ViewPager2还解决了ViewPager一些已知的问题和不稳定性,如条目位置错乱、刷新数据的不及时等。

  3. 支持使用Fragment作为页面
    ViewPager不同,ViewPager2直接支持使用Fragment作为页面,而无需通过FragmentPagerAdapterFragmentStatePagerAdapter进行适配。这简化了页面管理和生命周期处理,并提供了更直观和一致的使用体验。

  4. 更灵活的适配器
    ViewPager2引入了新的适配器接口,即RecyclerView.Adapter的子类RecyclerView.Adapter。这使得适配器的创建和管理更加灵活,同时提供了更多的功能和扩展性。

  5. 更丰富的功能和接口
    ViewPager2提供了许多新的功能和接口,例如支持页面预加载、更强大的页面切换动画支持、更丰富的回调接口等。这些功能和接口使得开发者能够更好地控制和定制ViewPager2的行为和外观。

3.2 FragmentStateAdapter

上面我们了解了ViewPager2对比ViewPager的一些区别和优化点,下面我们继续看一下ViewPager2对应的Adapter
我们知道ViewPager2继承自RecyclerView,那么它所对应的FragmentStateAdapter必定继承自RecyclerView.Adapter,这点小伙伴们应该能理解。那么我们在RecyclerView中的每个Item加入Fragment作为容器展示。
RecyclerView.Adapter关注的是ViewHolder的复用,但是在FragmentStateAdapter中的Framgent是不会复用的,即有多少个item就应该创建多少个Fragment,那么这其中是如何转换的呢?

我们先来看看FragmentStateAdapter源码:

public abstract class FragmentStateAdapter extendsRecyclerView.Adapter<FragmentViewHolder> implements StatefulAdapter {// 通过FragmentStateAdapter声明中的泛型可以知道,// ViewPager2之所以能够在RecyclerView的基础上能对外屏蔽对ViewHolder的使用,// 其内部是借助FragmentViewHolder实现的,其内部就new了一个FrameLayout。@Overridepublic final FragmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {return FragmentViewHolder.create(parent);}@Overridepublic final void onBindViewHolder(final @NonNull FragmentViewHolder holder, int position) {final long itemId = holder.getItemId();final int viewHolderId = holder.getContainer().getId();final Long boundItemId = itemForViewHolder(viewHolderId); // item currently bound to the VHif (boundItemId != null && boundItemId != itemId) {removeFragment(boundItemId);mItemIdToViewHolder.remove(boundItemId);}mItemIdToViewHolder.put(itemId, viewHolderId); // this might overwrite an existing entry// 内部会最终回调到createFragment用来创建当前FragmentensureFragment(position);/** Special case when {@link RecyclerView} decides to keep the {@link container}* attached to the window, but not to the view hierarchy (i.e. parent is null) */final FrameLayout container = holder.getContainer();if (ViewCompat.isAttachedToWindow(container)) {if (container.getParent() != null) {throw new IllegalStateException("Design assumption violated.");}container.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {@Overridepublic void onLayoutChange(View v, int left, int top, int right, int bottom,int oldLeft, int oldTop, int oldRight, int oldBottom) {if (container.getParent() != null) {container.removeOnLayoutChangeListener(this);placeFragmentInViewHolder(holder);}}});}// 回收已经不在item集合中的Fragment,节省内存开销gcFragments();}private void ensureFragment(int position) {long itemId = getItemId(position);if (!mFragments.containsKey(itemId)) {// TODO(133419201): check if a Fragment provided here is a new FragmentFragment newFragment = createFragment(position);newFragment.setInitialSavedState(mSavedStates.get(itemId));mFragments.put(itemId, newFragment);}}void gcFragments() {if (!mHasStaleFragments || shouldDelayFragmentTransactions()) {return;}// Remove Fragments for items that are no longer part of the data-setSet<Long> toRemove = new ArraySet<>();for (int ix = 0; ix < mFragments.size(); ix++) {long itemId = mFragments.keyAt(ix);if (!containsItem(itemId)) {toRemove.add(itemId);mItemIdToViewHolder.remove(itemId); // in case they're still bound}}// Remove Fragments that are not bound anywhere -- pending a grace periodif (!mIsInGracePeriod) {mHasStaleFragments = false; // we've executed all GC checksfor (int ix = 0; ix < mFragments.size(); ix++) {long itemId = mFragments.keyAt(ix);if (!isFragmentViewBound(itemId)) {toRemove.add(itemId);}}}for (Long itemId : toRemove) {removeFragment(itemId);}}// onViewAttachToWindow的时候调用placeFragmentInViewHolder,// 将FragmentViewHolder的container与当前Fragment绑定@Overridepublic final void onViewAttachedToWindow(@NonNull final FragmentViewHolder holder) {placeFragmentInViewHolder(holder);gcFragments();}void placeFragmentInViewHolder(@NonNull final FragmentViewHolder holder) {Fragment fragment = mFragments.get(holder.getItemId());if (fragment == null) {throw new IllegalStateException("Design assumption violated.");}FrameLayout container = holder.getContainer();View view = fragment.getView();if (!fragment.isAdded() && view != null) {throw new IllegalStateException("Design assumption violated.");}// { f:added, v:notCreated, v:notAttached} -> schedule callback for when createdif (fragment.isAdded() && view == null) {scheduleViewAttach(fragment, container);return;}// { f:added, v:created, v:attached } -> check if attached to the right containerif (fragment.isAdded() && view.getParent() != null) {if (view.getParent() != container) {addViewToContainer(view, container);}return;}// { f:added, v:created, v:notAttached} -> attach view to containerif (fragment.isAdded()) {addViewToContainer(view, container);return;}// { f:notAdded, v:notCreated, v:notAttached } -> add, create, attachif (!shouldDelayFragmentTransactions()) {scheduleViewAttach(fragment, container);mFragmentManager.beginTransaction().add(fragment, "f" + holder.getItemId()).setMaxLifecycle(fragment, STARTED).commitNow();mFragmentMaxLifecycleEnforcer.updateFragmentMaxLifecycle(false);} else {if (mFragmentManager.isDestroyed()) {return; // nothing we can do}mLifecycle.addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (shouldDelayFragmentTransactions()) {return;}source.getLifecycle().removeObserver(this);if (ViewCompat.isAttachedToWindow(holder.getContainer())) {placeFragmentInViewHolder(holder);}}});}}}
public final class FragmentViewHolder extends ViewHolder {private FragmentViewHolder(@NonNull FrameLayout container) {super(container);}// FragmentViewHolder实际上就创建了一个FrameLayout@NonNull static FragmentViewHolder create(@NonNull ViewGroup parent) {FrameLayout container = new FrameLayout(parent.getContext());container.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT));container.setId(ViewCompat.generateViewId());container.setSaveEnabled(false);return new FragmentViewHolder(container);}@NonNull FrameLayout getContainer() {return (FrameLayout) itemView;}
}

通过上面源码分析可以知道,虽然Fragment没有被复用,但是通过复用了ViewHoldercontainer实现了Framgent的交替显示

4 总结

总结一下本章节的内容:

  1. Fragment+ViewPager只能横向滚动,性能相对较差。对应不同的Adapter效果不一样。
  2. Fragment+ViewPager使用FragmentPagerAdapter,范围外fragments会保存在内存中(detach),但是fragment对应的View会被销毁,fragments对应的SavedState会保存,FragmentPagerAdapter内存较大但页面切换更友好,适用于Fragment数量少的情况
  3. Fragment+ViewPager使用FragmentStatePagerAdapter,范围外fragments不会保存在内存中(remove),View也会被销毁。只保存范围内fragments对应的SavedState。这个SavedStateFragment的生命周期回调中供外部传参数,和Activity类似。内存占用少,页面切换稍差。适用于Fragment数量多的情况。
  4. Fragment+ViewPager2能横向或纵向滚动,继承自RecyclerView所以基本有其所有的优点,包括内存占用、缓存管理等。FragmentStateAdapter继承自RecyclerView.Adapter,虽然Fragment没有被复用,但是通过复用了ViewHoldercontainer实现了Framgent的交替显示。

相关文章:

【Android Framework系列】第15章 Fragment+ViewPager与Viewpager2相关原理

1 前言 上一章节【Android Framework系列】第14章 Fragment核心原理(AndroidX版本&#xff09;我们学习了Fragment的核心原理&#xff0c;本章节学习常用的FragmentViewPager以及FragmentViewPager2的相关使用和一些基本的源码分析。 2 FragmentViewPager 我们常用的两个Page…...

typeof的作用

typeof 是 JavaScript 中的一种运算符&#xff0c;用于获取给定值的数据类型。 它的作用是返回一个字符串&#xff0c;表示目标值的数据类型。通过使用 typeof 运算符&#xff0c;我们可以在运行时确定一个值的类型&#xff0c;从而进行相应的处理或逻辑判断。 常见的数据类型…...

性能测试 —— Tomcat监控与调优:status页监控

Tomcat服务器是一个免费的开放源代码的Web 应用服务器&#xff0c;Tomcat是Apache 软件基金会(Apache Software Foundation)Jakarta 项目中的一个核心项目&#xff0c;由Apache、Sun 和其他一些公司及个人共同开发而成。 Tomcat是一个轻量级应用服务器&#xff0c;在中小型系统…...

Ubuntu 安装 CUDA 与 CUDNN GPU加速引擎

一、NVIDIA&#xff08;英伟达&#xff09;显卡驱动安装 NVIDIA显卡驱动可以通过指令sudo apt purge nvidia*删除以前安装的NVIDIA驱动版本&#xff0c;重新安装。 1.1. 关闭系统自带驱动nouveau 注意&#xff01;在安装NVIDIA驱动以前需要禁止系统自带显卡驱动nouveau&#xf…...

pdf文件太大如何处理?教你pdf压缩简单方法

PDF文件过大&#xff0c;是很多人在使用PDF文件时都遇到过的一个常见问题&#xff0c;过大的PDF文件不仅会占用大量的存储空间&#xff0c;还会影响文件传输和处理效率&#xff0c;下面给大家总结了几个方法&#xff0c;帮助大家解决PDF文件过大的问题。 方法一&#xff1a;嗨格…...

Nacos使用教程(二)——nacos注册中心(1)

文章目录 Nacos vs Eureka介绍架构设计Nacos架构Eureka架构 功能特性服务注册与发现配置管理健康检查 生态系统支持可用性与稳定性总结 Nacos中的CAP原则介绍CAP原则一致性&#xff08;Consistency&#xff09;可用性&#xff08;Availability&#xff09;分区容错性&#xff0…...

蓝桥杯2023年第十四届省赛真题-买瓜--C语言题解

目录 蓝桥杯2023年第十四届省赛真题-买瓜 题目描述 输入格式 输出格式 样例输入 样例输出 提示 【思路解析】 【代码实现】 蓝桥杯2023年第十四届省赛真题-买瓜 时间限制: 3s 内存限制: 320MB 提交: 796 解决: 69 题目描述 小蓝正在一个瓜摊上买瓜。瓜摊上共有 n 个…...

R语言进行孟德尔随机化+meta分析(1)---meta分析基础

目前不少文章用到了孟德尔随机化meta分析&#xff0c;今天咱们也来介绍一下&#xff0c;孟德尔随机化meta其实主要就是meta分析的过程&#xff0c;提取了孟德尔随机化文章的结果&#xff0c;实质上就是个meta分析&#xff0c;不过多个孟德尔随机化随机化的结果合并更加加强了结…...

网络安全第一次作业

1、什么是防火墙 防火墙是一种网络安全系统&#xff0c;它根据预先确定的安全规则监视和控制传入和传出的网络流量。其主要目的是阻止对计算机或网络的未经授权的访问&#xff0c;同时允许合法通信通过。 防火墙可以在硬件、软件或两者的组合中实现&#xff0c;并且可以配置为根…...

idea设置gradle

1、不选中 2、下面选specified location 指定gradle目录...

基于Elasticsearch的多文档检索 比如 商品(goods)、案例(cases)

概述 Elasticsearch多文档聚合检索 详细 记得把这几点描述好咯&#xff1a;需求&#xff08;要做什么&#xff09; 代码实现过程 项目文件结构截图 演示效果 应用场景 我们需要在五种不同的文档中检索数据。 比如 商品&#xff08;goods&#xff09;、案例&#xff08;ca…...

9月18日,每日信息差

今天是2023年09月19日&#xff0c;以下是为您准备的11条信息差 第一、江苏无锡首次获得6000年前古人类DNA 第二、全球天然钻石价格暴跌。数据显示&#xff0c;国际钻石交易所钻石价格指数在2022年3月达到158的历史峰值&#xff0c;之后一路下跌到目前的110左右&#xff0c;创…...

基于FPGA实现FPDLINK III

功能概述 本模块主要包含FPDLINKIII/CML收发信号与HDMI/SDI/USB信号、千兆网络信号&#xff0c;支持客户按照按照指定功能定制 当前默认功能为FPD LINK III/CML转为HDMI/SDI/UVC信号 性能参数 名称 描述 供电接口 DC12V FPD LINK RX GM8914 FPD LINK TX GM8913 千兆网…...

[补题记录] Atcoder Beginner Contest 309(E)

URL&#xff1a;https://atcoder.jp/contests/abc309 目录 E Problem/题意 Thought/思路 解法一&#xff1a; 解法二&#xff1a; Code/代码 E Problem/题意 一个家庭有 N 个人&#xff0c;根节点为 1&#xff0c;给出 2 ~ N 的父节点。一共购买 M 次保险&#xff0c;每…...

【HarmonyOS】解决API6 WebView跳转外部浏览器问题、本地模拟器启动黑屏

【问题描述1】 HarmonyOS API6 Java开发中使用WebView组件&#xff0c;如果网页中有跳转链接&#xff0c;点击会跳转到手机系统浏览器。 【解决方案】 解决这个问题的方法就是给WebView这种自定义的WebAgent对象。具体代码如下&#xff1a; WebConfig webConfigthis.webView…...

给出三个整数,判断大小

7-2 比较大小 给出三个整数&#xff0c;判断大小。 输入格式: 给出三个整数a,b,c 输出格式: 在一行中依次从小到大的顺序输出&#xff0c;两数之间有一个空格&#xff0c;无多余空格。 输入样例: 在这里给出一组输入。例如&#xff1a; 2 1 5 输出样例: 在这里给出相应的输…...

优化软件系统,解决死锁问题,提升稳定性与性能 redis排队下单

项目背景&#xff1a; 随着用户数量的不断增加&#xff0c;我们的速卖通小管家软件系统面临了一个日益严重的问题&#xff1a;在从存储区提供程序的数据读取器中进行读取时&#xff0c;频繁出现错误。系统报告了一个内部异常: 异常信息如下&#xff1a; 从存储区提供程序的数…...

MyBatisPlus 底层用 json 存储,Java 仍然使用 对象操作

PO 类的字段定义为一个对象&#xff0c;然后使用以下注解修饰 TableField(typeHandler JacksonTypeHandler.class) 当然 jsonTypeHandler 有多种可以选择...

发送验证码倒计时 防刷新重置!!!

需求&#xff1a;发送验证码&#xff0c;每60s可点击发送一次&#xff0c;倒计时中按钮不可点击&#xff0c;且刷新页面倒计时不会重置 可用以下方式避免刷新页面时&#xff0c;倒计时重置 localStorage本地缓存方式 思路&#xff1a; 1.记录倒计时的时间 2.页面加载时&…...

OpenCV项目开发实战--forEach的并行像素访问与其它方法的性能比较

在本教程中,我们将比较Mat 类的forEach方法与 OpenCV 中访问和转换像素值的其他方法的性能。我们将展示forEach如何比简单地使用at方法甚至有效地使用指针算术快得多。 OpenCV 内部有一些隐藏的宝石,有时并不为人所知。这些隐藏的宝石之一是Mat 类的forEach方法,它利用计算…...

cv::Mat 的常见操作方法

cv::Mat是OpenCV库中用于处理图像和矩阵的主要数据结构。以下是一些常见的cv::Mat操作方法&#xff1a; 创建和初始化 cv::Mat::Mat(): 创建一个空的cv::Mat对象。cv::Mat::Mat(int rows, int cols, int type): 创建一个指定行数、列数和数据类型的cv::Mat对象。cv::Mat::Mat(i…...

JVM——11.JVM小结

这篇文章我们来小结一下JVM JVM&#xff0c;即java虚拟机&#xff0c;是java代码运行时的环境。我们从底层往上层来说&#xff0c;分别是硬件部分&#xff0c;操作系统&#xff0c;JVM&#xff0c;jre&#xff0c;JDK&#xff0c;java代码。JVM是直接与操作系统打交道的。JVM也…...

月木学途开发 2.前台用户模块

概述 效果展 数据库设计 会员表 DROP TABLE IF EXISTS user_type; CREATE TABLE user_type (userTypeId int(11) NOT NULL AUTO_INCREMENT,userTypeName varchar(255) DEFAULT NULL,userTypeDesc varchar(255) DEFAULT NULL,PRIMARY KEY (userTypeId) ) ENGINEInnoDB AUTO_I…...

buuctf-ciscn_s_3

一、srop 参考文章-博客园-wudiiv11&#xff08;作者&#xff09;-BUUCTF-ciscn_2019_s_3 参考文章-博客园-z2yh&#xff08;作者&#xff09;-Srop 原理与利用方法 vlun函数中没有分配栈帧&#xff08;指rsp没有增长&#xff0c;也没有压入父函数的rbp&#xff0c;这也导致…...

3D模型格式转换工具HOOPS Exchange协助Epic Games实现CAD数据轻松导入虚幻引擎

一、面临的挑战 Epic Games最为人所知的身份可能是广受欢迎的在线视频游戏Fortnite的开发商&#xff0c;但它也是虚幻引擎背后的团队&#xff0c;虚幻引擎是一种实时3D创作工具&#xff0c;为世界领先的游戏提供动力&#xff0c;并且也被电影电视、建筑、汽车、制造、模拟等领…...

Linux- inode vnode

什么是inode inode 是 UNIX 和 UNIX-like 操作系统中的一个关键概念。它代表了文件系统中文件或目录的元数据。每个文件和目录在文件系统中都有一个与之关联的 inode。这个数据结构存储了关于文件的所有信息&#xff0c;除了其名称和实际数据之外。 以下是 inode 中通常包含的…...

不来看看?通过Python实现贪吃蛇小游戏

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Python》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这个专…...

C# linq初探 使用linq查询数组中元素

使用linq进行数组查询 输出数组中全部的偶数并升序输出结果 写法1&#xff1a; int[] numbers { 5, 10, 8, 3, 6, 12 }; //查询的数组var numqurey from num in numberswhere num % 2 0 //按照条件过滤orderby numselect num;foreach (var num in numqurey){Console.Writ…...

使用线程池进行任务处理

线程池 线程池&#xff1a;一种线程使用模式。线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分…...

ES6之Map和Set有什么不同?

一、Map 1.定义 Map是ES6提供的一种新的数据结构&#xff0c;它是键值对的集合&#xff0c;类似于对象&#xff0c;但是键的范围不限于字符串&#xff0c;各种类型的值都可以当做键。 Object结构是“字符串-值”的对应&#xff0c;Map结构则是“值-值”的对应 2.代码示例 M…...

wordpress自定义seo标题/优化大师免费下载

此代码是将前端传来的url参数进行转换&#xff0c;再以数据流的形式展示到前端 Controller RequestMapping("/tpzhurl") public class IppcTpUrlController {protected Logger log Logger.getLogger(this.getClass());RequestMapping(value "/urlZh")Tr…...

网站制作模板程序/中国法律服务网app最新下载

学习了Python的各种基础语法和常用包后&#xff0c;你是否对如何使用Python在实际工作中进行数据分析一头雾水&#xff1f;如果是&#xff0c;今天这篇文章一定能带给你一些用数据分析解决实际问题的思路。数据分析的目的决定了你的分析步骤&#xff0c;比如你的分析的目标是提…...

泸州建设网站/清理大师

1. dataType错误 我遇到的就是这个dataType错误&#xff0c;即后台返回的dataType类型与前台写的不一致&#xff0c;一般前台写json没问题&#xff0c;大部分是后台返回的类型对不上 2. async请求同步异步问题 这个没有遇见过很少碰到类似的问题 async默认是true(异步请求),如果…...

wordpress显示摘要插件/做一个网站的步骤

每日一练给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 ""给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子…...

合肥网站建设是什么意思/全媒体广告代理加盟

Shiro基础身份验证 如果要进行shiro的日志信息读取&#xff0c;那么需要使用一个org.apache.shiro.util.Factory接口&#xff0c;在这个接口里面定义有一 取得SecuruityManager接口对象的方法&#xff1a;public T getInstance()&#xff1b; Factory是接口&#xff0c;本次将通…...

技术博客wordpress主题/泰州seo网络公司

最近在使用logstash进行日志搜集&#xff0c;很方便的一个开源软件软件&#xff0c;开包即用&#xff0c;使用JRuby来开发的&#xff0c;呵呵&#xff0c;我一看到不是java开发的开源项目&#xff0c;就有一种莫名其妙的抵触情绪&#xff0c;怪哉怪哉&#xff0c;不过我去它们的…...