一文带你精通Android中的Activity

news2024/11/25 1:04:29

本文将会从活动的生命周期、启动模式、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开发者文档

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《Windows API每日一练》4.4 绘制填充区域

本节讲述如何填充由线条构建的封闭区域。当我们初始化一个窗口类时&#xff0c;往往已经指定了窗口的背景色画刷&#xff08;WHITE_BRUSH&#xff09;&#xff0c;即默认的填充封闭区域背景的画刷。如果我们想更换背景颜色&#xff0c;需要选入其他系统预定义的画刷&#xff08…

助力樱桃智能自动化采摘,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建果园种植采摘场景下樱桃成熟度智能检测识别系统

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到我们生活的方方面面&#xff0c;从智能家居到自动驾驶&#xff0c;再到医疗健康&#xff0c;其影响力无处不在。然而&#xff0c;当我们把目光转向中国的农业领域时&#xff0c;一个令人惊讶的…

几何公差的设计和选用

保证轴承的旋转精度&#xff0c;提出圆柱度&#xff1b; 这里的轴肩部面 为了测量方便&#xff0c;使用圆跳动代替垂直度公差方便一些。

胡说八道(24.6.15)——数字电子技术及Multisim仿真

上回书说到数电中的两种基本存储电路——锁存器和触发器以及时序逻辑电路的设计和分析。今天来看看触发器的几个应用&#xff0c;主要实践实践&#xff0c;不能只说概念。 首先&#xff0c;首当其冲的就是计数器&#xff0c;如果大家看过我之前记的笔记的话&#xff0c;应该不会…

vue3轮播图怎么做

先看效果 实现代码 <n-carouseleffect"card"dot-type"line"draggable:autoplay"!isHovered":current-index"currentIndex"prev-slide-style"transform: translateX(-150%) translateZ(-450px);opacity:1"next-slide-st…

SE语法总结博文(附思维导图)

Java中的规范 注释 //单行注释 /*多行注释 */ /**文档注释 */命名规范 命名时可以包含&#xff1a;字母、数字以及 下划线和 $ 符号等等。 但是不能以数字开头&#xff0c;也不能是关键字&#xff0c;且严格区分大小写。 类名&#xff1a;每个单词的首字母大写(大驼峰)&…

springboot优雅shutdown时异步线程安全优化

前面针对graceful shutdown写了两篇文章 第一篇&#xff1a; https://blog.csdn.net/chenshm/article/details/139640775 只考虑了阻塞线程&#xff0c;没有考虑异步线程 第二篇&#xff1a; https://blog.csdn.net/chenshm/article/details/139702105 第二篇考虑了多线程的安全…

Rewrite the Stars

文章目录 摘要1、引言2、相关工作3、重写星操作3.1、单层中的星操作3.2、扩展到多层3.3、特殊情况3.4、实证研究3.4.1、星操作的实证优越性3.4.2、决策边界对比3.4.3、扩展到无激活函数的网络 3.5、开放讨论与更广泛的影响 4、概念验证&#xff1a;StarNet4.1、StarNet架构4.2、…

HDU - 5651 xiaoxin juju needs help(Java JS Python C C++)

题目来源 Problem - 5651 (hdu.edu.cn) 题目描述 众所周知&#xff0c;小新是一位才华横溢的程序员。当他还是小学六年级的学生时&#xff0c;他就知道回文字符串了。 今年夏天&#xff0c;他在腾讯实习。一天&#xff0c;他的领导来找小新帮忙。他的领导给了他一个字符串&a…

LabVIEW程序的常见加密方式

LabVIEW程序的加密对于保护知识产权和敏感数据至关重要。本文将详细介绍LabVIEW程序常用的加密方式&#xff0c;包括VI加密、代码保护、文件加密和通信加密等&#xff0c;帮助开发者选择合适的加密方法来确保程序的安全性和完整性。 LabVIEW程序的常见加密方式 VI加密&#xf…

Fiddler抓包工具介绍

下载 下载:Web Debugging Proxy and Troubleshooting Tools|Fiddler 进去要填一个表 汉化版 百度网盘 请输入提取码 提取码&#xff1a;xq9t 下载过附件之后分别把两个文件 点开fiddler就ok了 配置https fiddler要想抓到https包(解密的),点击tools->options勾选三个对…

做好程序前设计

不要小看任何一道编程题目&#xff01;一定一定一定要想好之后再动手&#xff01;&#xff01;&#xff01; 带上你的草稿本&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xf…

DP:01背包问题

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

牛客热题:最长上升子序列(一)

&#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;力扣刷题日记 &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 文章目录 牛客热题&#xff1a;最长上升子序列(一)题目链接方法…

用PHP来调用API给自己定制一个“每日新闻”

头条新闻汇聚了互联网上的时事动态&#xff0c;提供最新新闻动态、网络热门话题和视频更新等&#xff0c;覆盖社会、政治、体育、经济、娱乐、科技等多个领域&#xff0c;并不断刷新内容。企业应用这一接口后&#xff0c;可以快速吸引更多的用户访问自己的平台。即使是非新闻类…

WINUI——CommunityToolkit.Mvvm Messenger接收消息时报错:Cannot access a disposed object.

背景 WINUI开发时使用CommunityToolkit.Mvvm的Messemger让UI展示一些信息时出现错误&#xff1a; System.ObjectDisposedException:“Cannot access a disposed object. ObjectDisposed_ObjectName_Name” 详细见下述截图&#xff1a; 开发环境 WIN11 WINUI&#xff13; …

微信小程序开发系列(三十五)·自定义组件的属性properties

微信小程序开发系列&#xff08;三十四&#xff09;自定义组件的创建、注册以及使用&#xff08;数据和方法事件的使用&#xff09;_wx小程序组件开发-CSDN博客 目录 1. 组件的属性 2. 组件的使用 3. 细节描述 1. 组件的属性 Properties是指组件的对外属性&#xff0c;主…

Nginx之静态文件服务器的搭建

1.概述 静态文件服务器是指提供HTML文件访问或客户端 可直接从中下载文件的Web服务器。对于图片、 JavaScript或CSS文件等渲染页面外观的、不会动态改 变内容的文件&#xff0c;大多数网站会单独提供以静态文件服 务器的方式对其进行访问&#xff0c;实现动静分离的架构。 HTML…

ReactNative和Android通信

初始化一个RN项目以后&#xff0c;接下来想要让Android与React Native通信 写一个继承自ReactContextBaseJavaModule类的子类&#xff0c;重写getName方法 package com.awesomeprojectimport android.util.Log import android.widget.Toast import com.facebook.react.bridge.…

Java并发自测题

文章目录 一、什么是线程和进程?线程与进程的关系,区别及优缺点&#xff1f;二、为什么要使用多线程呢?三、说说线程的生命周期和状态?四、什么是线程死锁?如何预防和避免线程死锁?五、synchronized 关键字六、并发编程的三个重要特性七、JMM &#xff08;Java Memory Mod…