Android堆栈分析

在开发中,与界面跳转联系比较紧密的概念是Task(任务)和Back Stack(回退栈)。activity的启动模式会影响Task和Back Stack的状态, 进而影响用户体验。除了启动模式之外,Intent类中定义的一些标志(以FLAG_ACTIVITY_开头)也会影响Task和Back Stack的状态。 在这篇文章中主要对android的堆栈管理进行分析和验证,其中涉及到activity的一个重要属性taskAffinity和Intent中的标志之一FLAG_ACTIVITY_NEW_TASK。

Task和Back Stack简介

task(任务)是一组Activities的集合,一组Activities被Stack(back stack)所管理,栈中Activity的顺序就是按照它们被打开的顺序依次存放的。

手机的Home界面是大多数task开始的地方,当用户在Home界面上点击了一个应用的图标时,这个应用的task就会被转移到前台。 如果这个应用目前并没有任何一个任务的话(说明这个应用最近没有被启动过),系统就会去创建一个新的task, 并且将该应用的主Activity放入到返回栈当中。

当一个Activity启动了另外一个Activity的时候,新的Activity就会被放置到返回栈的栈顶并将获得焦点。 前一个Activity仍然保留在返回栈当中,但会处于停止状态。当用户按下Back键的时候,栈中最顶端的Activity会被移除掉, 然后前一个Activity则会得重新回到最顶端的位置。返回栈中的Activity的顺序永远都不会发生改变, 我们只能向栈顶添加Activity,或者将栈顶的Activity移除掉。因此,返回栈是一个典型的后进先出(last in, first out)的数据结构。

task是可以跨应用的,这正是task存在的一个重要原因。有的Activity,虽然不在同一个app中,但为了保持用户操作的连贯性, 把他们放在同一个任务中。例如,在我们的应用中的一个Activity A中点击发送邮件,会启动邮件程序的一个Activity B来发送邮件, 这两个activity是存在于不同app中的,但是被系统放在一个任务中,这样当发送完邮件后,用户按back键返回,可以返回到原来的Activity A中, 这样就确保了用户体验。

下面来用代码做一个验证: 首先:我们来启动三个Activity来模拟生成活动与任务堆栈,三个Activity分别是:AndroidStackTaskActivity1、 AndroidStackTaskActivity2、AndroidStackTaskActivity3,具体代码如果下:

[代码]java代码:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
public class AndroidStackTaskActivity1 extends Activity implements OnClickListener{
        private Button next = null ;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            init();
        }
        private void init(){
            next = (Button)findViewById(R.id.button1);
            next.setOnClickListener(this);
        }
        @Override
        public void onClick(View v) {
            Intent i = new Intent(this,AndroidStackTaskActivity2.class);
            startActivity(i);
        }
    }
    public class AndroidStackTaskActivity2 extends Activity  implements OnClickListener {
        private Button next = null ;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main2);
            init();
        }
        private void init(){
            next = (Button)findViewById(R.id.button1);
            next.setOnClickListener(this);
        }
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Intent i = new Intent(this,AndroidStackTaskActivity3.class);
            startActivity(i);
        }
    }
    public class AndroidStackTaskActivity3 extends Activity  implements OnClickListener {
        private Button next = null ;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main2);
            init();
        }
        private void init(){
            next = (Button)findViewById(R.id.button1);
            next.setOnClickListener(this);
        }
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Intent i = new Intent(this,AndroidStackTaskActivity3.class);
            startActivity(i);
        }
    }

 

此时,生成的活动堆栈如下图所示:

首先activity1被start,此时,如果应用没有创建task则创建,并把activity1压入栈顶,activity1触发onCreate->onStart->onResume。

接着activity1转向到activity2时,activity1先触发onPause,activity2触发onCreate->onStart->onResume,然后activity1触发onPause->onStop,activity2压入栈顶。

以此类推,activity2转向activity3也是一样的步骤。那么当前栈顶是activity3。

当我们按下手机上的返回键时,栈顶的activity3触发onPause,activity2需要从状态stop到pause,所以触发了onPause->onStart->onResume, activity3触发onStop->onDestory,因为activity3从栈顶弹出,所以触发onDestory,此时,activity2在栈顶。

如果继续按返回键,当前栈顶的activity弹出并被destory,直到home界面。当所有的activity都弹出了,这个task也就消亡了。

当开始一个新的task时,前一个task被设置为后台。在后台,所有的activity都处理stop状态,但是back stack保留了所有后台activity的状态信息,只是丢失了焦点。

这个时候,用户还可以将任意后台的任务切换到前台,这样用户应该就会看到之前离开这个task时处于最顶端的那个Activity。

由于返回栈中的Activity的顺序永远都不会发生改变,所以如果你的应用程序中允许有多个入口都可以启动同一个Activity, 那么每次启动的时候就都会创建该Activity的一个新的实例,而不是将下面的Activity的移动到栈顶。这样的话就容易导致一个问题的产生, 即同一个Activity有可能会被实例化很多次,如下图所示:

但是呢,如果你不希望同一个Activity可以被多次实例化,这些功能甚至更多功能, 都是可以通过在manifest文件中设置元素的属性,或者是在启动Activity时配置Intent的flag来实现的。

下面我们就将开始讨论,如何通过manifest参数,以及Intent flag来改变Activity在任务中的默认行为。

1.使用manifest文件

当你在manifest文件中声明一个Activity的时候,你可以指定这个Activity在启动的时候该如何与任务进行关联。

2.使用Intent flag

当你调用startActivity()方法时,你可以在Intent中加入一个flag,从而指定新启动的Activity该如何与当前任务进行关联。 也就是说,如果Activity A启动了Activity B,Activity B可以定义自己该如何与当前任务进行关联, 而Activity A也可以要求Activity B该如何与当前任务进行关联。如果Activity B在manifest中已经定义了该如何与任务进行关联, 而Activity A同时也在Intent中要求了Activity B该怎么样与当前任务进行关联,那么此时Intent中的定义将覆盖manifest中的定义。

需要注意的是,有些启动模式在manifest中可以指定,但在Intent中是指定不了的。同样,也有些启动模式在Intent中可以指定,但在manifest中是指定不了的.

使用manifest文件

当在manifest文件中定义Activity的时候,你可以通过元素的launchMode属性来指定这个Activity应该如何与任务进行关联。 launchMode属性一共有以下四种可选参数:standard,singleTop,singleTask,singleInstance.之前已经详细介绍过这些内容,这里不在分析。

使用Intent flags

除了使用manifest文件之外,你也可以在调用startActivity()方法的时候,为Intent加入一个flag来改变Activity与任务的关联方式, 下面我们来一一讲解一下每种flag的作用:

1.FLAG_ACTIVITY_NEW_TASK

设置了这个flag,新启动Activity就会被放置到一个新的task当中(与”singleTask”有点类似,但不完全一样) ,当然这里讨论的仍然还是启动其它程序中的Activity。这个flag的作用通常是模拟一种Launcher的行为, 即列出一堆可以启动的东西,但启动的每一个Activity都是在运行在自己独立的任务当中的。

如果传递给startActivity()的Intent对象包含了FLAG_ACTIVITY_NEW_TASK标记,系统会为新Activity安排另外一个任务。 一般情况下,如同标记所暗示的那样,这会是一个新任务。然而,这并不是必然的。如果已经存在了一个与新Activity有着同样affinity的任务 ,则Activity会载入那个任务之中。如果没有,则启用新任务。简言之:有相同affinity的任务,则压入该任务,否则创建一个新的任务。

2.FLAG_ACTIVITY_SINGLE_TOP

设置了这个flag,如果要启动的Activity在当前任务中已经存在了,并且还处于栈顶的位置,那么就不会再次创建这个Activity的实例, 而是直接调用它的onNewIntent()方法。这种flag和在launchMode中指定”singleTop”模式所实现的效果是一样的。

3.FLAG_ACTIVITY_CLEAR_TOP

设置了这个flag,如果要启动的Activity在当前任务中已经存在了,就不会再次创建这个Activity的实例, 而是会把这个Activity之上的所有Activity全部关闭掉。比如说,一个任务当中有A、B、C、D四个Activity, 然后D调用了startActivity()方法来启动B,并将flag指定成FLAG_ACTIVITY_CLEAR_TOP,那么此时C和D就会被关闭掉, 现在返回栈中就只剩下A和B了。那么此时Activity B会接收到这个启动它的Intent,你可以决定是让Activity B调用onNewIntent()方法(不会创建新的实例), 还是将Activity B销毁掉并重新创建实例。如果Activity B没有在manifest中指定任何启动模式(也就是”standard”模式), 并且Intent中也没有加入一个FLAG_ACTIVITY_SINGLE_TOP flag,那么此时Activity B就会销毁掉,然后重新创建实例。 而如果Activity B在manifest中指定了任何一种启动模式,或者是在Intent中加入了一个FLAG_ACTIVITY_SINGLE_TOP flag,那么就会调用Activity B的onNewIntent()方法。

FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK结合在一起使用也会有比较好的效果,比如可以将一个后台运行的任务切换到前台,并把目标Activity之上的其它Activity全部关闭掉。这个功能在某些情况下非常有用,比如说从通知栏启动Activity的时候。

以上只介绍了常有用的几种控制Activity跳转的Flag标识.

主要的属性

主要的属性有: launchMode. taskAffinity. allowTaskReparenting. alwaysRetainTaskState. clearTaskOnLaunch . finishOnTaskLaunch.

下面将对每一个属性和标志一一介绍:

affinity

通常来说一个程序内/任务栈中的Activity具有亲和力,也就是说具有相同亲和力的Activity默认属于同一个任务Task中.

affinity可以用于指定一个Activity更加愿意依附于哪一个任务,在默认情况下,同一个应用程序中的所有Activity都具有相同的affinity, 所以,这些Activity都更加倾向于运行在相同的任务当中。当然了,你也可以去改变每个Activity的affinity值, 通过元素的taskAffinity属性就可以实现了。

taskAffinity属性接收一个字符串参数,你可以指定成任意的值(字符串中至少要包含一个.),但必须不能和应用程序的包名相同,因为系统会使用包名来作为默认的affinity值。

affinity决定两件事情——Activity重新宿主(从一个Task跳到了另一个Task中,新的Task就被称为重新宿主)的Task(参考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK标志启动的Activity宿主的Task。 注意:affinity只有在加载activity的Intent对象包含了FLAG_ACTIVITY_NEW_TASK 标记,或者当activity的allowTaskReparenting属性设置为“true”时才有效。

affinity主要有以下应用场景: 当调用startActivity()方法来启动一个Activity时,默认是将它放入到当前的任务当中。但是, 如果在Intent中加入了一个FLAG_ACTIVITY_NEW_TASK flag的话(或者该Activity在manifest文件中声明的启动模式是”singleTask”), 系统就会尝试为这个Activity单独创建一个任务。但是规则并不是只有这么简单,系统会去检测要启动的这个Activity的affinity和当前任务的affinity是否相同, 如果相同的话就会把它放入到现有任务当中,如果不同则会去创建一个新的任务。而同一个程序中所有Activity的affinity默认都是相同的, 这也是前面为什么说,同一个应用程序中即使声明成”singleTask”,也不会为这个Activity再去创建一个新的任务了。

allowTaskReparenting

当把Activity的allowTaskReparenting属性设置成true时,Activity就拥有了一个转移所在任务的能力。 具体点来说,就是一个Activity现在是处于某个任务当中的,但是它与另外一个任务具有相同的affinity值, 那么当另外这个任务切换到前台的时候,该Activity就可以转移到现在的这个任务当中。

那还是举一个形象点的例子吧,比如有一个天气预报程序,它有一个Activity是专门用于显示天气信息的, 这个Activity和该天气预报程序的所有其它Activity具体相同的affinity值,并且还将allowTaskReparenting属性设置成true了。 这个时候,你自己的应用程序通过Intent去启动了这个用于显示天气信息的Activity, 那么此时这个Activity应该是和你的应用程序是在同一个任务当中的。但是当把天气预报程序切换到前台的时候, 这个Activity又会被转移到天气预报程序的任务当中,并显示出来,因为它们拥有相同的affinity值, 并且将allowTaskReparenting属性设置成了true。

一般来说,当Activity启动后,它就与启动它的Task关联,并且在那里耗尽它的整个生命周期。 当当前的Task不再显示时,你可以使用这个特性来强制Activity移动到有着affinity的Task中。典型用法是: 把一个应用程序的Activity移到另一个应用程序的主Task中。

alwaysRetainTaskState,clearTaskOnLaunch,finishOnTaskLaunch可以放在一起讨论。 如何用户将任务切换到后台之后过了很长一段时间,系统会将这个任务中除了最底层的那个Activity之外的其它所有Activity全部清除掉。 当用户重新回到这个任务的时候,最底层的那个Activity将得到恢复。这个是系统默认的行为,因为既然过了这么长的一段时间, 用户很有可能早就忘记了当时正在做什么,那么重新回到这个任务的时候,基本上应该是要去做点新的事情了。

当然,既然说是默认的行为,那就说明我们肯定是有办法来改变的,在元素中设置以下几种属性就可以改变系统这一默认行为:

alwaysRetainTaskState

如果将最底层的那个Activity的这个属性设置为true,那么上面所描述的默认行为就将不会发生,任务中所有的Activity 即使过了很长一段时间之后仍然会被继续保留。

一般来说,特定的情形如当用户从主画面重新选择这个Task时,系统会对这个Task进行清理(从stack中删除位于根Activity之上的所有Activivity)。 典型的情况,当用户有一段时间没有访问这个Task时也会这么做,例如30分钟。 然而,当这个特性设为“true”时,用户总是能回到这个Task的最新状态,无论他们是如何启动的。这非常有用, 例如,像Browser应用程序,这里有很多的状态(例如多个打开的Tab),用户不想丢失这些状态。系统会为我们保持这些状态数据。

clearTaskOnLaunch

如果将最底层的那个Activity的这个属性设置为true,那么只要用户离开了当前任务, 再次返回的时候就会将最底层Activity之上的所有其它Activity全部清除掉。简单来讲,就是一种和alwaysRetainTaskState完全相反的工作模式, 它保证每次返回任务的时候都会是一种初始化状态,即使用户仅仅离开了很短的一段时间。 这个特性只对启动一个新的Task的Activity(根Activity)有意义;对Task中其它的Activity忽略。

假设,某人从主画面启动了ActivityP,并从那里迁移至Activity Q。接下来用户按下HOME,然后返回Activity P。 一般,用户可能见到的是Activity Q,因为它是P的Task中最后工作的内容。然而,如果P设定这个特性为“true”, 当用户按下HOME并使这个Task再次进入前台时,其上的所有的Activity(在这里是Q)都将被清除。因此,当返回到这个Task时, 用户只能看到P。如果这个特性和allowTaskReparenting都设定为“true”,那些能重新宿主的Activity会移动到共享affinity的Task中; 剩下的Activity都将被抛弃。

finishOnTaskLaunch

这个属性和clearTaskOnLaunch是比较类似的,不过它不是作用于整个任务上的,而是作用于单个Activity上。 如果某个Activity将这个属性设置成true,那么用户一旦离开了当前任务,再次返回时这个Activity就会被清除掉。 如果这个特性和allowTaskReparenting都设定为“true”,这个特性胜出,Activity的affinity忽略。这个Activity不会重新宿主,但是会销毁。

Task和process的区别

process一般翻译成进程,进程是操作系统内核中的一个概念,表示直接受内核调度的执行单位。在应用程序的角度看,我们用java编写的应用程序, 运行在dalvik虚拟机中,可以认为一个运行中的dalvik虚拟机实例占有一个进程,所以,在默认情况下, 一个应用程序的所有组件运行在同一个进程中。但是这种情况也有例外,即,应用程序中的不同组件可以运行在不同的进程中。 只需要在manifest中用process属性指定组件所运行的进程的名字。如下所示:

[代码]xml代码:

?
1
2
<activity android:name=".MyActivity" android:label="@string/app_nam" android:process=":remote">
</activity>

 

这样的话这个activity会运行在一个独立的进程中。

task是可以跨应用的,这正是task存在的一个重要原因。有的Activity,虽然不在同一个app中,但为了保持用户操作的连贯性,把他们放在同一个任务中。 task不仅可以跨应用(Application),还可以跨进程(Process)。

关于onNewIntent()

launchMode为singleTask的时候,通过Intent启到一个Activity,如果系统已经存在一个实例,系统就会将请求发送到这个实例上, 但这个时候,系统就不会再调用通常情况下我们处理请求数据的onCreate方法,而是调用onNewIntent方法.

launchMode为singleTop的时候,如果IntentActivity处于任务栈的顶端,也就是说之前打开过的Activity,现在处于onPause、onStop 状态的话, 其他应用再发送Intent的话,执行顺序为:onNewIntent,onRestart,onStart,onResume。

不要忘记,系统可能会随时杀掉后台运行的 Activity ,如果这一切发生,那么系统就会调用 onCreate 方法,而不调用 onNewIntent 方法,一个好的解决方法就是在 onCreate 和 onNewIntent 方法中调用同一个处理数据的方法,如下所示:

[代码]java代码:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  processExtraData();
}
protected void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
   setIntent(intent);//must store the new intent unless getIntent() will return the old one
  processExtraData()
}
private void processExtraData(){
  Intent intent = getIntent();
  //use the data received here
}

 

注意onNewIntent如果没有调用setIntent(intent),则getIntent()获取的数据将不是你所期望的。 注意这句话:Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.所以最好是调用setIntent(intent),这样在使用getIntent()的时候就不会有问题了。

转载于:https://www.cnblogs.com/android-blogs/p/5690686.html

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

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

相关文章

如何写一篇MBA论文-涉及matlab建模

如何写一篇MBA论文&#xff1f; 知乎 19 个回答方向&#xff0c;具体一点&#xff0c;不要太大。战略管理、薪酬管理、绩效考核、营销管理&#xff0c;客户关系管理、供应链管理、供应商选择与评价&#xff0c;库存问题。。论文模式第1章&#xff1a;绪论第2章&#xff1a;现状…

什么电脑的牌子好用_扬州诚招电动牙刷代理有什么牌子比较好用

扬州诚招电动牙刷代理有什么牌子比较好用&#xff0c;珈蓝电器实惠物美&#xff0c;为人类口腔事业的发展再创新贡献。扬州诚招电动牙刷代理有什么牌子比较好用&#xff0c; 很多人说电动牙刷是懒人神器&#xff0c; 但偷懒可以&#xff0c;口腔清洁效果可不能因此打折。电动牙…

360浏览器打不开网页_苹果移动端、PC端safari浏览器打不开网页的解决方案!

你还在为苹果自带的safari浏览器打不开网页而苦恼吗&#xff0c;接下来的答案会帮助你解决苦恼。苹果自带safari浏览器的设备分为两种&#xff1a;移动端、PC端。因此不同设备出现safari浏览器打不开网页的情况需要具体问题具体分析。最简单的问题往往最容易被我们忽视&#xf…

台式电脑如何截屏_买台式电脑如何避免成为被宰羔羊(一)

台式电脑的优点是很多的&#xff0c;比如价格便宜(和游戏本比起来)&#xff0c;比如性能发挥稳定(因为不受限于散热)&#xff0c;比如屏幕大看起来更舒服。但是和笔记本比起来&#xff0c;台式的水就非常深了&#xff0c;无论是线下实体店&#xff0c;还是线上网店&#xff0c;…

n型半导体和p型半导体的区别_VNX系列大流量工业型膜堆, 为半导体等行业提供超纯水!...

自20世纪80年代以来&#xff0c;IONPURE始终以为广泛的应用提供最优质的电化学解决方案延续着它的领导地位。IONPURE持续创新&#xff0c;于2004年推出了VNX 系列大流量CEDI膜堆&#xff0c;单个膜堆的名义产水流量最大可达12.5m3/h。IONPURE于2018年推出了单个膜堆的名义产水流…

属于db模式缺点的是什么_详解 Seata Golang 客户端 AT 模式及其使用

源码:point_down: seata-golang概述我们知道 Seata Java Client 的 AT 模式&#xff0c;通过代理数据源&#xff0c;实现了对业务代码无侵入的分布式事务协调机制&#xff0c;将与 Transaction Coordinator (TC) 交互的逻辑、Commit 的逻辑、Rollback 的逻辑&#xff0c;隐藏在…

如何在mfc主对话框中再显示子对话框_win10扩展显示器设置方法

使用win10系统的过程中&#xff0c;常常需要对win10系统扩展显示器进行设置。良多对电脑不太认识的用户不知道win10系统扩展显示器到底该如何设置?实在win10系统扩展显示器的设置方法非常简朴&#xff0c;下面小编教你win10扩展显示器设置方法。一些用户使用电脑时需要运行多个…

蓝牙驱动卸载后自动安装_Intel 蓝牙驱动安装教程

前言可能有些人之前没有搞定Intel蓝牙的驱动&#xff0c;今天就把蓝牙的驱动也发一下&#xff0c;实现Intel全家桶的驱动&#xff0c;到处倒腾换网卡也是挺折腾的。所支持的蓝牙IDIntelBluetoothFirmware 是一个用于在 macOS 中启用原生蓝牙的固件上传驱动&#xff0c;固件的二…

cad在线转低版本_为什么别人制图那么快?41个CAD实用技巧,3天轻松玩转CAD

获取更多业界资讯和深度好文● 点击蓝字关注我们 ●点击上方蓝色字体 关注我们我们在使用CAD制图时&#xff0c;总感觉自己的速度非常慢&#xff0c;为什么别人可以那么快的制图呢&#xff1f;今天就给大家分享一些CAD实用技巧&#xff0c;让你3天轻松玩转CAD。一、提高绘图效率…

不同协议的数据包如何处理_【项目申报专员】如何处理各种不同的项目申报工作呢...

前文我们说到了在企业做项目申报专员需要掌握的政策查询&#xff0c;以及申报流程解读工作&#xff0c;今天我给大家来分享在企业如何做好对不同项目的申报工作。说这个问题之前&#xff0c;我们先得了解一些背景知识。在企业做项目申报专员工作意味着什么&#xff1f;意味着事…

jsoup简单的爬取网页数据

/*** Project Name:JavaTest* File Name:BankOfChinaExchangeRate.java* Package Name:com.lee.javatest* Date:2016年7月22日下午1:34:09* Copyright (c) 2016年7月22日, Pwenlee All Rights Reserved.* */package com.lee.javatest;import java.io.Serializable; import java…

sql每个月每个人的花销占比_11月:每个认真生活的人,都值得被认真对待

恍然已11月&#xff0c;风吹枯叶落&#xff0c;落叶生肥土&#xff0c;肥土滋养着果实&#xff0c;果实缓慢而坚定着成长。图片&#xff5c;东海青 摄图片&#xff5c;子夜鸟 摄11月&#xff0c;不要怂这是属木芙蓉的晚秋。花朵娇嫩&#xff0c;它却无所忌惮地美丽着&#xff0…

比较TFS与SVN,你必须知道的10点区别

相比SVN&#xff0c;对于TFS的优点我有以下几点看法&#xff0c;供大家参考&#xff1a; 1. 总体比较&#xff1a; TFS是一个应用软件生命周期管理&#xff08;ALM&#xff09;软件&#xff0c;是一个软件研发平台产品&#xff0c;其功能覆盖了软件研发过程中的所有环节&#…

react textarea 空格为什么不换行_你需要的 React + TypeScript 50 条规范和经验

这篇文章没有对错之分&#xff0c;肯定也有不完善的地方&#xff0c;结合了自己日常开发和经验。可以让你书写代码更具严谨性,希望看完之后有所帮助。本文字数4000 &#xff0c;看完本文大概需半小时。1. 注释(1) 文件顶部的注释&#xff0c;包括描述、作者、日期/** * descrip…

Three.js基础探寻二——正交投影照相机

本篇主要介绍照相机中的正交投影照相机。   第一篇传送门&#xff1a;Three.js基础探寻一 1.照相机 图形学中的照相机定义了三维空间到二维屏幕的投影方式。 针对投影方式照相机分为正交投影照相机和透视投影照相机。 2.两种相机的区别与适用范围 正交投影&#xff1a; 透视投…

centos删除文件夹_等保测评主机安全之centos密码长度

密码长度&#xff0c;作为等级保护主机测评项里中密码复杂度要求之一&#xff0c;是必须要查的。在《等级测评师初级教程》里&#xff0c;对于密码长度的设置指向了/etc/login.defs里的PASS_MIN_LEN字段。# PASS_MIN_LEN Minimum acceptable password length.PASS_MIN_LEN …

Activity的四种启动模式-图文并茂

1、对于使用standard 模式的活动&#xff0c;系统不会在乎这个活动是否已经在返回栈中存在&#xff0c;每次启动都会创建该活动的一个新的实例。例如A启动A&#xff0c;A再接着启动A&#xff0c;A继续启动A&#xff0c;然后再分别出栈&#xff0c;如图所示2、当活动的启动模式指…

ajax如何提交多表单的值_25 HTML5表单基本控件(二)

成长是一辈子的事儿&#xff01;大家好&#xff01;我是时问新。分享前端、Python等技术&#xff0c;以及个人成长路上的那些事儿。密码框使用标签&#xff0c;把标签上的type属性的值&#xff0c;设置为"password"&#xff0c;就可以创建密码框。密码框和单行文本框…

android_studio上传svn的时候那些不提交

buid文件夹不需要提交 转载于:https://www.cnblogs.com/YangBinChina/p/5708510.html