Android 4大组件之一Activity
操作方法
- 01
Activity 清单文件: 1、所有的应用程序必须要有清单文件 在manifest节点下需要声明当前应用程序的包名 2、包名:声明包的名字,必须唯一 如果两个应用程序的包名和签名都相同,后安装的会覆盖先安装的 3、声明的程序的组件(4大组件) 其中比较特殊的是广播接收者,可以不在清单文件中配置,可以通过代码进行注册 4、声明程序需要的权限:保护用户的隐私 5、可以控制服务在单独的进程中的,四大组件都可以配置这个属性process 在组件节点配置process: 如:android:process="xxx.ooo.xxx" 比如说:处理图片的时候,会很耗内存,就需要在单独的新的进程中,可以减少内存溢出的几率 启动Activity 通过意图(Intent)来启动一个Activity; 1) 显示启动: 显示启动一般用于自己调用自己的情况(在当前应用找),这样的启动方式比较快速,创建Intent后指定包名和类名; Intent intent = new Intent(this, OtherActivity.class); startActivity(intent); // 启动新的Activity 或者: Intent intent = new Intent(); intent.setClassName("com.itheima.activity", "com.itheima.activity.OtherActivity"); // 包名、全类名 startActivity(intent); // 启动新的Activity 2)隐式启动: 一般用于调用别人的Activity,创建Intent后指定动作和数据以及类型; // 电话 Intent intent = new Intent(); intent.setAction(Intent.ACTION_CALL); // 设置动作 intent.setData(Uri.parse("tel://123456")); // 设置数据 // 网页 intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("http://192.168.1.45:8080/androidWeb")); // 音频/视频,设置type intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"), "audio/*"); // 设置数据和数据类型,将启动音频播放器(vedio) 3)为隐式启动配置意图过滤器: n 显式意图是指在创建意图时指定了组件,而隐式意图则不指定组件,通过动作、类型、数据匹配对应的组件; n 在清单文件中定义<activity>时需要定义<intent-filter>才能被隐式意图启动; n <intent-filter>中至少配置一个<action>和一个<category>,否则无法被启动; n Intent对象中设置的action、category、data在<intent-filter>必须全部包含Activity才能启动; n <intent-filter>中的<action>、<category>、<data>都可以配置多个,Intent对象中不用全部匹配,每样匹配一个即可启动; n 如果一个意图可以匹配多个Activity,Android系统会提示选择; <!-- 注册 Activity, lable 表示Activity的标题 --> <activity android:name="com.itheima.activity.OtherActivity" android:label="OtherActivity" > <!-- 配置隐式意图,匹配http --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <!—必须,表示动作为View --> <data android:scheme="http" /> <!—http开头--> <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动时,默认匹配 --> </intent-filter> <!-- 匹配tel --> <intent-filter> <action android:name="android.intent.action.CALL" /> <data android:scheme="tel" /> <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动 --> </intent-filter> <!-- 匹配 音频、视频 --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <data android:scheme="file" android:mimeType="audio/*" /> <!—文件协议l类型 --> <data android:scheme="file" android:mimeType="video/*" /> <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动 --> </intent-filter> </activity> 3、启动时传递数据 可通过意图Intent对象实现Activity之间的数据传递; 使用Intent.putExtra()方法装入一些数据, 被启动的Activity可在 onCreate方法中getIntent()获取; 可传输的数据类型: a.基本数据类型(数组), b. String(数组), c. Bundle(Map), d. Serializable(Bean), e.Parcelable(放在内存一个共享空间里); 基本类型: Intent intent = new Intent(this, OtherActivity.class); intent.putExtra("name", "张飞"); // 携带数据 intent.putExtra("age", 12); startActivity(intent); 一捆数据: Intent intent = new Intent(this, OtherActivity.class); Bundle b1 = new Bundle(); b1.putString("name", "赵云"); b1.putInt("age", 25); Bundle b2 = new Bundle(); b2.putString("name", "关羽"); b2.putInt("age", 44); intent.putExtra("b1", b1); intent.putExtra("b2", b2); 序列化对象(须实现序列化接口): Intent intent = new Intent(this, OtherActivity.class); Person p = new Person("张辽", 44); intent.putExtra("p", p); 接收数据: 在OtherActivity 的onCreate()方法,通过 getIntent().get 相关的数据的方法来获取数据; 4、关闭时返回数据 基本流程: l 使用startActivityForResult(Intent intent, int requestCode) 方法打开Activity; l 重写onActivityResult(int requestCode, int resultCode, Intent data) 方法; l 新Activity中调用setResult(int resultCode, Intent data) 设置返回数据之后,关闭Activity就会调用上面的onActivityResult方法; 注意:新的Activity的启动模式不能设置成 singleTask(如果已创建,会使用以前创建的)与singleInstance(单例,单独的任务栈), 不能被摧毁(执行不到finish方法),父Activity中的 onActivityResult方法将不会执行; finish():表示关闭当前Activity,会调用onDestroy方法; Activity_A: public void openActivityB(View v) { Intent intent = new Intent(this, Activity_B.class); Person p = new Person("张辽", 44); intent.putExtra("p", p); startActivityForResult(intent, 100); // 此方法,启动新的Activity,等待返回结果, 结果一旦返回,自动执行onActivityResult()方法 } protected void onActivityResult(int requestCode, int resultCode, Intent data) { if(data == null) { // 没有数据,不执行 return; } System.out.println(requestCode + ", " + resultCode); // code 可用来区分,哪里返回的数据 String name = data.getStringExtra("name"); int age = data.getIntExtra("age", -1); } Activity_B: public void close(View v) { // == 关闭当前Activity时,设置返回的数据 == Intent intent = new Intent(); intent.putExtra("name", "典韦"); intent.putExtra("age", 55); setResult(200, intent); finish(); // 关闭,类似于点击了后退 } 5、生命周期 1)Acitivity三种状态 a. 运行:activity在最前端运行; b. 停止:activity不可见,完全被覆盖; c. 暂停:activity可见,但前端还有其他activity<>,注意:在当前Activitiiy弹出的对话框是Activity的一部分,弹出时,不会执行onPause方法; 2)生命周期相关的方法(都是系统自动调用,都以 on 开头): a. onCreate: 创建时调用,或者程序在暂停、停止状态下被杀死之后重新打开时也会调用; b. onStart: onCreate之后或者从停止状态恢复时调用; c. onResume: onStart之后或者从暂停状态恢复时调用,从停止状态恢复时由于调用onStart,也会调用onResume(界面获得焦点); d. onPause: 进入暂停、停止状态,或者销毁时会调用(界面失去焦点); e. onStop: 进入停止状态,或者销毁时会调用; f. onDestroy: 销毁时调用; g. onRestart: 从停止状态恢复时调用; 3)生命周期图解: 应用启动时,执行onCreate onStart onResume,退出时执行:onPause onStop onDestroy; 6、横竖屏切换与信息的保存恢复 切换横竖屏时,会自动查找layout-port 、layout-land中的布局文件,默认情况下, 切换时,将执行摧毁onPause onStop onDestroy,再重置加载新的布局onCreate onStart onResume; 切换时如果要保存数据, 可以重写: onSaveInstanceState(); 恢复数据时, 重写: onRestoreInstanceState(); è固定横屏或竖屏: android:screenOrientation="landscape" è横竖屏切换, 不摧毁界面(程序继续执行) android:configChanges="orientation|keyboardHidden|screenSize" 保存信息状态的相关方法: a. onSaveInstanceState: 在Activity被动的摧毁或停止的时候调用(如横竖屏切换,来电),用于保存运行数据,可以将数据存在在Bundle中; b. onRestoreInstanceState: 该方法在Activity被重新绘制的时候调用,例如改变屏幕方向,onSavedInstanceState可为onSaveInstanceState保存的数据 7、启动模式 1)任务栈的概念 问:一个手机里面有多少个任务栈? 答:一般情况下,有多少个应用正在运行,就对应开启多少个任务栈; 一般情况下,每开启一个应用程序就会创建一个与之对应的任务栈; 二般情况下,如launchMode为 singleInstance,就创建自己单独的任务栈; 2)任务栈的作用: 它是存放Activity的引用的,Activity不同的启动模式,对应不同的任务栈的存放; 可通过getTaskId()来获取任务栈的ID,如果前面的任务栈已经清空,新开的任务栈ID+1,是自动增长的; 3)启动模式: 在AndroidManifest.xml中的<activity>标签中可以配置android:launchMode属性,用来控制Actvity的启动模式; 在Android系统中我们创建的Acitivity是以栈的形式呈现的: ①、standard:默认的,每次调用startActivity()启动时都会创建一个新的Activity放在栈顶; ②、singleTop:启动Activity时,指定Activity不在任务栈栈顶就创建,如在栈顶,则不会创建,会调用onNewInstance(),复用已经存在的实例 ③、singleTask:在任务栈里面只允许一个实例,如果启动的Activity不存在就创建,如果存在直接跳转到指定的Activity所在位置, 如:栈内有ABCD,D想创建A, 即A上的BCD相应的Activity将移除; ④、singleInstance:(单例)开启一个新的任务栈来存放这个Activity的实例,在整个手机操作系统里面只有一个该任务栈的实例存在,此模式开启的Activity是运行在自己单独的任务栈中的; 4)应用程序、进程、任务栈的区别 ①、应用程序: 四大组件的集合 在清单文件中都放在application节点下 对于终端用户而言,会将其理解为activity ②、进程: 操作系统分配的独立的内存空间,一般情况下,一个应用程序会对应一个进程,特殊情况下,会有多个进程 一个应用程序会对应一个或多个进程 ③、任务栈:task stack(back stack)后退栈 记录用户的操作步骤,维护用户的操作体验, 专门针对于activity而言的,只用于activity 一般使用standard,其他情况用别的 5)启动模式的演示 1、创建两个activity,布局中设置两个按钮,分别开启两个activity 第一、standard启动模式的:开启几个就会在任务栈中存在几个任务 01和02都是存在于一个任务栈中的 第二、在清单文件中将02的启动模式改为singletop, 此时02处于栈顶,就只会创建一个02的任务,再开启02,也不会创建新的 第三、将02的启动模式改为singletask 如果02上面有其他任务栈,就会将其他的清除掉,利用这个已经创建的02 当开启02的时候,即先将01清除,然后利用下面的02 第四、将02的启动模式改为singleinstance 可以通过打印任务栈的id(调用getTaskId()方法)得知,两个activity不在同一个任务栈中 若先开启三个01,在开启02,任务栈如图: 再开启01,任务栈的示意图如下: 此时按返回键,会先一层一层清空01,最后再清空02 空进程:任务栈清空,意味着程序退出了,但进程留着,这个就是空进程,容易被系统回收; 8、内存管理 Android系统在运行多个进程时,如果系统资源不足,会强制结束一些进程,优先选择哪个进程来结束是有优先级的。 会按照以下顺序杀死: ①、空: 进程中没有任何组件; ②、后台:进程中只有停止状态的Activity; ③、服务:进程中有正在运行的服务; ④、可见:进程中有一个暂停状态的Activity; ⑤、前台:进程中正在运行一个Activity; Activity在退出的时候进程不会销毁, 会保留一个空进程方便以后启动. 但在内存不足时进程会被销毁; Activity中不要在Activity做耗时的操作, 因为Activity切换到后台之后(Activity停止了), 内存不足时, 也容易被销毁;