2021-04-09

activity的四种加载模式,回调机制

在这里插入图片描述
Activity的四种加载模式:

standard模式(系统默认的模式):每次通过这个模式启动目标Activity时,Android总会为目标Activity创建一个实例,并将该Activity添加到Task栈顶,(栈是先进后出),这种模式不会启动新的Task,新的Activity会不断被添加到原有的Task中。当按下返回键的时候,最上面的那个先删除。

singleTop模式:与standand类似,唯一不同的是,当将要被启动的Activity位于栈顶的时候,不会在创建新的实例,而是用最上面的那个实例。
singleTask模式:在整个Task过程中值存在一个实例。这里又分为三种情况:

  1. 如果创建的实例不存在,则会创建一个实例。
  2. 如果已经存在,并且位于栈顶,则和singleTop一样。
  3. 如果存在但是没有位于栈顶,则把所有的实例移除,把目标实例放入,从而变成栈顶。

singleInstance模式:在这种模式下,无论从哪个Task中启动只会存在一个目标实例。并会采用一个全新的Task来存放目标活动。

如果目标不存在,则会用一个全新的Task来存放目标Activity,并且位于栈顶。
如果目标实例存在,则系统会把此Task移驾前台。
Activity的生命周期与加载模式

  • 4个状态 运行状态 暂停状态 停止状态 销毁状态
  • 7个周期方法onCreate–>onStart()–>onResume()–>onPause()–>onStop()–>onDestroy()
  • Android应用程序,用Task(Activity栈)来管理Activity,最先启动的被放到栈底.
  • Activity的回调机制,当Activity处于不同的生命周期时,相应的周期方法被回调.

Fragment的生命周期和使用

Fragment 概要

Fragment表示 Activity 中的行为或用户界面部分。您可以将多个片段(片段就是指 Fragment )组合在一个 Activity 中来构建多窗格 UI,以及在多个 Activity 中重复使用某个片段。您可以将片段视为 Activity 的模块化组成部分,它具有自己的生命周期,能接收自己的输入事件,并且您可以在 Activity 运行时添加或移除片段(有点像您可以在不同 Activity 中重复使用的“子 Activity”)。

片段必须始终嵌入在 Activity 中,其生命周期直接受宿主 Activity 生命周期的影响。 例如,当 Activity 暂停时,其中的所有片段也会暂停;当 Activity 被销毁时,所有片段也会被销毁。

当您将片段作为 Activity 布局的一部分添加时,它存在于 Activity 视图层次结构的某个 ViewGroup 内部,并且片段会定义其自己的视图布局。您可以通过在 Activity 的布局文件中声明片段,将其作为 元素插入您的 Activity 布局中,即静态添加。或者通过将其添加到某个现有 ViewGroup,利用应用代码进行动态插入。不过,片段并非必须成为 Activity 布局的一部分;您还可以将没有自己 UI 的片段用作 Activity 的不可见工作线程。

Fragment 作用

Android 在 Android 3.0 (API 11)中引入了片段,主要是为了给更大的屏幕(如平板电脑)上更加动态和灵活的 UI 设计提供支持。由于平板屏幕比手机的屏幕大得多,也能显示更多的布局和组件。

例如,新闻应用可以使用一个片段在左侧显示文章列表,使用另一个片段在右侧显示文章 — 两个片段并排显示在一个 Activity 中,每个片段都具有自己的一套生命周期回调方法,并各自处理自己的用户输入事件。 因此,用户不需要使用一个 Activity 来选择文章,然后使用另一个 Activity 来阅读文章,而是可以在同一个 Activity 内选择文章并进行阅读,如图 1 中的平板电脑布局所示。

图1

在平板电脑尺寸的设备上运行时,该应用可以在 Activity A 中嵌入两个片段。 不过,在手机尺寸的屏幕上,没有足以储存两个片段的空间,因此Activity A 只包括用于显示文章列表的片段,当用户选择文章时,它会启动Activity B,其中包括用于阅读文章的第二个片段。 因此,应用可通过重复使用不同组合的片段来同时支持平板电脑和手机,如图 1 所示。
在这里插入图片描述
Fragment 生命周期
在这里插入图片描述
可以看到 Fragment 的生命周期和 Activity 很相似,只是多了一下几个方法:
onAttach() 在Fragment 和 Activity 建立关联是调用(Activity 传递到此方法内)
onCreateView() 当Fragment 创建视图时调用
onActivityCreated() 在相关联的 Activity 的 onCreate() 方法已返回时调用。
onDestroyView() 当Fragment中的视图被移除时调用
onDetach() 当Fragment 和 Activity 取消关联时调用。

可以看下几种操作情况下Fragment 的生命周期变化
在这里插入图片描述

管理 Fragment 生命周期和 Activity 生命周期很相似,同时 Activity 的生命周期对 Fragment 的生命周期也有一定的影响,如下图所示
在这里插入图片描述

适配器

学习使用安卓好多组件需要用到适配器,刚开始不了解看了一下相关的设计模式,简单的入个门。
在这里插入图片描述
适配器模式的定义:将一个类的接口,装换成客户期望的另一个接口,适配器让原本接口不兼容的类可以合作无间。

在这里插入图片描述
比如ListView的适配模式如下:适配器负责将数据转换成ListView需要的格式,然后传递给ListView,然后如果ListView数据改变的话适配器负责把数据源进行改变
在这里插入图片描述

数组

在数组开辟空间之后,每个位置都是有下标(索引的),我们就是通过这个索引来访问元素的
数组下标从0开始,到数组长度-1结束,访问其他位置就出异常。
数组特点:1.其长度是确定的,数组一旦被创建,他的大小就是不可以改变的。
2.其元素必须是相同的类型,不允许出现混合类型。
3.数组的元素可以使任何数据类型,包括基本类型和引用类型。
数组静态初始化
int[] arr={1,2,3};
int [] arr= new int[]{1,2,3};
动态初始化
int [] arr=new int[2];
arr[0]=12;
arr[1]=1;
增强for循环(foreach循环) 有点:代码简单 确定不能进行索引有关的操作
数组的优点:查询效率高
数组的缺点:删除和添加效率低,需要移动大量的元素

方法的定义及使用

方法的最大好处是可以进行重复调用,但是至于说那些操作要形成方法,这些都要根据你的实际项目经验而自我总结的。
##方法的基本定义
限制条件:在主类中定义,并且由主方法直接调用的方法形式。
方法就是一段可以被重复调用的方法块。在Java中要想进行方法的定义,则可以使用如下的语法完成。

public static 返回类型 方法名称([参数类型 变量, …]) {
方法体代码;
[return [返回值];]
}

在定义方法的时候对于方法的返回值有一下的两类:

void:没有返回值;

数据类型(基本类型,引用类型)。

范例: 定义一个没有返回值,没有参数的方法

public class Demo {
public static void main(String[] args) {
print(); //主方法里面直接调用方法
}
public static void print() {
System.out.println(“Hello World!”); //定义方法
}
}

范例: 定义一个有参数无返回值的方法

public class Demo {
public static void main(String[] args) {
print(“Hello”); //主方法里面直接调用方法
print(" world");
print("!");
}
public static void print(String msg) { //定义方法
System.out.print(msg);
}
}

范例: 有参数有返回值的方法

public class Demo {
public static void main(String[] args) {
int result = add(10, 20);
System.out.println(result);
//既然方法有返回值,那么这些返回值也可以直接输出
System.out.println(add(100, 200));
}
public static int add(int x, int y) { //定义方法
return x + y;
}
}

但是在定义方法的时候有一点特别要注意,如果某一个方法上使用了void定义,那么该方法可以直接用return来结束调用。一般而言,这种return的处理往往需要结合if判断来实现。

public class Demo {
public static void main(String[] args) {
print(10);
print(20);
}
public static void print(int x) { //定义方法
if(x == 20) //表示的是方法结束的判断
return; //此语句之后的代码不再执行
System.out.println("x = " + x);
}
}

##方法重载(重点)
方法重载指的是:方法名称相同,参数的类型和个数不同。

范例: 实现方法重载

public class TestDemo {
public static void main(String[] args) {
//此时将根据参数的类型和个数的不同执行不同的方法体
System.out.println(add(10, 20));
System.out.println(add(30, 40, 50));
System.out.println(add(1.1, 2.1));
}
public static int add(int x, int y) {
return x + y;
}
//此时方法名称相同,参数的个数不同
public static int add(int x, int y, int z) {
return x + y + z;
}
public static double add(double x, double y) {
return x + y;
}
}

在进行方法重载的时候有一个重要的原则:要求方法的返回值类型一定要相同。

范例: 观察如下程序

public class TestDemo {
public static void main(String[] args) {
//此时将根据参数的类型和个数的不同执行不同的方法体
System.out.println(“hello”); //输出字符串
System.out.println(1); //输出整形
System.out.println(1.1); //输出浮点型
System.out.println(‘A’); //输出字符
System.out.println(true); //输出布尔
}
}

证明:System.out.println()是一个被重载的方法
方法递归调用

方法的递归调用指的是一个方法自己调用自己的形式。一般如果要进行方法的递归操作往往都具备有以下的特点:

方法必须有一个递归的结束条件;

方法在每次递归处理的时候一定要做出一些变更;

范例: 实现1 ~ 100的累加操作

public class TestDemo {
public static void main(String[] args) {
System.out.println(sum(100));
}
public static int sum(int num) {
if(num == 1)
return 1;
return num + sum(–num);
}
}

[main()调用] 第1次执行sum()方法 return 100 + sum(99);
[sum()递归] 第2次执行sum()方法 return 99 + sum(98);
[sum()递归] 第3次执行sum()方法 return 98 + sum(97);
…
[sum()递归] 倒数第2次执行sum()方法 return 2 + sum(1);
[sum()递归] 倒数第1次执行sum()方法 return 1;

范例: 实现60!,这个结果太大,应该使用double。

public class TestDemo {
public static void main(String[] args) {
System.out.println(mul(60));
}
public static double mul(int num) {
if(num == 1)
return 1;
return num * mul(–num);
}
}

通过代码可以发现使用while循环的操作其实大部分都可以更换为递归,之所以使用递归主要是一个方法可以执行的操作很多,而且结构要好。

类与对象的基本概念

一、面向对象

概念:面向对象程序设计(OOP)是一种程序设计的泛型,同时也是一种程序开发的方法,它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性

二、类和对象的概念

  1. 类:类是现实世界在计算机中的反映,它将数据和对这些数据的操作封装在一起(并没有开空间)
    在这里插入图片描述
  2. 对象:类的实例(占有实际的空间)在这里插入图片描述
    1)类相当于盖楼房的图纸一样,虽然定义了有哪些成员,但并没有实际的空间

2)类可以实例化出多个对象,实例化出的对象占有实际空间(用来存储成员变量)
三、类的三大特性:

1.封装 2.继承 3.多态

封装:函数的封装是一种形式,隐藏对象的属性和实现细节(函数内部),仅仅对外提高函数的接口和对象进行交互。

类的访问限定符可以协助其完成封装

四、类的三个访问限定符在这里插入图片描述
1.public:公有的,类的成员可以从类外直接访问

2.private/protected:类的成员不能从类外直接访问

3.类的每个访问限定符可以多次在类中使用,作用域为从该限定符开始到下一个限定符之前/类结束

4.类中如果没有定义限定符,则默认为私有的(private)

5.类的访问限定符体现了类的封装性在这里插入图片描述
因为_name是私有的,所以在类外不能使用,而_age,Eat()是公有的,所以在类外可以直接使用

五、类的定义

1.定义一个简单的类
在这里插入图片描述
2.类的对象可以直接通过 . 来访问类的公有成员,类的对象指针可以通过->来访问类的公有成员在这里插入图片描述
3.类外定义成员函数,需要使用::(作用域解析符)指明其属于哪个类

六、类的大小

类的成员函数放在公共代码区,所有该类的对象共享这些成员函数,每个对象的大小为类内成员变量的大小之和,遵循内存对齐原则在这里插入图片描述
1.为什么要内存对齐?

答:为了提高程序的性能,方便cpu访问内存,处理器并不是一个字节一个字节来访问内存,一般是4个字节或8个字节

2.空类占多少个字节?为什么?

答:空类占1个字节,占位用,告诉系统我这里定义了一个类,虽然它是空的

封装性的初步分析

1.封装性的引入
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。
除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。
这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs())
同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).
–>此时,针对于属性就体现了封装性。
1.1 通俗理解
简单地讲:使用者对类内部定义的属性( 对象的成员变量) 的直接操作会导致数据的错误、混乱或安全性问题。
保护的方式:信息隐藏
2.引入封装性的面试规范解答
程序设计追求“高内聚,低耦合”
高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
低耦合:仅对外暴露少量的方法用于使用。
隐藏对象内部的复杂性,只对外公开简单的接口,便于外界调用,从而提高系统的可拓展性、可维护性。
即把该隐藏的隐藏起来,该暴露的暴露出来,这就是封装性的设计思想。
二、封装性的体现
1.语法规范
Java中通过将类的属性xxx私有化(private)(数据声明为私有的(private)),再提供公共的(public)方法:getXxx() 和setXxx()实现对该属性的操作(获取和设置该属性的值)

1.2 目的
隐藏一个类中不需要对外提供的实现细节;
使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
便于修改,增强代码的可维护性;
2. 拓展封装性的体现
如上;
不对外暴露的私有的方法;
单例模式(将构造器私有化);
如果不希望类在包外被调用,可以将类设置为缺省的(default)
3.封装性的体现,需要权限修饰符
3.1 权限修饰符定义
限定对象对该类成员的访问权限。

3.2 权限修饰符的种类:4种
Java规定的4种权限(从小到大排列):private、(缺省)default、protected 、public

种类 类内部 同一个包 不同包的子类 同一个工程
private ok no no no
缺省(defau) ok ok no no
protected ok ok ok no
public ok ok ok ok
调用顺序由小到大:类内部<同一个包 <不同包的子类<同一个工程
注意:

种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类;
修饰类的话,只能使用:(缺省)default、public;
4.总结封装性
Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

三、代码展示
/* 1.创建程序,在其中定义两个类:Person和PersonTest类。定义如下:
用setAge()设置人的合法年龄(0~130),用getAge()返回人的年龄。
2.练习2:
2.1. 在前面定义的Person类中添加构造器,利用构造器设置所有人的age属性初始值都为18。
2.2. 修改上题中类和构造器,增加name属性,使得每次创建Person对象的同时初始化对象的age属性值和name属性值。
*/
class Person2 {

private int age;
private String name;

public Person2(){
    age = 18;
}

public Person2(String n,int a){
    name = n;
    age = a;
}


public void setAge(int a){
    if(a < 0 || a > 130){

// throw new RuntimeException(“传入的数据非法!”);
System.out.println(“传入的数据非法!”);
return;
}

    age = a;

}

public int getAge(){
    return age;
}

//绝对不要这样写!!

// public int doAge(int a){
// age = a;
// return age;
// }
public void setName(String n){
name = n;
}
public String getName(){
return name;
}

}
//在PersonTest类中实例化Person类的对象b,调用setAge()和getAge()方法,体会Java的封装性。
class PersonTest2 {
public static void main(String[] args) {

    Person2 p1 = new Person2();

// p1.age = 1;编译不通过

    p1.setAge(12);

    System.out.println("年龄为:" + p1.getAge());

// p1.doAge(122);

    Person2 p2 = new Person2("Tom", 21);
    System.out.println("name = " + p2.getName() + ",age = " + p2.getAge());

}

}

//编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量。
//此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
class TriAngle { //angle:角 angel:天使

private double base;//底边长
private double height;//高

public TriAngle(){

}

public TriAngle(double b,double h){
    base = b;
    height = h;
}


public void setBase(double b){
    base = b;
}
public double getBase(){
    return base;
}
public void setHeight(double h){
    height = h;
}
public double getHeight(){
    return height;
}

}
class TriAngleTest {
public static void main(String[] args) {

    TriAngle t1 = new TriAngle();
    t1.setBase(2.0);
    t1.setHeight(2.4);

// t1.base = 2.5;//The field TriAngle.base is not visible
// t1.height = 4.3;
System.out.println("base : " + t1.getBase() + ",height : " + t1.getHeight());

    TriAngle t2 = new TriAngle(5.1,5.6);
    System.out.println("base : " + t2.getBase() + ",height : " + t2.getHeight());
}

}

构造方法,匿名对象

一.构造方法
在实例化一个对象后,如果要为这个对象中的属性赋值,则必须用setter方法为属性分别赋值才可以,这显然不够方便。这时可以通过构造方法来完成这样的操作。在面向对象中构造方法的主要作用是为类中的属性初始化。
构造方法可以看成为一种特殊的方法:
【构造方法的定义格式】

class 类名称{
访问权限 类名称(类型1 参数1,类型2 参数2,…….){
…….//构造方法没有返回值
}
}

在构造方法时要注意:
构造方法的名称必须与类名称一致;
构造方法的声明处不能有任何返回值类型的声明;
不能在构造方法中使用return返回一个值;

声明一个构造方法:

class Person{
public Person(){ // 声明构造方法
System.out.println(“一个新的Person对象产生。”) ;
}
};
public class ConsDemo01{
public static void main(String args[]){
System.out.println(“声明对象:Person per = null ;”) ;
Person per = null ; // 声明对象时并不去调用构造方法
System.out.println(“实例化对象:per = new Person() ;”) ;
per = new Person() ;//实例化对象
}
};

运行结果:

声明对象:Person per = null ;
实例化对象:per = new Person() ;
一个新的Person对象产生。

程序实例化对象的过程与之前一样的,在类中定义一个person类的构造方法,但是从程序的运行结果来看,当调用关键字new实例化对象时才会调用构造方法。
在上例中,类中并没有构造方法,但是也可以调用,只是为什么?首先要说明的是,只要是类就必定存在构造方法,在Java中如果一个类中没有明确的声明一个构造方法时,则在编译时会直接生成一个无参数、什么都不做的构造方法,也就是说,如果以上的Person类中没有声明构造方法,实际上编译时会在动加上以下的构造方法:

class Person{
public Person(){}
}

下面用构造方法进行复制

class Person{
private String name ;
private int age ;
public Person(String n,int a){ // 声明构造方法,为类中的属性初始化
this.setName(n) ;
this.setAge(a) ;
}
public void setName(String n){
name = n ;
}
public void setAge(int a){
if(a>0&&a<150){
age = a ;
}
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
public void tell(){
System.out.println(“姓名:” + this.getName() + “;年龄:” + this.getAge()) ;
}
};
public class ConsDemo02{
public static void main(String args[]){
System.out.println(“声明对象:Person per = null ;”) ;
Person per = null ; // 声明对象时并不去调用构造方法
System.out.println(“实例化对象:per = new Person() ;”) ;
per = new Person(“张三”,30) ;//实例化对象
per.tell() ;
}
};

运行结果为:

声明对象:Person per = null ;
实例化对象:per = new Person() ;
姓名:张三;年龄:30
1
2
3
通过对比可以看出,通过构造方法进行赋值比通过setter方法更加方便。
与普通方法一样,构造方法也是可以重载的,只要每个构造方法的参数类型或参数个数不同,即可实现重载
【构造方法的重载】

class Person{
private String name ;
private int age ;
public Person(){} // 声明一个无参的构造方法
public Person(String n){ // 声明有一个参数的构造方法
this.setName(n) ;
}
public Person(String n,int a){ // 声明构造方法,为类中的属性初始化
this.setName(n) ;
this.setAge(a) ;
}
public void setName(String n){
name = n ;
}
public void setAge(int a){
if(a>0&&a<150){
age = a ;
}
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
public void tell(){
System.out.println(“姓名:” + this.getName() + “;年龄:” + this.getAge()) ;
}
};
public class ConsDemo03{
public static void main(String args[]){
System.out.println(“声明对象:Person per = null ;”) ;
Person per = null ; // 声明对象时并不去调用构造方法
System.out.println(“实例化对象:per = new Person() ;”) ;
per = new Person(“张三”,30) ;//实例化对象
per.tell() ;
}
};

运行结果为:

声明对象:Person per = null ;
实例化对象:per = new Person() ;
姓名:张三;年龄:30

以上方法被重载了三次,在主方法调用的是只有一个参数的构造方法。
二.匿名对象
匿名对象就是没有明确的给出名称的对象。一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用。
【匿名对象的使用】

class Person{
private String name ;
private int age ;
public Person(String n,int a){ // 声明构造方法,为类中的属性初始化
this.setName(n) ;
this.setAge(a) ;
}
public void setName(String n){
name = n ;
}
public void setAge(int a){
if(a>0&&a<150){
age = a ;
}
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
public void tell(){
System.out.println(“姓名:” + this.getName() + “;年龄:” + this.getAge()) ;
}
};
public class NonameDemo01{
public static void main(String args[]){
new Person(“张三”,30).tell() ;
}
};

运行结果:

姓名:张三;年龄:30
1
在上面程序中,直接使用了“new Person(“张三”,30)”语句,这实际上就是一个匿名对象,与之前声明的对象不同,此处没有任何栈内存引用它,所以此对象使用一次之后接等待被垃圾收集机制回收。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值