您的位置:首页 > 移动开发 > Android开发

Android Activity

2016-03-09 15:47 309 查看

Android Activity

@(Android学习笔记)[Android]

Android四大组件

Activity

BroadCastReceiver

Service

ContentProvider

Activity

一个Activity是一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务,例如拨号、拍照、发送email、看地图。每一个activity被给予一个窗口,在上面可以绘制用户交互的画面。窗口通常充满屏幕,但也可以小于屏幕而浮于其它窗口之上。

创建Activity

需要在清单文件中为其配置一个activity标签,声明你的activity在manifest文件为了它可以被系统访问。否则如果系统找不到,在显示时会直接报错ActivityNotFoundException。要声明你的activity,打开manifest文件,添加一个activity元素作为application元素的子元素。

<manifest ... >
<application ...>
<activity android:name=".MainActivity" />
<activity android:name=".SecondActivity" />
<activity android:name=".ThirdActivity" />
...
</application...>
...
</manifest>


Activity 在调用的时候实例化,如果manifest没有声明这个activity,但不使用不会报错。

如果Activity所在的包跟应用包名同名,那么可以省略不写。

标签中如果带有这个子节点,则会在系统中创建一个快捷图标

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>


声明入口activity,就会生成快捷图标,可以声明多个入口activity,会产生多个Activity对应的快捷图标。

activity的名称label、图标icon可以和应用程序application节点的名称、图标不相同,但默认使用application节点下的属性

android:icon="@drawable/ic_launcher"
android:label="@string/app_name"


创建步骤:

创建class类继承Activity

创建布局文件,作为Activity的显示内容

在清单文件中注册Activity

Activity的跳转

Activity的跳转需要创建Intent对象,通过设置intent对象的参数指定要跳转的Activity。

通过设置Activity的包名和类名实现跳转,启动同一个应用中的Activity,称为显式意图。

通过指定动作实现跳转,启动不同应用中的Activity,称为隐式意图

显式意图

跳转至同一项目下的另一个Activity,直接指定该Activity的字节码即可

Intent intent = new Intent();
intent.setClass(this, SecondActivity.class);
startActivity(intent);


跳转至其他应用中的Activity,需要指定该应用的包名和该Activity的类名

Intent intent = new Intent();
//启动系统自带的拨号器应用
intent.setClassName("com.android.dialer","com.android.dialer.DialtactsActivity");
startActivity(intent);


隐式意图

例:隐式意图跳转至指定Activity

Intent intent = new Intent();
//启动系统自带的拨号器应用
intent.setAction(Intent.ACTION_DIAL);
startActivity(intent);


要让一个Activity可以被隐式启动,需要在清单文件的activity节点中设置intent-filter子节点

<intent-filter >
<action android:name="com.cskaoyan.second"/>
<data android:scheme="cakaoyan" android:mimeType="aa/bb"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>


action 指定动作(可以自定义,可以使用系统自带的)

data 指定数据(操作什么内容,同时包括URI和数据类型)

category 类别 (默认类别)

对隐式意图设置意图属性:

//[1]创建意图对象   意图就是我要完成一件事
Intent intent = new Intent();
//[2] 设置跳转的动作
intent.setAction("com.chenqiao.testactivity");
//[3] 设置category
intent.addCategory("android.intent.category.DEFAULT");
//[4]设置数据
// intent.setData(Uri.parse("chenqiao:"+110));
//[5]设置数据类型
//intent.setType("aa/bb");
//[6]注意   如果setdata 方法和 settype 方法一起使用的时候  应该使用下面这个方法
intent.setDataAndType(Uri.parse("chenqiao:"+110), "aa/bb");
//[4]开启Activity
startActivity(intent);


对应的activity过滤器设置:

<intent-filter>
<action android:name="com.itheima.testactivity" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="aa/bb" android:scheme="chenqiao" />
</intent-filter>


隐式意图启动Activity,需要为intent设置以上三个属性,且值必须与该Activity在清单文件中对三个属性的定义匹配

intent-filter节点及其子节点都可以同时定义多个,隐式启动时只需与任意一个匹配即可

在启动效率上,隐式远远低于显式

如果系统中存在多个Activity的intent-filter同时与你的intent匹配,那么系统会显示一个对话框,列出所有匹配的Activity,由用户选择启动哪一个。

意图匹配原则:

action行为检测

manifest文件中activity的一个intent-filter元素以子元素的形式列出了行为。例如:

<intent-filter . . . >
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
. . .
</intent-filter>


如同示例所展示的,一个Intent对象只命名一个单独的行为,而一个过滤器可以列出多个行为。列表不能为空;一个过滤器至少要包含一个元素,否则它将屏蔽所有的意图。

要通过这个检测,在Intent对象中指定的行为必须与过滤器所列出的行为之一相匹配。如果该对象或是过滤器没有指定一个行为,就会有下面的结果:

如果过滤器没有列出任何行为,就没有行为可以与意图相匹配,所有的意图都无法通过检测。没有意图可以通过过滤器。

另一方面,如果Intent对象没有指定任何的行为,它将自动通过检测——只要过滤器含有一个或以上的行为。

category类别检测

intent-filter也会将类别作为子元素列出。例如:

<intent-filter . . . >
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
. . .
</intent-filter>


注意之前描述过的表示行为和类型的常量不在mainfest文件中被使用。而是使用完整的字符串值。例如,在范例中的“android.intent.category.BROWSABLE”字符串和文档之前提到的CATEGORY_BROWSABLE常量相对应。类似地,字符串“android.intent.action.EDIT”和ACTION_EDIT常量相对应。

一个意图要通过类别检测,Intent对象中的每一个类别都必须与过滤器中的某个类别相匹配。过滤器可以列出其他更多的类别,但不能省略任何一个意图中含有的类别。

一个不含有类别的Intent对象,无论过滤器中有哪些类别,总是能够通过这项检测。这通常是正确的。

不过,有一个例外,Android把所有传递给startActivity()的隐式意图视为它们包含了至少这样一个类别:“android.intent.category.DEFAULT”(CATEGORY_DEFAULT常量)。因此,要接受隐式意图的活动必须在其意图过滤器中包含有“android.intent.category.DEFAULT”.

data数据检测

如同行为和类别,意图过滤器的的数据类型也是作为子元素保存的。而且和它们一样,这些子元素可以出现多次或完全不出现。

<intent-filter . . . >
<data android:mimeType="video/mpeg" android:scheme="http" . . . />
<data android:mimeType="audio/mpeg" android:scheme="http" . . . />
. . .
</intent-filter>


每一个元素可以指定一个URI和数据类型(MINE媒体类型)。URI的每一个部分由不同的属性——模式(scheme)、主机(host)、接口(port)和路径(path)。scheme://host:port/path

当一个Intent对象中的URI和过滤器中的URI相比较时,仅比较过滤器中所包含的URI部分。例如,如果一个过滤器仅指定了一个模式,那所有具有这个模式的URI就与过滤器相匹配。如果过滤器指定了一个模式及一个授权但是没有指定路径,那么无论是什么路径,具有相同模式和授权的URI将得到匹配。如果过滤器指定了模式、授权和路径,那就只有具有相同模式、授权和路径的URI得到匹配。不过,过滤器中指定的路径可以包含通配符以仅仅限定部分路径。

一个data元素的类型(type)属性指定了数据的MINE类型。在过滤器中这比URI更为常见。Intent对象和过滤器都可以用””通配符作为子类别域来标识子类别匹配,例如“text/”或“audio/*”。

数据检测同时将Intent对象中的URI和数据类型与过滤器中的URI和数据类型相比较。该过程遵循以下规则:

不包含URI和数据类型的Intent对象只有在过滤器也不指定任何URI及数据类型时才能通过检测。

包含URI但不包含数据类型(且数据类型不能通过URI推断出来)的Intent对象>只 有在其URI与过滤器中的URI相匹配且过滤器同样没有指定类型时才能通过检测。这是仅仅在类似mailto:和tel:这样没有指向实际数据的URI时才会出现的情况。

包含数据类型但不包含URI的Intent对象只有在过滤器列出了相同的数据类型而没有指定URI时才能通过检测。

同时包含有URI和数据类型(或URI可以推导出数据类型)的Intent对象在其数据类型与过滤器中列出的类型相匹配时通过检测的数据类型部分。当其URI与过滤器中的URI相匹配,或,其具有一个content:或file:URI并且过滤器没有指定URI时,通过测试的URI部分。换言之,如果过滤器仅列出了数据类型,一个组件将被假定支持content:和file:数据。

Activity生命周期

void onCreate()

Activity已经被创建完毕

void onStart()

Activity已经显示在屏幕,但没有得到焦点

void onResume()

Activity得到焦点,可以与用户交互

void onPause()

Activity失去焦点,无法再与用户交互,但依然可见

void onStop()

Activity不可见,进入后台

void onDestroy()

Activity被销毁

void onRestart()

Activity从不可见变成可见时会执行此方法

Activity生命周期图



内存不足

内存不足时,系统会优先杀死后台Activity所在的进程,都杀光了,如果内存还是不足,那么就会杀死暂停状态的Activity所在的进程,如果还是不够,有可能杀死前台进程

如果有多个后台进程,在选择杀死的目标时,采用最近最少使用算法(LRU)

Activity任务栈

应用运行过程中,内存中可能会打开多个Activity,那么所有打开的Activity都会被保存在Activity任务栈

栈:后进先出,最先进栈,就会最后出栈

Activity的四种启动模式

每个应用会有一个Activity任务栈,存放已启动的Activity

Activity的启动模式,修改任务栈的排列情况

standard 标准启动模式

singleTop 单一顶部模式

如果任务栈的栈顶存在这个要开启的activity,不会重新的创建activity,而是复用已经存在的activity。保证栈顶如果存在,不会重复创建。

应用场景:浏览器的书签

singeTask 单一任务栈,在当前任务栈里面只能有一个实例存在

当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。保证整个任务栈里面只有一个实例存在

应用场景:浏览器的activity

如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。

singleInstance启动模式非常特殊, activity会运行在自己的任务栈里面,并且这个任务栈里面只有一个实例存在

如果你要保证一个activity在整个手机操作系统里面只有一个实例存在,使用singleInstance

应用场景: 电话拨打界面

横竖屏切换

默认情况下 ,横竖屏切换, 销毁当前的activity,重新创建一个新的activity

在一些特殊的应用程序常见下,比如游戏,不希望横竖屏切换activity被销毁重新创建

需求:禁用掉横竖屏切换的生命周期

1.横竖屏写死

android:screenOrientation="landscape"
android:screenOrientation="portrait"


2.让系统的环境,不再去敏感横竖屏的切换。

android:configChanges="orientation|screenSize|keyboardHidden"


Activity切换数据存储

Activity切换时,edittext里面的文字没有了

解决方法

1:给edittext控件加上id,系统会自动保存然后恢复过来

或者在onSaveInstanceState保存,在重新创建的oncreate方法中恢复

2:在AndroidManifest.xml里加入声明

activity android:name=”.MainActivity” android:screenOrientation=”landscape”

3:在AndroidManifest.xml里加入声明

<activity android:name=".MainActivity"android:configChanges="screenSize|orientation"/>


获取通过setData传递的数据

//获取启动此Activity的intent对象
Intent intent = getIntent();
Uri uri = intent.getData();


Activity跳转时的数据传递

Activity通过Intent启动时,可以通过Intent对象携带数据到目标Activity

Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("maleName", maleName);
intent.putExtra("femaleName", femaleName);
startActivity(intent);


在目标Activity中取出数据

Intent intent = getIntent();
String maleName = intent.getStringExtra("maleName");
String femaleName = intent.getStringExtra("femaleName");


Activity返回时传递数据

从A界面打开B界面, B界面关闭的时候,返回一个数据给A界面

步骤:1. 开启activity并且获取返回值

//第一个参数为请求码,即调用startActivityForResult()传递过去的值
//第二个参数为结果码,可以根据业务需求自己编号,结果码用于标识返回数据来自哪个新Activity
startActivityForResult(intent, 0);


在新开启的界面里面实现设置数据的逻辑

Intent data = new Intent();
data.putExtra("phone", phone);
//设置一个结果数据,数据会返回给调用者
setResult(0, data);
finish();//关闭掉当前的activity,才会返回数据


在开启者activity里面实现方法

onActivityResult(int requestCode, int resultCode, Intent data)
//通过data获取返回的数据


根据请求码和结果码确定业务逻辑

请求码:用来区分数据来自于哪一个Activity

结果码:用来区分,返回的数据时属于什么类型

利用Android 提供的Parcelable 传递数据

实现Parcelable步骤

implements Parcelable

重写writeToParcel方法,将你的对象序列化为一个Parcel对象,即:将类的数据写入外部提供的Parcel中,打包需要传递的数据到Parcel容器保存,以便从 Parcel容器获取数据

重写describeContents方法,内容接口描述,默认返回0就可以

实例化静态内部对象CREATOR实现接口Parcelable.Creator

Parcelable的性能比Serializable好,在内存开销方面较小,所以在内存间数据传输时推荐使用Parcelable,如activity间传输数据。

而Serializable可将数据持久化方便保存,所以在需要保存或网络传输数据时选择Serializable,因为android不同版本Parcelable可能不同,所以不推荐使用Parcelable进行数据持久化

Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。而Android的Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。

选择序列化方法的原则

1)在使用内存的时候,Parcelable比Serializable性能高,所以推荐使用Parcelable。

2)Serializable在序列化的时候会产生大量的临时变量,从而引起频繁的GC。

3)Parcelable不能使用在要将数据存储在磁盘上的情况,因为Parcelable不能很好的保证数据的持续性在外界有变化的情况下。尽管Serializable效率低点,但此时还是建议使用Serializable 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: