一文带你精通Android中的Activity

本文将会从活动的生命周期、启动模式、Intent数据传输、最佳实践等多维度来讲解Activity,希望对你有用

生命周期

  • 深入理解活动的生命周期,可以帮助我们更加流畅地编程,并在管理系统资源方面更加游刃有余

活动状态

每个活动在生命周期中最多有运行、暂停、停止、销毁四种状态

  • 1)运行状态:当一个活动在返回栈的栈顶时,该活动就处于运行状态,如果回收处于运行状态的活动,会带来极差的用户体验
  • 2)暂停状态:当活动不再处于栈顶,但仍然可见时,则活动进入了暂停状态(并非每个活动都会占满屏幕);处于暂停状态的活动属于完全存活;只有在内存非常紧张的情况下,系统才会考虑回收该状态的活动
  • 3)停止状态:当活动不再处于栈顶,且完全不可见时,会进入停止状态;系统仍然会为该状态的活动保存相应的状态和成员变量;当其他地方需要内存时,系统可能会回收该状态的活动
  • 4)销毁状态:当活动从返回栈中移除后就变成了销毁状态,系统会最为倾向于回收处于该状态的活动,以保证系统的内存充足

生存期 & 回调方法

Activity有如下7个回调函数,覆盖活动生命周期的每个环节:

  • onCreate()在活动第一次被创建时调用,用于完成活动的初始化操作,如:布局加载、绑定事件
  • onStart():在活动由不可见变为可见时调用

  • onResume():在活动准备好和用户交互时调用,该活动会处于返回栈的栈顶,且活动处于运行状态
  • onPause()在系统准备去启动或恢复其他活动时调用,通常会在该方法中释放比较消耗CPU的资源,以及某些关键数据

  • onStop()在活动完全不可见时调用,和onPause()方法的主要区别在于:如果启动的新活动是对话框类的活动,onPause()方法会执行,而onStop()方法并不会执行
  • onDestory()在活动被销毁前调用,之后活动的状态将变为销毁状态,常用于完成内存释放等操作

  • onRestart():在活动由停止变为运行状态前调用,即让活动重新启动

以上,除了onRestart(),其他方法都是两两相对的,所以,活动可分为三种生存期:

  • 完整生存期:活动在onCreate()方法和onDestory()方法之间所经历的,即为完整的生存期
  • 可见生存期:活动在onStart()方法和onStop()方法之间所经历的,为可见生存期,即活动对用户总是可见的,即便可能无法和用户交互;可通过onStart()和onStop()方法来合理地管理对用户可见的资源以保证处于停止状态的活动不会占用过多内存
  • 前台生存期:活动在onResume()方法和onPause()方法之间所经历的,即为前台生存期 =》活动总是处于运行状态,活动可以和用户交互

启动模式(launchMode)

  • Activity由任务(Task)栈管理,一个任务就是一组存放在栈中活动的集合,该栈也被称为返回栈(Back Stack)
  • 默认情况下,每当启动一个新的Activity,该Activity就会被加入到返回栈中,并处于栈顶的位置;当按下Back键或调用finish()方法区销毁活动时,处于栈顶的Activity机会出栈(系统总是会显示栈顶的Activity给用户)
  • 启动模式一共有4种,分别为standard、singleTop、singleTask和singleInstance,可在AndroidManifest.xml中通过给标签指定android:launchMode属性来指定启动模式

1)standard(标准模式)

  • standard是默认的启动模式,即标准模式,在不显示指定启动模式的情况下,所有的活动都默认使用该启动模式;每启动一个Activity,都会创建一个新的实例
  • 如果目标活动FirstActivity已经在栈顶,再次启动活动,还会再创建一个新的活动实例并压入栈中
  • 应用场景:适用于不希望保留状态或者每次启动都需要创建新实例的场景,例如,一个浏览器的多个页面,每次打开新的页面都会创建一个新的实例
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.myapplication1.R;
import com.example.myapplication1.intent.SecondActivity;

public class OneActivity extends AppCompatActivity {

    private Button oneBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);

        oneBtn = findViewById(R.id.oneBtn);
        oneBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(OneActivity.this, OneActivity.class));   // 验证standard和singleTop启动模式
                // startActivity(new Intent(OneActivity.this, SecondActivity.class));
            }
        });
    }
}
  • 修改AndroidManifest.xml,添加launchMode属性:
        <activity
            android:name=".launch.OneActivity"
            android:exported="true"
            android:launchMode="standard" />
  • xml布局:
    <Button
        android:id="@+id/oneBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="this is OneActivity"
        android:gravity="center"
        android:textAllCaps="false"/>
  • 在OneActivity上启动OneActivity显得有些奇怪,这里只是为便于我们理解、验证,一般不会这么写

  • 多次点击按钮,从logcat过滤出的日志可看出,每次点击按钮都会创建一个新的Activity入栈,同时,要多次点击返回键才能退出程序

  • 触发点击事件后,从OneActivity跳转到TwoActivity时,修改代码:

startActivity(new Intent(OneActivity.this, SecondActivity.class));

输出结果如下,如果目标Activity不在栈顶,就会新建Activity并入栈:
在这里插入图片描述

2)singleTop(栈顶复用模式)

  • singleTop:当要启动的目标Activity已经处于栈顶时,不会创建新的实例,会复用栈顶的Activity,并且其onNewIntent()方法会被调用;如果目标Activity不在栈顶,则跟standard一样会重复创建新的Activity实例
  • 应用场景:适合需要频繁打开和关闭的场景,例如:通知栏点击后打开的页面;一个推送通知的详情页面,用户可能会频繁打开和关闭它,使用SingleTop模式可以避免创建多个实例
  • 将前面用到OneActivity的launchMode属性修改为singleTop,重新运行OneActivity,多次点击按钮,只会创建一个Activity,并一直复用
    在这里插入图片描述

在这里插入图片描述

3)singleTask(栈内复用模式)

  • singleTask:每次启动活动时,系统会首先检查任务栈中是否存在该Activity的实例,如果发现存在,则直接复用该实例(目标Activity会调用onRestart()方法重新启动),在该目标Activity上的Activity都会调用onDestroy()方法清除(被弹出栈);如果任务栈中没有该Activity,则创建新的实例
  • 应用场景:适合作为应用的主页或者一个任务的开始页面,例如:邮箱应用的主页面;一个邮箱应用的主Activity,用户从任何地方返回到主页面时,都应该看到同一个Activity实例,而不是创建新的实例
  • TwoActivity、OneActivity重写onRestart()和onDestroy()方法
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.d("OneActivity","---onRestart---");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d("OneActivity","---onDestroy---");
    }
  • 重新运行OneActivity,点击按钮,OneActivity跳转到TwoActivity,在TwoActivity中重新启动OneActivity,则会发现返回栈中已经有OneActivity实例了,于是TwoActivity出栈【onDestroy()方法被调用】,OneActivity来到栈顶【onRestart()方法被调用】
    在这里插入图片描述

4)singleInstance(全局单例模式)

  • singleInstance:全局复用,不管哪个Task栈,只要存在目标Activity,就复用;每个Activity占用一个新的Task栈
  • 如果应用中的活动要允许其他程序调用,且其他应用和我们的应用可共享该活动实例,前面三种启动模式无法做到(同一个活动在不同的返回栈中入栈需要创建新的实例),而使用singleInstance模式就可以解决该问题,实现只有一个单独的返回栈来管理该活动,不管是哪个应用来访问该活动,都共用同一个返回栈,如此可解决共享活动实例的问题
  • 应用场景:适合需要与程序分离开的页面,如拨打电话、系统通讯录等;一个来电页面,它应该总是单独存在,不受其他Activity的影响。
  • 修改launchMode属性singleInstance,并在Activity中输出返回栈的唯一标识:taskId
|  |  |
|--|--|
|  |  |

Log.d("OneActivity","task id is " + getTaskId());
  • 输出结果如下,三个Activity都分别放在不同的返回栈中
    在这里插入图片描述

基本使用

下面我用一个复杂的案例重新串下Activity相关的知识点:

  • 第一个Activity:
import androidx.appcompat.app.AppCompatActivity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.example.myapplication1.R;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);

        // 输出日志,便于测试Activity的启动模式
        Log.d("FirstActivity","---onCreate---");
        Log.d("FirstActivity","taskId ="+getTaskId() + ", hasCode =" + hashCode());
        printTaskLog();

        TextView view = findViewById(R.id.firstView);
        view.setText("this is first activity");

        Button detailBtn = findViewById(R.id.detail);
        detailBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 创建Intent对象的三种方式
                // 1. Intent(Context packageContext, Class<?> cls)
                Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
                // 2. Intent intent = new Intent();
                //  intent.setClass(FirstActivity.this, SecondActivity.class);
                // 3. intent.setComponent(new ComponentName(FirstActivity.this, SecondActivity.class));
                startActivity(intent);
            }
        });
    }

    private void printTaskLog() {
        try {
            ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.d("current task name", activityInfo.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 页面布局activity_first.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".intent.FirstActivity">

    <TextView
        android:id="@+id/firstView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello,Android developer!" />

    <Button
        android:id="@+id/detail"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查看详情"/>

</LinearLayout>
  • 第一个Activity跳转来到的第二个Activity:
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.example.myapplication1.R;

public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Log.d("SecondActivity","---onCreate---");
        Log.d("SecondActivity","taskId ="+getTaskId() + ", hasCode =" + hashCode());
        printTaskLog();

        Button button = findViewById(R.id.second);
        button.setText("this is second activity");
        button.setTextColor(Color.RED);
        button.setBackgroundColor(Color.BLUE);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(SecondActivity.this,"SecondActivity向ThirdActivity传递数据",Toast.LENGTH_LONG).show();
                Intent intent = new Intent(SecondActivity.this, ThirdActivity.class);
                startActivity(intent);
            }
        });
    }

    private void printTaskLog() {
        try {
            ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.d("current task name", activityInfo.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 页面布局activity_second.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".intent.SecondActivity">

    <Button
        android:id="@+id/second"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/detail"/>

</LinearLayout>
  • 第二个Activity跳转来到的第三个Activity:
import androidx.appcompat.app.AppCompatActivity;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.example.myapplication1.R;

public class ThirdActivity extends AppCompatActivity implements View.OnClickListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        Log.d("ThirdActivity","---onCreate---");
        Log.d("ThirdActivity","taskId ="+getTaskId() + ", hasCode =" + hashCode());
        printTaskLog();

        TextView view = findViewById(R.id.third);
        view.setText("this is third activity");

        // this: ThirdActivity对象
        view.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.third){
            // 结束当前的活动页面
            finish();
        }
    }

    private void printTaskLog() {
        try {
            ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.d("current task name", activityInfo.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 页面布局activity_third.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".intent.ThirdActivity">

    <Button
        android:id="@+id/third"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="@string/thirdText"/>

</LinearLayout>
  • 控件触发事件的两种常用写法(以Click点击事件举例):
    1)控件调用set开头的监听事件方法
    View.java:
    public void setOnClickListener(@Nullable OnClickListener l) {
        if (!isClickable()) {
            setClickable(true);
        }
        getListenerInfo().mOnClickListener = l;
    }

在这里插入图片描述

2)实现监听事件的接口View.OnClickListener,重写事件的onClick(View v)处理方法:
在这里插入图片描述

  • AndroidManifest.xml清单文件中加入三个Activity的声明,没有指定launchMode属性,则默认为standard:
        <activity
            android:name=".intent.ThirdActivity"
            android:exported="true" />
        <activity
            android:name=".intent.SecondActivity"
            android:exported="true" />
        <activity
            android:name=".intent.FirstActivity"
            android:exported="true" 
            android:launchMode="standard"/>

运行结果说明:

  • 运行FirstActivity,依次点击FirstActivity、SecondActivity、ThirdActivity中的Button按钮,输出结果如下图所示,三个Activity被放入id为83,名称为com.example.myapplication1的任务栈中,又hash值不同,则可认为每启动一个Activity,都会重新创建一个Activity栈帧压入任务栈中
    在这里插入图片描述
  • 当跳转到ThirdActivity时,点击Button,触发点击事件,调用finish()方法,会结束ThirdActivity,跳转到SecondActivity
  • 启动模式使用singleInstance,修改AndroidManifest.xml中Activity的launchMode属性:
    android:launchMode="singleInstance"
    如下图可见,任务栈的唯一标识taskId不同,即存放每个Activity的Task栈不同,每创建一个Activity,都会生成一个新的任务栈来存放Activity
    在这里插入图片描述

最佳实践

随时随地退出程序

  • 当跳转的页面足够多后,退出程序需要连按多次Back键才行,Home键只是将程序挂起,并没有退出程序
  • 如果程序需要一个注销或退出的功能,则必须要实现随时随地能退出程序
  • 实现思路:用集合类管理所有的活动,代码如下:
import android.app.Activity;
import android.os.Build;

import java.util.ArrayList;
import java.util.List;

public class ActivityManager {
    private static List<Activity> activityList = new ArrayList<>();

    // 将当前创建的活动添加到管理器中
    public static void add(Activity activity){
        activityList.add(activity);
    }

    // 将要销毁的活动从管理器中移除
    public static void remove(Activity activity){
        activityList.remove(activity);
    }

    // 完成管理器中的所有活动,保证能随时随地退出程序
    public static void finishAll(){
        for (Activity activity : activityList) {
            if (!activity.isFinishing()){
                activity.finish();
            }
        }
    }

    public static List<Activity> getAll(){
        return activityList;
    }
}
  • 编写Activity测试:
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import com.example.myapplication1.R;

public class ManagerActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_manager);

        Log.d("ManagerActivity","current activity: " + getClass().getSimpleName());
        ActivityManager.add(this);

        findViewById(R.id.managerBtn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(ManagerActivity.this,LogoutActivity.class));
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityManager.remove(this);
    }
}
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.example.myapplication1.R;

public class LogoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_logout);
        ActivityManager.add(this);

        Log.d("logout before",ActivityManager.getAll().toString());

         findViewById(R.id.logoutBtn).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 // 完全退出应用程序
                 ActivityManager.finishAll();
//                 Log.d("logout going",ActivityManager.getAll().toString());
             }
         });

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityManager.remove(this);
        Log.d("logout after",ActivityManager.getAll().toString());
    }
}
  • 为能明显看出效果,可以多跳转几个页面,最后来到LogoutActivity,点击Button,直接退出应用程序,来到桌面
    注意:需要在跳转Activity中重写onDestroy()方法并在管理器中移除当前Activity,在onCreate()方法中,触发点击事件前加入 ActivityManager.add(this);
    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityManager.remove(this);
    }
  • 活动管理器中的活动在执行finishAll()前后的变化:
    在这里插入图片描述

参考

  • 郭霖《第一行代码》第二版
  • Android开发者文档

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

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

相关文章

等保一体机:多种防护机制,让等保合规简单高效!

自1994年国务院颁布《中华人民共和国计算机信息系统安全保护条例》规定计算机信息系统实行安全等级保护以来&#xff0c;等级保护工作经过了近25年的发展历程&#xff0c;成为了我国网络安全保护的重要举措之一。 2019年12月1日等保2.0正式开始实施&#xff0c;我国网络安全行业…

C++ virtual public(虚继承类)

这个"virtual"有什么作用&#xff1f; 由于C支持多重继承&#xff0c;所以对于一个派生类中有几个直接父类&#xff0c;而几个直接父类中有几个可能分别继承自某一个基类&#xff08;就是父类的父类&#xff09;&#xff0c;这样在构造最终派生类时&#xff0c;会出现…

15.docker-compose(单机版的容器编排工具)

docker-compose(单机版的容器编排工具) 类似ansible剧本 安装docker-compose编排工具 yum install -y docker-compose #&#xff08;需要epel源&#xff09;##docker-compose配置文件详细指令详解&#xff0c;参考如下链接 http://www.jianshu.com/p/2217cfed29d7 上传两个d…

路由器虚拟服务器有什么作用

现如今在IPv4时代&#xff0c;由于公网IP地址的匮乏&#xff0c;约有70%的电脑都处于内网中&#xff0c;上网需要通过路由器。如果反过来想要访问身处内网的电脑&#xff0c;我们就需要在路由器里开放相应的端口才能实现。而这开放端口的功能&#xff0c;在路由器里就叫做虚拟服…

Vue54-浏览器的本地存储webStorage

一、本地存储localStorage的作用 二、本地存储的代码实现 2-1、存储数据 注意&#xff1a; localStorage是window上的函数&#xff0c;所以&#xff0c;可以把window.localStorage直接写成localStorage&#xff08;直接调用&#xff01;&#xff09; 默认调了p.toString()方…

导出本地服务到Public Network,需有密码才能访问,7天有效时间

导出服务到Public Network&#xff0c;7天有效时间&#xff0c;需有密码才能访问 npm install -g localtunnellt --port 8000详细文档 https://localtunnel.github.io/www/

树状数组练习

先看一下最后一题&#xff0c;这是一个树状数组的题目&#xff0c;那就水一下吧,但是由于没有注意问题&#xff0c;wa了很多次 const int N (int)1e5 5; int n; int flag[N]; int dp[N]; class Solution { public:vector<int> countOfPeaks(vector<int>& num…

贪心算法学习五

例题一 解法&#xff08;贪⼼&#xff09;&#xff1a; 贪⼼策略&#xff1a; 我们的任何选择&#xff0c;应该让这个数尽可能快的变成 1 。 对于偶数&#xff1a;只能执⾏除 2 操作&#xff0c;没有什么分析的&#xff1b; 对于奇数&#xff1a; i. 当 n 1 的时候…

Prometheus之图形化界面grafana与服务发现

前言 上一篇文章中我们介绍了Prometheus的组件&#xff0c;监控作用&#xff0c;部署方式&#xff0c;以及如何通过在客户机安装exporter再添加监控项的操作。 但是不免会发现原生的Prometheus的图像化界面对于监控数据并不能其他很好的展示效果。所以本次我们将介绍一…

DP:01背包问题

一、背包问题的概述 背包问题是⼀种组合优化的NP完全问题。 本质上是为了找出“带有限制条件的组合最优解” 1、根据物品的个数&#xff0c;分为如下几类&#xff1a; • 01背包问题&#xff1a;每个物品只有⼀个&#xff08;重点掌握&#xff09;• 完全背包问题&#xff1…

【如何保持专注】

今日&#x1f4d2;&#xff0c;看博主分享下保持专注的新方法&#xff0c;有点意思 &#xff0c; 怎么保持专注&#xff0c;给大家分享两个极客的方法啊。 第一个呢是来自于一个非常著名的程序员啊&#xff0c;叫做这个尼克温特&#xff0c;大家有兴趣可以查一下&#xff0c;就…

探究肥胖致血糖异常的原因与运动的意义

肥胖对身体血糖存在影响&#xff0c;原因主要在于以下两方面。 首先&#xff0c;肥胖者体内的脂肪组织大量积聚&#xff0c;会释放诸多有害物&#xff0c;对胰岛素的正常功能形成干扰&#xff0c;致使胰岛素抵抗加剧&#xff0c;从而造成血糖调节失常。 其次&#xff0c;肥胖往…

Spring AI探索

Spring AI概述 该Spring AI项目旨在简化包含人工智能功能的应用程序的开发&#xff0c;避免不必要的复杂性。 该项目从著名的 Python 项目&#xff08;例如 LangChain 和 LlamaIndex&#xff09;中汲取灵感&#xff0c;但 Spring AI 并非这些项目的直接移植。该项目的成立基于…

Day 24:100301. 构成整天的下标对数目II

Leetcode 100301. 构成整天的下标对数目II 给你一个整数数组 hours&#xff0c;表示以 **小时 **为单位的时间&#xff0c;返回一个整数&#xff0c;表示满足 i < j 且 hours[i] hours[j] 构成 **整天 **的下标对 i, j 的数目。 **整天 **定义为时间持续时间是 24 小时的 *…

Electron+vite+vuetify项目搭建

最近想用Electron来进行跨平台的桌面应用开发。同时想用vuetify作为组件&#xff0c;于是想搭建一个这样的开发环境。其中踩了不少坑&#xff0c;总是会出现各种的编译错误和问题&#xff0c;依赖的各种问题&#xff0c;搞了好久最终环境终于弄好可正常开发了。这里分享下快速搭…

C语言王国——深入自定义类型(结构体)

目录 一、引言 二、结构体 1. 结构体类型的声明 2. 结构体变量的创建和初始化 2.1 创建 2.2 初始化 2.3 typedef 2.4 特殊声明 2.5 自引用 3. 结构成员访问操作符 4. 结构体内存对齐 4.1 对齐规则 4.2 offsetof 4.3 为什么存在内存对齐 5. 结构体传参 6. 结构体实现…

力扣191. 位1的个数

Problem: 191. 位1的个数 文章目录 题目描述思路复杂度Code 题目描述 思路 题目规定数值的范围不会超过32位整形数 1.定义统计个数的变量oneCount&#xff1b;由于每次与给定数字求与的变量mask初始化为1 2.for循环从0~32&#xff0c;每一次拿mask与给定数字求与运算&#xff…

单向散列函数解析

目录 1. 概述 2. 单向散列函数的性质 2.1 根据任意长度的消息计算出固定长度的散列值 2.2 能够快速计算出散列值 2.3 消息不同散列值也不同 2.4 具备单向性 3. 单向散列函数的算法 3.1 MD5 3.2 SHA序列 3.3 SM3 1. 概述 针对计算机所处理的消息&#xff0c;有时候我们…

GitLab、jenkins

Gitlab服务器&#xff1a;192.168.10.20 jenkins服务器&#xff1a;192.168.10.30 web应用服务器&#xff1a;192.168.10.100 通过容器部署gitlab&#xff1a; 安装容器管理软件podman 修改主机的22端口&#xff0c;该gitlab软件包中会使用到该端口 gitlab容器需要使用/etc/res…

Thinkphp起名网宝宝起名网站源码

Thinkphp起名网宝宝起名网站源码 源码介绍 1.宝宝在线起名 2.八字起名&#xff0c;周易取名 3.一对一起名 5.支持手机wap 链接数据库地址&#xff1a;Application\Common\Conf 修改里面config.php数据库连接&#xff0c;导入sm.sql数据库文件即可 伪静态用thinkphp 后台…