【Android进阶】8、单 Activity-多 Fragment 模式 与 Fragment 的管理器

news/2024/4/29 13:48:43/文章来源:https://blog.csdn.net/jiaoyangwm/article/details/126847595

文章目录

    • 8.1 UI的灵活需求
    • 8.2 Fragment
    • 8.3 Fragment实战
    • 8.4 创建数据类
    • 8.5 创建 UI fragment
      • 8.5.1 定义 CrimeFragment 布局
      • 8.5.2 创建 CrimeFragment 类
        • 8.5.2.1 实现 Fragment 的生命周期函数
        • 8.5.2.2 在 Fragment 中实例化部件
    • 8.6 让 Activity 托管 Fragment
      • 8.6.1 定义 Activity 的 FrameLayout 视图
      • 8.6.2 给 FragmentManager 添加 fragment
        • 8.6.2.1 fragment事务
        • 8.6.2.2 FragmentManager 和 Fragment 生命周期
    • 8.7 采用 Fragment 的应用架构

这次我们开发新的名为CriminalIntent的应用, 记录各种办公室陋习, 如随手将脏盘子丢在休息室水池里,或者自己打印完文件就走,全然不顾公共打印机里已缺纸,等等,效果如下:

在这里插入图片描述
其主界面是列表, 子界面可新建记录: 记录时, 可添加标题, 日期, 照片, 可在联系人中查找当事人, 发微信/短信给当事人来提出抗议, 看见陋习, 记录下来, 舒缓了心情, 就可以继续专心做手头上的工作了。

8.1 UI的灵活需求

除了前文提到的一个页面对应一个Activity之外, 我们还有更细粒度的需求

  • 假设用户正在平板设备上运行应用。平板设备屏幕较大,能够同时显示列表和记录明细, 那么UI就变化较大 在这里插入图片描述
  • 假设用户正在手机上查看记录明细信息,并想查看列表中的下一条记录信息。如果无须返回列表界面,滑动屏幕就能查看下一条记录就好了。每滑动一次屏幕,应用便自动切换到下一条记录明细。

可以看出,灵活多变的UI设计是以上假设情景的共同点。也就是说,为了适应用户或设备的需求,Activity 界面可以在运行时组装,甚至重新组装。

Activity自身并不具备这样的灵活性。activity视图可以在运行时切换,但控制视图的代码必须在activity中实现。结果,各个activity还是得和特定的用户界面紧紧绑定。

8.2 Fragment

采用fragment而不是 activity 来管理应用UI,可让应用具有前述的灵活性。

fragment是一种控制器对象,activity可委派它执行任务。这些任务通常就是管理用户界面。受管的用户界面可以是一整屏或整屏的一部分。

其中管理用户界面的fragment又称为UI fragment。它也有自己的视图(由布局文件实例化而来)。fragment视图包含了用户可以交互的可视化UI元素.

根据应用和用户的需求,可联合使用fragment及activity来组装或重组用户界面。在整个生命周期中,activity视图还是那个视图。因此不必担心会违反Android系统的activity使用规则。

下面来看看应用该如何支持在同一屏中显示列表与明细内容。我们应用的activity视图会由一个列表fragment和一个明细fragment组成。明细视图负责显示列表项的明细内容。

选择不同的列表项就显示对应的明细视图,activity负责以一个明细fragment替换另一个明细fragment,如下图所示。这样,视图切换的过程中,也不用销毁activity了。有fragment助阵,一切就这么简单。

在这里插入图片描述

8.3 Fragment实战

首先开发如下明细记录部分, MainActivity管理UI Fragment,其界面如下:

在这里插入图片描述

其文件结构如下:
在这里插入图片描述

其分层结构如下:
在这里插入图片描述

8.4 创建数据类

新建项目如下:

在这里插入图片描述
新建Crime.kt如下:

data class Crime(val id: UUID = UUID.randomUUID(),var title: String = "",var date: Date = Date(),var isSolved: Boolean = false
)

8.5 创建 UI fragment

8.5.1 定义 CrimeFragment 布局

创建 UI fragment 与创建 activity 的步骤相同:

  • 定义 UI 布局文件
  • 创建 fragment 类并设置其视图为第一步定义的布局
  • 编写代码以实例化部件
    首先在 res/values/strings.xml 中添加字符串资源
<resources><string name="app_name">CriminalIntent</string><string name="crime_title_hint">Enter a title for the crime.</string><string name="crime_title_label">Title</string><string name="crime_details_label">Details</string><string name="crime_solved_label">Solved</string>
</resources>

然后,定义UI。CrimeFragment 的视图布局包含一个垂直 LinearLayout 部件,这个部件又含有五个子部件:两个 TextView、一个 EditText、一个 Button 和一个 CheckBox。

要创建布局文件,在项目工具窗口中,右键单击res/layout文件夹,选择New → Layout resource file菜单项。命名布局文件为fragment_crime.xml,输入LinearLayout作为根元素节点,示例如下:

在这里插入图片描述
选择资源类型为Layout,Root Element 为 LinearLayout,示例如下:
在这里插入图片描述
res/layout/fragment_crime.xml 中写如下布局:

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_margin="16dp"><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/crime_title_label"/><EditTextandroid:id="@+id/crime_title"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/crime_title_hint"/><TextViewstyle="?android:listSeparatorTextViewStyle"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/crime_details_label"/><Buttonandroid:id="@+id/crime_date"android:layout_width="match_parent"android:layout_height="wrap_content"tools:text="Wed Nov 14 11:56 EST 2018"/><CheckBoxandroid:id="@+id/crime_solved"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/crime_solved_label"/>
</LinearLayout>

其布局效果如下图:
在这里插入图片描述

8.5.2 创建 CrimeFragment 类

新建 CrimeFragment 类,示例如下:
在这里插入图片描述

CrimeFragment 类需继承自 Fragment类(Android Studio 会提示两个同名的 Fragment类, 我们选择androidx.fragment.app.Fragment的JetPack库里的 Fragment,代码如下:

import androidx.fragment.app.Fragment
class CrimeFragment: Fragment() {
}

8.5.2.1 实现 Fragment 的生命周期函数

Fragment 也有声明周期,其生命周期有如下不同之处:

  • Fragment.onCreate(Bundle?)public 的,因为 Fragment 所属的 Activity 需调用它。
  • Fragment.onCreate(Bundle?) 只是配置了 Fragment,而onCreateView(LayoutInflater, ViewGroup?, Bundle?) 才创建了 Fragment(该函数会实例化 Fragment 视图的布局, 并将实例化的 View 返回给托管的 Activity)。

其生命周期函数的声明如下:

class CrimeFragment: Fragment() {private lateinit var crime: Crimeoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)crime = Crime()}// 实例化并返回视图override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {// 第一个参数是 布局资源ID// 第二个参数是 视图的父视图// 第三个参数是 是否立即将生成的视图 添加给 父视图, false表示将Fragment的视图交给Activity保管val view = inflater.inflate(R.layout.fragment_crime, container, false)return view}
}

8.5.2.2 在 Fragment 中实例化部件

为 crime_title 文本,设置按钮监听函数,代码如下:

class CrimeFragment : Fragment() {private lateinit var crime: Crimeprivate lateinit var titleField: EditTextoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)crime = Crime()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {val view = inflater.inflate(R.layout.fragment_crime, container, false)titleField = view.findViewById(R.id.crime_title)return view}override fun onStart() {super.onStart()val titleWatcher = object : TextWatcher {override fun beforeTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {// This space intentionally left blank}override fun onTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {crime.title = sequence.toString()}override fun afterTextChanged(sequence: Editable?) {// This one too}}titleField.addTextChangedListener(titleWatcher)}
}

TextWatcher 监听器是设置在 onStart() 里的。有些监听器不仅能在用户与之交互时触发,也能在因设备旋转,视图恢复后导致数据重置时触发。能响应数据输入的监听器有 EditTextTextWatcherCheckBoxOnCheckChangedListener

因为视图状态在onCreateView(…)之后和onStart()之前恢复。而视图状态一恢复,EditText的内容就要用crime.title的当前
值重置。因为视图状态恢复后才会触发监听器事件,所以应在 onStart() 里设置监听器。

接下来,设置 Button 的文本并默认禁用,代码如下:

package com.bignerdranch.android.criminalintentimport 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.widget.Button
import android.widget.EditText
import androidx.fragment.app.Fragmentclass CrimeFragment : Fragment() {private lateinit var crime: Crimeprivate lateinit var titleField: EditTextprivate lateinit var dateButton: Buttonoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)crime = Crime()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {val view = inflater.inflate(R.layout.fragment_crime, container, false)titleField = view.findViewById(R.id.crime_title)dateButton = view.findViewById(R.id.crime_date) as ButtondateButton.apply {text = crime.date.toString()isEnabled = false}return view}override fun onStart() {super.onStart()val titleWatcher = object : TextWatcher {override fun beforeTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {// This space intentionally left blank}override fun onTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {crime.title = sequence.toString()}override fun afterTextChanged(sequence: Editable?) {// This one too}}titleField.addTextChangedListener(titleWatcher)}
}

接下来,设置 CheckBox 的监听函数,代码如下:

package com.bignerdranch.android.criminalintentimport 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.widget.Button
import android.widget.CheckBox
import android.widget.EditText
import androidx.fragment.app.Fragmentclass CrimeFragment : Fragment() {private lateinit var crime: Crimeprivate lateinit var titleField: EditTextprivate lateinit var dateButton: Buttonprivate lateinit var solvedCheckBox: CheckBoxoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)crime = Crime()}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {val view = inflater.inflate(R.layout.fragment_crime, container, false)titleField = view.findViewById(R.id.crime_title) as EditTextdateButton = view.findViewById(R.id.crime_date) as ButtondateButton.apply {text = crime.date.toString()isEnabled = false}solvedCheckBox = view.findViewById(R.id.crime_solved) as CheckBoxreturn view}override fun onStart() {super.onStart()val titleWatcher = object : TextWatcher {override fun beforeTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {// This space intentionally left blank}override fun onTextChanged(sequence: CharSequence?, start: Int, count: Int, after: Int) {crime.title = sequence.toString()}override fun afterTextChanged(sequence: Editable?) {// This one too}}titleField.addTextChangedListener(titleWatcher)solvedCheckBox.apply {setOnCheckedChangeListener { _, isChecked -> crime.isSolved = isChecked }}}
}

8.6 让 Activity 托管 Fragment

为托管UI fragment,activity必须:

  • 在其布局中为 fragment 的视图安排位置
  • 管理 fragment 实例的生命周期

可以写代码把 fragment 添加给 activity。这样,你自己便能决定何时添加 fragment,以及随后可以完成何种任务。你也可以移除 fragment,用其他 fragment 代替 当前fragment,甚至重新添加已移除的 fragment。

8.6.1 定义 Activity 的 FrameLayout 视图

虽然已选择在托管 activity 的代码中添加 UI fragment,但还是要在 activity 视图层级结构中为 fragment 视图安排位置。找到并打开 MainActivity 的布局文件 res/layout/activity_main.xml,使用一个 FrameLayout 替换默认布局。布局文件如下所示:

<FrameLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/fragment_container"android:layout_width="match_parent"android:layout_height="match_parent"/>

其布局是一个 FrameLayout 占满了 整个 Activity,如下图所示:

在这里插入图片描述

当前的 activity_main.xml 布局文件仅由一个服务于单个 fragment 的容器视图组成,但托管 activity 布局本身也可以非常复杂。除自身部件外,托管 activity 布局还可定义多个容器视图。

现在运行项目,效果如下图。只能看到一个空的FrameLayout,因为 MainActivity 还没有托管任何 fragment。稍后,我们会编写代码,将 fragment 的视图放置到 FrameLayout 中。不过,首先要有一个fragment。
在这里插入图片描述

8.6.2 给 FragmentManager 添加 fragment

Activity 类中有 FragmentManager类,其具体管理的对象有 fragment队列fragment事务回退栈。它负责将 fragment 视图添加到 activity 的视图层级结构中, 其架构如下图。
在这里插入图片描述

8.6.2.1 fragment事务

获取 FragmentManager 后, 再向其中添加一个 fragment,代码示例如下:

class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container)if (currentFragment == null) {val fragment = CrimeFragment()// 创建并提交一个fragment事务supportFragmentManager.beginTransaction() // beginTransaction() 返回FragmentTransaction实例.add(R.id.fragment_container, fragment) // 添加操作.commit() // 提交事务}}
}

运行效果如下:

在这里插入图片描述

其中,fragementManager 可在事务中执行多个操作:如添加、移除、附加、分离或替换 fragement。

fragementManager 维护着 fragment 事务回退栈,当从栈中回退时,一个事务内的批量操作会打包回退,很方便控制 UI。

  • 其中 add() 函数第一个参数是资源 ID,第二个参数是新创建的 CrimeFragment
  • 资源 ID 的作用是:
    • 告诉 FragmentManager,fragment 视图该出现在 Activity视图 的什么位置。
    • 唯一标识 FragmentManager 队列中的 Fragment。

上文代码中,我们使用 R.id.fragment_container 的容器视图资源ID,向 FragmentManager 请求并获取 fragment。如果要获取的 fragment 在队列中,FragmentManager 就直接返回它。

为什么要获取的fragment可能已在队列中了呢?

  • 前面说过,设备旋转或回收内存时 Android 系统会销毁 MainActivity,而后重建时会调用 MainActivity.onCreate(Bundle?) 函数。
  • activity被销毁时,它的 FragmentManager 会将 fragment 队列保存下来。这样,activity重建时,新的FragmentManager会首先获取保存的队列,然后重建fragment队列,从而恢复到原来的状态。、
  • 当然,如果指定容器视图资源 ID 的 fragment 不存在,则 fragment 变量为空值。这时应该新建 CrimeFragment,并启动一个新的fragment事务,将新建fragment添加到队列中。

8.6.2.2 FragmentManager 和 Fragment 生命周期

Fragment 和 Activity 生命周期一一对应,都有停止、暂停、运行,如下图所示:

在这里插入图片描述
因为 fragment 代表 activity 工作,所以它的状态要能反映 activity 状态。因此,需要对应的生命周期函数处理 activity 的工作。

activity的生命周期函数由操作系统负责调用,而fragment的生命周期函数由托管activity的FragmentManager负责调用。

对于 activity 用来管理事务的 fragment,操作系统概不知情。添加 fragmentFragmentManager 管理时,onAttach(Context?)、onCreate(Bundle?)和onCreateView(...)函数会被调用。

托管 activity 的 onCreate(Bundle?) 函数执行后,onActivityCreated(Bundle?) 函数也会被调用。因为是在 MainActivity.onCreate(Bundle?) 函数中添加 CrimeFragment,所以fragment被添加后,该函数会被调用。

在activity处于运行状态时,添加fragment会发生什么呢?这种情况下,FragmentManager 会立即驱赶 fragment,调用一系列必要的生命周期函数,快速跟上 activity 的步伐(与activity的最新状态保持同步)。

例如,向处于运行状态的 activity 中添加 fragment时,以下 fragment 生命周期函数会被依次调用:onAttach(Context?)、onCreate(Bundle?)、onCreateView(…)、onViewCreated(…)、onActivityCreated(Bundle?)、onStart() 以及 onResume()。

一旦追上,托管 activity 的 FragmentManager 就会边接收操作系统的调用指令,边调用其他生命周期函数,让 fragment 与 activity 保持步调一致。

8.7 采用 Fragment 的应用架构

使用 Fragment的本意是封装关键部件以方便复用。这里所说的关键部件,是针对应用的整个屏幕来讲的。

Fragment 虽好用,但不能滥用。如果有很多零碎小部件要复用,比较好的架构设计是使用定制视图(使用View子类)。

最佳实践是,应用单屏最多2~3个 Fragment,如下图就只用了2个Fragment:

在这里插入图片描述
假如只需开发一个小应用,简单起见,就不用fragment了。

然而,对于稍复杂些的应用,肯定要用fragment。这样既方便应用的未来扩展,也能让你获得足够多的开发体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_9327.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux网络编程基础<多进程并发服务器>

一、应用场景 最简单的socket示列代码只能一个客户端连接一个服务器&#xff0c;并不支持多个客户端对服务器的连接&#xff0c;为了能让多个客户端进行连接所以需要多进程或者多线程处理 二、思路解析 服务器端的程序是俩个套接字socket创建一个lfd&#xff0c;accept创建一…

外置编码矩阵神经网络all you need

🍿*★,*:.☆欢迎您/$:*.★* 🍿 目录 背景 正文 总结 背景描述

数据结构刷题:第十三天

目录 一&#xff0c;二叉搜索树中的搜索 1&#xff0c;递归 复杂度分析 2&#xff0c;迭代 复杂度分析 二&#xff0c;二叉搜索书中的插入操作 1&#xff0c;模拟 思路与算法 复杂度分析 一&#xff0c;二叉搜索树中的搜索 700. 二叉搜索树中的搜索 - 力扣&#xff08;L…

阿里P8大佬,整理的从零构建企业级容器集群实战笔记,真涨薪神器

前言 微服务架构时代对我们的基础设施管理提出了非常大的挑战&#xff0c;DevOps和持续交付成为了基本能力要求。没有近两年容器技术的快速发展&#xff0c;这些能力可能仍然只属于少数技术实力强大的互联网公司。容器技术的应用从真正意义上催化了我们在基础设施管理上的革命…

最小系统板 STM32入门,呼吸灯实现(STM32F103C6T6)

Hi, I’m Shendi 接着前一篇 https://blog.csdn.net/qq_41806966/article/details/126894938 这一次使用库来进行 LED 灯的开关&#xff0c;及延时的实现 呼吸灯实现 之前使用直接修改地址的方式实现点灯&#xff0c;这次用 GPIO 实现点灯&#xff0c;并加上延迟&#xff0…

傅立叶及其python应用

前言 本文是傅立叶及其python应用系列的第三篇文章对应的仓库地址为https://github.com/yuanzhoulvpi2017/tiny_python/tree/main/Fourier_Series 介绍 第二篇主要介绍了傅立叶的核心&#xff1a;“傅里叶级数就是函数在某个函数空间中各个基底的投影和“&#xff0c;然后基…

Day27、使用DQL命令查询数据

1、DQL语言 1.1、DQL(Data Query Language&#xff0c;数据查询语言) 1&#xff09;查询数据库数据&#xff0c;如SELECT语句 2&#xff09;简单的单表查询或多表的复杂查询和嵌套查询 3&#xff09;数据库语言中最核心、最重要的语句 4&#xff09;使用频率最高的语句 1.2、SE…

Linux小白学习

Linux学习 虚拟机 安装Linux镜像下载简单命令含义 一、虚拟机安装 参考视频&#xff1a;https://www.bilibili.com/video/BV1dS4y1e7rH?share_sourcecopy_web&vd_source0d57c2e2317ebb16893c37677d1b8931 二、Linux镜像下载 网盘下载地址&#xff1a; 链接&#xff1a;h…

如何设计一个可扩展的登录功能

本文主要分享了如何设计一个可扩展的登录功能。 一、多种登录方式&#xff08;需要有一个唯一值来绑定各种登录方式&#xff0c;目前业界用的比较多的是手机号&#xff09; 1.用户名密码登录 最原始的登录方式&#xff0c;这种登录方式与注册功能是分开的&#xff0c;业界慢慢…

网课查题公众号搭建教程(内附接口、源码)

网课查题公众号搭建教程(内附接口、源码) 本平台优点&#xff1a;免费查题接口搭建 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a;题库后台http://daili.j…

Windows11+Ubuntu 3系统如何安全地删掉最后一个Ubuntu系统?

文章目录Windows11Ubuntu 3系统如何安全地删掉最后一个Ubuntu系统&#xff1f;3系统是什么&#xff1f;第一步&#xff1a;删掉Ub16第二步&#xff1a;重启进入grub命令行第三步&#xff1a;从grub命令行中手动启动ubuntu20第四步&#xff1a;进入Windows11更新开机启动项grub配…

LeetCode 0304. 二维区域和检索 - 矩阵不可变

【LetMeFly】304.二维区域和检索 - 矩阵不可变 力扣题目链接&#xff1a;https://leetcode.cn/problems/range-sum-query-2d-immutable/ 给定一个二维矩阵 matrix&#xff0c;以下类型的多个请求&#xff1a; 计算其子矩形范围内元素的总和&#xff0c;该子矩阵的 左上角 为…

3、Android 活动Activity(4)(为活动补充附加信息)

在意图之外给活动添加额外的信息&#xff0c; 首先可以把字符串参数放到字符串资源文件中&#xff0c;待App运行之时再从资源文件读取字符串值&#xff1b; 接着还能在AndroidManifest.xml中给指定活动配置专门的元数据&#xff0c;App运行时即可获取对应活动的元数据信息&…

C#使用winform做一个开关小游戏

成品展示 游戏原理&#xff1a; 游戏时&#xff0c;任意点击一个格子&#xff0c;其自身状态改变&#xff0c;且上下左右四个格子的状态也进行变化&#xff0c;即&#xff1a;原来是开的变成关的&#xff0c;原来是关的变成开的。 制作过程 1.建项目会的吧。 2.设置游戏窗…

TCP重传,滑动窗口,流量控制,拥塞控制

重传机制 超时重传快速重传SACKD-SACK 超时重传 RTT 就是 数据从网络一端传送到另一端所需要的时间&#xff0c;也就是包的往返时间。 超时重传时间以 RTO 表示&#xff0c;应该略大于RTT。 如果超时重发的数据&#xff0c;再次超时时有需要重传&#xff0c;TCP的策略是超…

[需求管理-2]:什么是需求以及需求的收集与识别

目录 第1章 什么是需求识别 第2章 需求的来源 2.1 外部需求&#xff08;收集&#xff09; 2.2 内部需求&#xff08;开发&#xff09; 第3章 需求的层次 第4章 需求的形式 4.1 提问题&#xff08;针对业务层次需求、原始性需求&#xff09;&#xff1a;第一性原理 4.2 …

视觉SLAM十四讲_4李群与李代数

本文为b站视频的一个笔记 在SLAM中&#xff0c;我们经常要解下面一个问题 FminJ(T)Σi1N∣∣zi−Tpi∣∣2F minJ(T) \Sigma_{i1}^N||z_i - Tp_i||^2FminJ(T)Σi1N​∣∣zi​−Tpi​∣∣2 这个问题中, T是位姿变量。对于求最小值问题&#xff0c;我们第一步就要求函数对于变量…

Java小白踩坑录上

文章目录1、Java小白踩坑录 - String和char2、Java小白踩坑录 - Random 揭秘3、Java小白踩坑录 - B计划之Java资源如何释放&#xff1f;4、Java小白踩坑录 - 反射到底有多慢&#xff1f;5、Java小白踩坑录 - 数组 & List6、Java小白踩坑录 - Java类型的七十二变揭秘7、Java…

IDEA生成带参数和返回值注解

文章目录步骤说明打开IDEA进入 - 设置 - 编辑器 - 活动模板现象一&#xff1a;IDEA提示悬空的注解现象二&#xff1a;IDEA提示标签说明已丢失使用范围设置注解使用步骤说明 打开IDEA进入点击左上角 - 文件 - 设置 - 编辑器 - 活动模板 新建活动模板 填写模板文本 编辑变量 …

2.canal服务器配置及java客户端

【README】 1.本文总结自 B站《尚硅谷-canal》&#xff1b; 2.canal 介绍&#xff0c;可以参考 GitHub - alibaba/canal: 阿里巴巴 MySQL binlog 增量订阅&消费组件 3. canal服务器配置包括 mysql配置&#xff0c;canal配置等&#xff1b; 4.mysql服务器&#xff0c;ca…