适当stop和restart你的Activity对于确保用户的数据没有丢失是很重要的,下面是几个需要stop和restart一个Activity的情况:
- 用户打开最近使用窗口并且切换到其他app,这个Activity被stop,如果用户点击app icon或者从最近使用里返回app,Activity restart
- 从当前Activity打开另一个Activity,当前Activity在另一个Activity被创建时stop,当用户点返回键时,Activity restart
- 用户接电话时
与paused状态不同,stopped的状态下Activity完全不可见,用户焦点完全在另一个Activity或另一个App的Activity
Note: 因为系统会在内存中保持Activity实例,所以一般app不用实现onStop或者onRestart方法,甚至onStart方法,因为大多app比较简单,可能只实现onPause方法处理一些资源或者数据即可
Stop你的Activity当接收到onStop方法调用时,Activity不再可见,应该释放几乎所有不需要使用的资源,一旦Activity stop,如果系统需要回收系统能存,可能销毁实例,极端情况下,系统可能连onDestroy都不调用而直接杀掉进程,所以使用onStop方法处理会导致内存泄露的资源非常重要
即使onPause在onStop之前调用,也应该在onStop中处理更复杂,更耗CPU的操作,像写入数据库等
例如,下面例子像持久存储写入一个草稿
@Override protected void onStop() { super.onStop(); // Always call the superclass method first // Save the note's current draft, because the activity is stopping // and we want to be sure the current note progress isn't lost. ContentValues values = new ContentValues(); values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText()); values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle()); getContentResolver().update( mUri, // The URI for the note to update. values, // The map of column names and new values to apply to them. null, // No SELECT criteria are used. null // No WHERE columns are used. ); }
Activity处在stopped状态时,Activity对象会保持在内存中,不需要重新初始化resumed状态之前初始化的组件,系统也会跟踪布局中View的状态,所以如果在EditText中有输入也不必保存
Note: 即使系统在stopped状态下destroy你的Activity,View的状态仍然被保存在一个Bundle中,当用户再次回到这个Activity事例时还会存在
Start/Restart你的Activity当Activity从stopped状态到前台来,接到onRestart方法调用,系统也会调用onStart方法,因为每次Activity变得可见时系统都会调用onStart方法,无论创建还是restart,onRestart方法只是在stopped状态resume时才调用,所以可以在在其中执行一些特殊的恢复操作,例如用户长时间离开后,在onStart方法中确保系统状态是否可以是再好不过的了
@Override protected void onStart() { super.onStart(); // Always call the superclass method first // The activity is either being restarted or started for the first time // so this is where we should make sure that GPS is enabled LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean gpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); if (!gpsEnabled) { // Create a dialog here that requests the user to enable GPS, and use an intent // with the android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS action // to take the user to the Settings screen to enable GPS when they click "OK" } } @Override protected void onRestart() { super.onRestart(); // Always call the superclass method first // Activity being restarted from stopped state }
因为多数资源在onStop方法中释放,所以一般不用实现onDestroy方法,但也要确保所有可能导致内存泄露的资源已经被释放
第九章 结构体和共用体
一、结构体
由一系列具有相同类型或不同类型的的数据构成的数据集合(但不能包含函数类型)
1.定义
1)第一种形式
struct 结构体类型名 { 数据类型名1 成员名1; ......... 数据类型名2 成员名2; }; struct 结构体类型名 变量名列表;
2)第二种形式
struct 结构体类型名 { 数据类型名1 成员名1; ......... 数据类型名2 成员名2; }变量名列表;
注意:
结构体的成员也可以是一个结构体变量
C语言允许对两个相同类型的结构体变量之间进行整体赋值,但不允许整体输出;
2.指向结构体的指针
struct 结构名 * 结构指针变量名;
3.访问成员
结构体变量名 . 成员名 或 (*结构体指针变量).成员名
4.结构体与函数
1)结构体变量和结构体指针变量作为函数返回值
struct struct_function(void); struct * struct_function(void);
第一个返回的是结构体对象
当返回值为结构体变量时,是将返回的结构体初始化
第二个返回的是结构体指针(速度比较快)
当返回值为结构体指针变量时,初始化函数返回指针变量时是修改内存中的一个结构体变量的值,并将该结构体变量的初始地址返回
2)结构体变量和结构体指针变量作为函数形式参数
struct struct_funtion(struct struct_pm,...); struct * struct_funtion(struct * pstruct_pm,.....);
A)形参为结构体变量
当结构体变量作为形参时,在调用该函数时,首先复制整个结构体形成结构体副本,然后对副本进行修改,但并没有修改原来的结构体,再将副本作为返回值返回
B)形参为结构体变量指针
当结构体指针作为形参时,在调用该函数时首先复制的是该结构体的地址,形成一个地址副本,然后使用这个地址副本对其指向的结构体变量进行修改,最后将地址副本作为返回值
二、共用体
共用体用来描述类型不同的数据,与结构体不同的是:共用体对成员存储时采用覆盖技术,共享存储空间,成员被分配在同一段内存空间中。成员既可以具有相同的数据类型,也可以具有不同的数据类型
1、定义
union 共用体名 { 数据类型 成员名1; 数据类型 成员名2; ......... 数据类型 成员名3; };
2、共用体与结构体的比较:
1)相同的定义方式
2)引用成员的方式也一样
3)共用体变量所占的内存长度等于其成员变量中所占存储空间最大的那个,而结构体变量其所占的内存长度等于其成员变量所占内存之和(不考虑内存对齐)
struct { char i; float f; }sum; //定义一个结构体变量sum
union { char i; float f; }max; //定义一个共用体变量
3、共用体的初始化
初始化共用体变量,只需初始化第一个成员
错误的初始化方法:
union mark { int score //表示分数 char degree[4]; //表示等级 } liming = {90,"优"}; //出错
正确的初始化方法
union mark { int score //表示分数 char degree[4]; //表示等级 } liming = {90};
4、注意事项:
1)共用体存放的是最后一次存放成员的值
max.i = 100; max.f = 123.123;
执行完上面两条语句后,只有max.f有效,max.i 已经没有意义了
2)共用体变量的地址和各个成员的地址都是同一个地址值
3)不能把共用体变量用作函数参数和函数返回值,但可以使用指向共用体变量的指针
三、枚举
一种将变量可能取值明确列举出来,变量的取值只限于列举出来的常量。
enum 枚举名{枚举值表}; enum 枚举名 变量名列表;
eunm meta_color{ red, green, blue };
enum meta_color{red, green = 20, blue};
四、自定义类型 typedef
并不是用户自己定义的一种新的数据类型,而是用户根据自己的具体需要给某种数据类型重新命名
1.定义
//typedef 类型名 标识符 struct pts { int x; int y; }; typedef struct pts Point;
typedef 实质上是对现有数据类型的另一种说明,并没有增加新的数据类型
2、typedef和define的不同:
1)typedef只针对数据类型,不针对值,define既可以针对数据类型,也可以针对值。
2)typedef是对一种已有数据类型的彻底“封装”,在声明之后不能再往里面添加任何代码,而define只是简单的文本替代
3、typedef的主要作用;
1)使用typedef有利于程序的移植和跨平台开发
typedef unsigned int size_t;
在所有的计算机平台中,没有哪一种类型是最佳的选择,因此给出了一种新的数据类型size_t,让具体的实现者来这个类型名定义为特定的类型。size_t定义在头文件time.h中
2)使用typedef可以简化代码
一、函数形参–指针参数和数组参数的区别
- 作为函数形参的数组和指针可以互换
- 这种转换仅限于函数形参的声明
例子:以下3个声明是等价的
void putValues(int *);
void putValues(int[]);
void putValues(int[10]);
备注:数组长度不是参数类型的一部分。函数和编译器都不知道传统给它的数组的长度的大小。
- 传入指定长度数组的一种简便方法
二、默认参数值
- 默认参数值是一种在大多数情况下都适用的值。
- 函数声明可为全部或者部分参数提供默认值。
- 函数调用的实参按位置解析,默认参数只能用来替换函数调用缺少的尾部实参。
- 一个参数只能在一个文件里被指定一次默认实参。函数后续的声明中可以指定其他默认参数。可以在函数声明和定义处定义默认参数值。
- 默认参数可以用任意表达式指定。
例如:
---------------------ff1.h-----------------------------
intff(int a, int b,int c=0);
--------------------ff2.h------------------------------
#include “ff1.h”
intgetValue();
intff(int a, int b =getValue(), c);
--------------------ff2.cpp------------------------------
#include “ff2.h”
intff(int a=0, int b,int c)
{
}
三、可选形参