作者:韩亚飞_yue31313_韩梦飞沙 QQ:313134555
day06 多线程&Handler类&四大组件之:Activity
Ø 多线程下载及断点续传
一、RandomAccessFile类:io包下(用于多线程下载)
随机访问文件:
作用:可以读文件也能写文件
seek()向指定位置读和写
void seek(long pos)
设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。
setLength(大小)设定一个文件的初始大小
writeLong(long):用于一个比较大的字节大小的写入,方便记录下载的指针.
mode:rws:表示不用缓存,直接写入放硬盘,且包括元数据
rwd:也是直接写入硬盘,但是不包括元数据
元数据就是一些版本信息,摘要之类
二、多线程下载
(一) 定义及作用:
同时给服务器发送多个下载请求,下载速度快--受带宽制约
(二) 运用原理:
就是首先获得整个文件大小,创建出一个同等大小的本地空文件
再把这个数据用字节分成几部分,让几个线程去下载,比如300k 那么可以让一个线程下0-100k,第二个线程下100-200k..全部存入本地同样大小的文件中
从哪个字节下的,就从文件里哪个字节的位置去存.用RandomAccessFile流的seek()方法
(三) 怎么用?
1获取下载地址URL
2.通过截取URL创建本地文件File
3.获得HttpURLConnection对象用URL
4.获得网络数据大小:总长度length
5.计算每个线程要下载的长度:总长 /线程个数
6.设制输出流
7.设制一个空文件一样大,关闭流
8.建立多个线程,遍历,设id
9.设制每个线程的下载的开始位置和结束位置
10.给每个线程定义HttpURLConnection连接,并设制请求头
conn设制请求行:setRequestProperty("Range","开始长度,结束长度")
11.获取返回的输入流
12.将流用RandomAccessFile流的seek()方法下载到文件
13.用一个boolean变量实现暂停
三、断点续传
(一)定义及作用:
就是停止正在下载的资源,下次再次下载时,将会接上上次未下载的位置,继续下载
(二) 实现原理:
有下载,就可能会暂停,为了暂停能够接着下载,这个时候就用到断点续传.
实现原理就是把每次下载的数据的长度,存入一个本地临时文件,然后下次开下载时,
都先判断是否有本地文件,有的话开始的起始位置从文件中读取.这样就实现了
(三) 怎么用?
得到网络地址URL
创建本地文件
创建临时文件
创建下载方法
获取连接
计算总长和每个线程下载长度
作一个判断临时文件存在否,没有就创建一个,多少个线程写入几个0,
是用long存的,所以每个线程长度都有8个字节,所以每次seek到第几个线程*8的位置读出数据long
下载的时候,每往硬盘里存多少数据,就把数据长度加到临时文件中对应的线程long上
每次下载读开始长度都是读临时文件里的long
实时下载了的文件长度要同步,就是计算总共下载了多少时,因为有多个线程去操作这个数据
通过定义一段时间去判断这个时间内总数据的变化去计算下载速度
(四)进度条:ProgressBar
可用style去选择样式
定义一个id
在Activity中获取ProgressBar对象
设最大刻度方法:setMax(文件总长度)int参数
设当前进度:setProgress(实时下载长度)int参数
Ø Handler类
一、定义及作用.
是一个安卓下的一个类,主要用于接受子线程发送的数据, 并用此数据配合主线程更新UI.
因为子线程中不能操作主线程视图,也就是只有创建view的线程才能修改线程,
很多情况是主线程中有view,而数据在新线程中,新线程把数据发送到主线程,主线程接收数据操作View
注:ProgressBar是一个例外:只有这个才可以在新线程中操作主线程中的ProgressBar
二、怎么用:
方式一:通过Message类
1.在子线程中发数据:子线程用到的Handler和主线程为同一个
Message ms = new Message();//建立Message对象
ms.what=1;//给message设一个标识,看情况可以选择要不要
Bundle bd = ms.getData();//用其getData方法获得Bundle对象
bd.putInt("num", num);//添加数据:可以是putString等基本类型,及实现序列化的对象等
或者:用ms.obj=num;直接绑定数据对象.,这样就不用bundle去绑定了.
handler.sendMessage(ms);//发送消息
在主线程中接收数据,重写其handleMessage方法
关于what:这是一个Message的int成员变量,用于区分传过来的message做不同处理
因为message传过来都是执行Handler的HandlerMessage方法,无法区分是哪个message
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Bundle bd =msg.getData();
int num = bd.getInt("num");
tv.setText(num + "");
break;
case 2:
Bundle bd1 = msg.getData();
String s =bd1.getString("s");
tv1.setText(s);
break;
}
}
};
注:如果message是绑定obj过来的,则可直接获得对象,强转成对应的对象就行
intnum=(Integer)msg.obj;
方式二:通过Handler的post方法
不适合操作费时久的代码,因为这个并没有开启一个新线程处理这些代码,只是把代码发给主线程去处理.
1. 发数据:原理是把这段代码用Handler发给主线程去运行
handler.post(new Runnable() {
public void run() {
try {
image1.setImageBitmap(service.getBitmap(wb
.getPortrait()));
} catch (Exception e) {
e.printStackTrace();
}
}
});
2. 接数据:只要在主线程是创建一个Handler对象就可以了
Handler handler = new Handler();
应用一: 避免ANR(无响应)异常
1. ANR是什么?
Application Not Response 应用程序无响应
Android中主线程 (“事件处理线程” / “UI线程”) 在5秒内没有响应输入事件
或BroadcastReceiver没有在10秒内完成返回就会抛出这个异常.
ANRs (“Application Not Responding”),意思是”应用没有响应“。
这个异常应该尽量避免,不然影响用户体验.
2. 容易出现ANR异常的操作
1、在主线程内进行网络操作
2、在主线程内进行一些缓慢的磁盘操作(例如执行没有优化过的SQL查询)
3. 解决方法:用Handler
1.所有可以把耗时代码创建新线程去执行
2.如果与主线程有数据传递,就用handler传递给主线程.这样界面层就不会卡
3.防止连续操作---弹出对话框:
ProgressDialog类 set对话框方式 setMessage信息 设置setCancelable--显示show
// 创建一个ProgressDialog对象
progressDialog = new ProgressDialog(this);
updateThread thread = new updateThread();
// 设制Dialog样式:以下表示进度条
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
// 设制对话框内容
progressDialog.setMessage("请稍等......");
// 设制对话框标题
progressDialog.setTitle("下载数据中");
// 设制进度初始值与最大值
progressDialog.setProgress(0);
progressDialog.setMax(100);
// 设制进度条是否能取消
progressDialog.setCancelable(false);
// 让进度条显示
progressDialog.show();
效果如下:
Ø Activity--四大组件之活动Activity
一、定义及作用:
Activity是Android最重要的组件之一,是一个活动界面,用于提供一个屏幕或窗口.
在这个窗口上用户可以绘制各种各样的View,用户可以通过与窗口来交互.来完成某项任务,例如拨号、拍照、发送email、看地图。每一个activity被给予一个窗口,在上面可以绘制用户接口。窗口通常充满屏幕,但也可以小于屏幕而浮于其它窗口之上。
一个应用说白了就是多个Activity组成.
二、怎么用?
(一)创建一个Activity的步骤
Ÿ 定义类继承Activity
Ÿ 在AndroidManifest.xml的<application>节点中声明<activity>
<activity
android:name=".ActivitydemoActivity"
android:label="@string/app_name" >
...............
</activity>
(二)通过显式意图Intent对象操作Activity
通常用于应用程序内部跳转
1. 创建意图对象
显式意图三种创建方式
① 构造函数,代码少
new Intent(this, NewActivity.class);
② 类名形式,灵活,可扩展性强
intent.setClassName(this, "cn.itcast.activity.NewActivity");
③ 包名类名形式,可启动其他程序中的Activity
第一个参数是应用名,第二个参数是表示应用是哪个Activity
intent.setClassName("cn.itcast.downloader", "cn.itcast.downloader.MainActivity");
2. 通过意图对象启动新的Activity
startActivity(intent);
startActivityForResult(intent, 响应码);
注:以上两个方法都是通过Context,也就是当前Activity的上下文环境调用的
(三)通过隐式意图Intent对象操作Activity
常用于多个程序之间跳转.
① 获取意图对象
Intent intent = new Intent();
② 设制意图动作类型
如果Intent请求中没有设定Action类型,那么只要<intent-filter>中包含有Action类型,这个Intent请求就将顺利地通过<intent-filter>的行为测试。
intent.setAction("android.intent.action.CALL");
③ 设置类别
intent.addCategory(WIFI_SERVICE);
④ 传递数据或(数据和类型)-数据需不需要就要看需求
intent.setData(Uri.parse("tel://18600012345"));
可以同时指定数据和数据类型
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/1.mp4"), "video/*");
⑤ 启动新的Activity
设备中所有完全匹配Intent设置的属性的应用,都会响应,具体用哪个执行,会弹出给你选择
startActivity(intent);
startActivityForResult(intent, 响应码);
⑥ 常用的隐式意图
1,打开web浏览器
Uri myBlogUri =Uri.parse("http://kuikui.iteye.com");
returnIt = new Intent(Intent.ACTION_VIEW,myBlogUri);
2,地图
Uri mapUri =Uri.parse("geo:38.899533,-77.036476");
returnIt = new Intent(Intent.ACTION_VIEW,mapUri);
3,调拨打电话界面
Uri telUri =Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_DIAL,telUri);
4,直接拨打电话
Uri callUri = Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_CALL,callUri);
5,卸载
Uri uninstallUri =Uri.fromParts("package", "xxx", null);
returnIt = new Intent(Intent.ACTION_DELETE,uninstallUri);
6,安装
Uri installUri =Uri.fromParts("package", "xxx", null);
returnIt = newIntent(Intent.ACTION_PACKAGE_ADDED, installUri);
7,播放
Uri playUri =Uri.parse("file:///sdcard/download/everything.mp3");
returnIt = new Intent(Intent.ACTION_VIEW,playUri);
播放音频
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/Adele - Rolling in the Deep.mp3"), "audio/*");
播放视频
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/1.mp4"), "video/*");
显示图片
intent.setAction("android.intent.action.VIEW");
intent.setDataAndType(Uri.parse("file:///mnt/sdcard/9.jpg"), "image/*");
8,掉用发邮件
Uri emailUri =Uri.parse("mailto:shenrenkui@gmail.com");
returnIt = new Intent(Intent.ACTION_SENDTO,emailUri);
9,发邮件
returnIt = new Intent(Intent.ACTION_SEND);
String[] tos = {"shenrenkui@gmail.com" };
String[] ccs = {"shenrenkui@gmail.com" };
returnIt.putExtra(Intent.EXTRA_EMAIL, tos);
returnIt.putExtra(Intent.EXTRA_CC, ccs);
returnIt.putExtra(Intent.EXTRA_TEXT,"body");
returnIt.putExtra(Intent.EXTRA_SUBJECT,"subject");
returnIt.setType("message/rfc882");
Intent.createChooser(returnIt, "ChooseEmail Client");
10,发短信
Uri smsUri =Uri.parse("tel:100861");
returnIt = new Intent(Intent.ACTION_VIEW,smsUri);
returnIt.putExtra("sms_body","shenrenkui");
returnIt.setType("vnd.android-dir/mms-sms");
11,直接发邮件
Uri smsToUri =Uri.parse("smsto://100861");
returnIt = new Intent(Intent.ACTION_SENDTO,smsToUri);
returnIt.putExtra("sms_body","shenrenkui");
12,发彩信
Uri mmsUri =Uri.parse("content://media/external/images/media/23");
returnIt = new Intent(Intent.ACTION_SEND);
returnIt.putExtra("sms_body","shenrenkui");
returnIt.putExtra(Intent.EXTRA_STREAM,mmsUri);
returnIt.setType("image/png");
用获取到的Intent直接调用startActivity(returnIt)就ok了。
(四)声名Activity的用法:通过配置IntentFilter意图过滤器
隐式意图通常包含动作及数据,只要一个Activity中的IntentFilter定义了这个动作类型,那么相应的Activity便会响应.
每一个应用程序创建的时候Android SDK都默认配了一个IntentFilter,用于表示应用程序打开时,启动哪个Activity.
如果想让一个Activity还能响应其它的意图.就要在给Activity定义额外的IntentFilter,
如果一个组件没有intent filter, 那么它只能接受显式intent
如何定义IntentFilter
1. 在Activity标签内定义
<activity
android:name=".ActivitydemoActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"
< data android:type=" audio/ mpeg"android:scheme=" http" .../ >
</intent-filter>
</activity>
2. IntentFilter的action(动作)元素:
表示一个动作,用一个字符串表示:必须唯一,intent通过setAction来设置.当设置的动作名称与这个匹配时,这个Activity启动
或者,对于 broadcase intents 来说,表示正在发生,并且被报告的动作。
这个元素一定要有,否则任何Intent请求都不能和该<intent-filter>匹配
系统自带的一些Action有:
Android为我们定义了一套标准动作:
① 标准的Activity Actions
ACTION_MAIN 作为一个主要的进入口,而并不期望去接受数据
ACTION_VIEW 向用户去显示数据
ACTION_ATTACH_DATA 别用于指定一些数据应该附属于一些其他的地方,例如,图片数据应该附属于联系人
ACTION_EDIT 访问已给的数据,提供明确的可编辑
ACTION_PICK 从数据中选择一个子项目,并返回你所选中的项目
ACTION_CHOOSER 显示一个activity选择器,允许用户在进程之前选择他们想要的
ACTION_GET_CONTENT 允许用户选择特殊种类的数据,并返回(特殊种类的数据:照一张相片或录一段音)
ACTION_DIAL 拨打一个指定的号码,显示一个带有号码的用户界面,允许用户去启动呼叫
ACTION_CALL 根据指定的数据执行一次呼叫
(ACTION_CALL在应用中启动一次呼叫有缺陷,多数应用ACTION_DIAL,ACTION_CALL不能用在紧急呼叫上,紧急呼叫可以用ACTION_DIAL来实现)
ACTION_SEND 传递数据,被传送的数据没有指定,接收的action请求用户发数据
ACTION_SENDTO 发送一跳信息到指定的某人
ACTION_ANSWER 处理一个打进电话呼叫
ACTION_INSERT 插入一条空项目到已给的容器
ACTION_DELETE 从容器中删除已给的数据
ACTION_RUN 运行数据,无论怎么
ACTION_SYNC 同步执行一个数据
ACTION_PICK_ACTIVITY 为已知的Intent选择一个Activity,返回别选中的类
ACTION_SEARCH 执行一次搜索
ACTION_WEB_SEARCH 执行一次web搜索
ACTION_FACTORY_TEST 工场测试的主要进入点,
标准的广播Actions
ACTION_TIME_TICK 当前时间改变,每分钟都发送,不能通过组件声明来接收,只有通过Context.registerReceiver()方法来注册
ACTION_TIME_CHANGED 时间被设置
ACTION_TIMEZONE_CHANGED 时间区改变
② 自定义Action
你也可以定义自己的action strings 来激活组件。自定义的action应该包含包名作为前缀: 例如"com.example.project.SHOW_COLOR".
Action 很大程度上决定 Intent余下部分的结构。 ---- 特别是:data 和 extras 两个字段。就像一个方法的方法名通常决定了方法的参数和返回值。 基于这个原因,应该给action 命名一个尽可能明确的名字。 可以通过 setAction() 设置action,通过 getAction()进行获取.
3. IntentFilter的category(类型)元素:
可选:只有当Intent请求中所有的Category与组件中某一个IntentFilter的<category>完全匹配时,才会 让该 Intent请求通过测试,IntentFilter中多余的<category>声明并不会导致匹配失败。一个没有指定任何类别测试的 IntentFilter仅仅只会匹配没有设置类别的Intent请求。
Intent有,则IntentFilter必须有,Intent没有,则IntentFilter必须没有
使用 android:category 属性用来指定在什么样的环境下动作才被响应。每个 Intent Filter 标签可以包含多个 category 标签。你可以指定自定义的种类或使用 Android 提供的标准值,如下所示:
CATEGORY_BROWSABLE | 目标activity可以使用浏览器来显示-例如图片或电子邮件消息. |
CATEGORY_GADGET | 该activity可以被包含在另外一个装载小工具的activity中. |
CATEGORY_HOME | 该activity显示主屏幕,也就是用户按下Home键看到的界面. |
CATEGORY_LAUNCHER | 该activity可以作为一个任务的第一个activity,并且列在应用程序启动器中. |
CATEGORY_PREFERENCE | 该activity是一个选项面板. |
❑ ALTERNATIVE
你将在这章的后面所看到的,一个 Intent Filter 的用途是使用动作来帮忙填入上下文菜单。 ALTERNATIVE 种类指定,在某种数据类型的项目上可以替代默认执行的动作。例如,一个联系人的默认动作时浏览它,替代的可能是去编辑或删除它。
❑ SELECTED_ALTERNATIVE
与 ALTERNATIVE 类似,但 ALTERNATIVE 总是使用下面所述的 Intent 解析来指向单一的动作。SELECTED_ALTERNATIVE在需要一个可能性列表时使用。
❑ BROWSABLE
指定在浏览器中的动作。当Intent 在浏览器中被引发,都会被指定成 BROWSABLE 种类。
❑ DEFAULT
设置这个种类来让组件成为Intent Filter 中定义的 data 的默认动作。这对使用显式 Intent 启动的 Activity 来说也是必要的。
❑ GADGET
通过设置 GADGET 种类,你可以指定这个 Activity 可以嵌入到其他的 Activity 来允许。
❑ HOME
HOME Activity 是设备启动(登陆屏幕)时显示的第一个 Activity 。通过指定 Intent Filter 为 HOME 种类而不指定动作的话,你正在将其设为本地 home 画面的替代。
❑ LAUNCHER
使用这个种类来让一个Activity 作为应用程序的启动项
intent中常用到的方法:
addCategory() 添加一个 category
removeCategory() 删除一个 category()
getCategorys() 获取所有的category()
4. IntentFile标签:data元素(可选):
有两个属性:minetype表示文件类型, scheme表示接收什么类型的URL
data android:mimeType="audio/mpeg" android:scheme="http" . . . />
每个<data>元素指定一个URI和数据类型(MIME类型)。它有四个属性scheme、host、port、path对应于URI的每个部分:
scheme://host:port/path
例如,下面的URI:
content://com.example.project:200/folder/subfolder/etc
scheme是content,host是"com.example.project",port是200,path是"folder/subfolder/etc"。host和port一起构成URI的凭据(authority),如果host没有指定,port也被忽略。
这四个属性都是可选的,但它们之间并不都是完全独立的。要让authority有意义,scheme必须也要指定。要让path有意义,scheme和authority也都必须要指定。
Scheme属性匹配规则:
当比较intent对象和过滤器的URI时,仅仅比较过滤器中出现的URI属性。
例如,如果一个过滤器仅指定了scheme,所有有此scheme的URIs都匹配过滤器;
如果一个过滤器指定了scheme和authority,但没有指定path,所有匹配scheme和authority的URIs都通过检测,而不管它们的path;
如果四个属性都指定了,要都匹配才能算是匹配。然而,过滤器中的path可以包含通配符来要求匹配path中的一部分。
<data>元素的type属性指定数据的MIME类型。Intent对象和过滤器都可以用"*"通配符匹配子类型字段,例如"text/*","audio/*"表示任何子类型。
数据检测既要检测URI,也要检测数据类型。规则如下:
是以Intent为准:意思是Intent有,IntentFilter必须有,没有的,则IntentFilter也必须没有.
· 一个Intent对象既不包含URI,也不包含数据类型:仅当过滤器也不指定任何URIs和数据类型时,才能通过检测;否则都不能通过。
· 一个Intent对象包含URI,但不包含数据类型:仅当过滤器也不指定数据类型,同时它们的URI匹配,才能通过检测。例如,mailto:和tel:都不指定实际数据。
· 一个Intent对象包含数据类型,但不包含URI:仅当过滤也只包含数据类型且与Intent相同,才通过检测。
· 一个Intent对象既包含URI,也包含数据类型(或数据类型能够从URI推断出):数据类型部分,只有与过滤器中之一匹配才算通过;URI部分,它的URI要出现在过滤器中,或者它有content:或file: URI,又或者过滤器没有指定URI。换句话说,如果它的过滤器仅列出了数据类型,组件假定支持content:和file:。
如果一个Intent能够通过不止一个活动或服务的过滤器,用户可能会被问那个组件被激活。如果没有目标找到,会产生一个异常。
3.2、通用情况
上面最后一条规则表明组件能够从文件或内容提供者获取本地数据。因此,它们的过滤器仅列出数据类型且不必明确指出content:和file: scheme的名字。这是一种典型的情况,一个<data>元素像下面这样:
<dataandroid:mimeType="image/*"/>
告诉Android这个组件能够从内容提供者获取image数据并显示它。因为大部分可用数据由内容提供者(content provider)分发,过滤器指定一个数据类型但没有指定URI或许最通用。
另一种通用配置是过滤器指定一个scheme和一个数据类型。例如,一个<data>元素像下面这样:
<dataandroid:scheme="http"android:type="video/*"/>
Intent 中常用的方法:
setData() 方法:设置一个 datatype.--注:只能设置URI,
setType() :设置MIMEtype,
setDataAndType() :可以对二者都进行设置, 获取URI 和 data type 可分别调用 getData() 和 getType() 方法。
Launcher是Android的应用程序启动器
5. Extras
为键-值对形式的附加信息. 例如ACTION_TIMEZONE_CHANGED的intent有一个"time-zone"附加信息来指明新的时区, 而ACTION_HEADSET_PLUG有一个"state"附加信息来指示耳机是被插入还是被拔出.
intent对象有一系列put...()和set...()方法来设定和获取附加信息. 这些方法和Bundle对象很像. 事实上附加信息可以使用putExtras()和getExtras()作为Bundle来读和写.
6. Flags
有各种各样的标志,许多指示Android系统如何去启动一个活动(例如,活动应该属于那个任务)和启动之后如何对待它(例如,它是否属于最近的活动列表)。所有这些标志都定义在Intent类中。
(五)用意图实现Activity之间数据的传递
不同的Activity之间数据的交换通过Intent对象传递的
1. Intent能放的数据类型
8种数据类型及数组字符串 bundle 实现序列化接口的对象(原理是把对象先序列化成了字节数组,传过去后又反序列化成对象去使用,所以其实是内容相同的两个不同对象).Parcelable 邮包化
2. 发送数据
1.Intent直接用put设置数据,类似于一个map 但不同的是这里的key可以有相同
Intent.putExtra(key,content).
在另一个Activity中getIntent()获得intent对象,再用这个intent去获取数据
intent.getStringExtra(key);
getIntExtra(key,默认值);--也可以设默认值,就是没数据值默认是什么.
2Bundle类设置数据.用于绑定两个数据
创建Bundle对象
Bundle bundle1 = new Bundle();
bundle1.putString("name","张三");
bundle1.putInt("age", 18);
Bundle bundle2 = new Bundle();
bundle2.putString("name","李四");
bundle2.putInt("age", 19);
再把Bundle对象添加入BundleIntent.putExtra(key,value);
intent.putExtra("bundle1",bundle1);
intent.putExtra("bundle2",bundle2);
3用对象传数据
用putExtra(key,对象)
得到对象:用getSerialzbleExtra(key);
小技巧:可以把多个对象装入一个集合或数组,再序列化
3. Intent数据的获取
获取Intent对象
Intent intent = getIntent();
get数据类型Extra(key,默认值(可有可无));
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", -1);
4. 结果数据的返还
① 在Activity中创建意图
Intent intent = new Intent(this,OtherActivity.class);
intent.putExtra("name", "张三");
intent.putExtra("age", 18);
② 用startActivityForResult启动新Activity
startActivityForResult(intent, 100); // 启动一个Activity, 等待返回结果
③ 在打开的新Activity中创建Intent对象
④ 把对象用setResult方法设置数据返回
⑤ setResult(200,装有数据的intent对象)
⑥ 执行finish()关闭方法,返回数据
⑦ finish()后会把数据返回
⑧ 原Activity自动执行onActivityForResult方法获得Intent
当前Activity启动的新Activity关闭时,就会自动启动执行onActivityForResult(请求码,响应码,intent)
protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) {
................................................................................................................................................
}
⑨ 从Intent中提取数据
intent.getStringExtra("name") ;
intent.getIntExtra("age", -1);
5. Intent请求码,与响应码
请求码用于区分一个Activity中,启动多个startActivityForResult的intent
因为当前Activity是可能会启动多个Activity,
使用startActivityForResult(Intentintent, int requestCode)方法打开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。例如:一个Activity有两个按钮,点击这两个按钮都会打开同一个Activity,不管是那个按钮打开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode,int resultCode, Intent data)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮打开的,并且要做出相应的业务处理
响应码用于区分多个新开的Activity同时关闭时
在一个Activity中,可能会使用startActivityForResult()方法打开多个不同的Activity处理不同的业务,当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode,int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新Activity,就在setResult方法中.加上请求码.
(六)手动销毁一个Activity
finish();
finishActivity(requestCode);
三、什么时候用?
当需要把数据在手机上呈现给用户时
四、有什么特点?
(一)Acitivity三种状态
运行:activity在最前端运行
停止:activity不可见,完全被覆盖
暂停:activity可见,但前端还有其他acti vity
(二)横束屏切换
1. 会销毁Activity后重建:
也就是会执行onPuase()--onStop()--onDistroy-onCtreate-onStart()--onResume()
但如果在manifest中配置如下:则不会销毁重键
<activity
android:configChanges="orientation"/>,则不会销毁
2. 在切换前会执行Activity中的这个方法,可以用于保存数据,比如游戏的时候
protected void onSaveInstanceState(BundleoutState) {
super.onSaveInstanceState(outState);
System.out.println("onSaveInstanceState");
outState.putString("data", "销毁前存储的数据!!!");
}
3. 在切换后会执行Activity中的这个方法,可以用于获得数据
这个Bundle与上面是同一个 ,在上面存,在这里就可以取
protected voidonRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
System.out.println("onRestoreInstanceState");
System.out.println(savedInstanceState.getString("data"));
}
注:以上两个方法,如果Activity正常退出,不会执行.
(三)生命周期及相关方法
onCreate:创建时调用,或者程序在暂停、停止状态下被杀死之后重新打开时也会调用
onStart:onCreate之后或者从停止状态恢复时调用
onResume:onStart之后或者从暂停状态恢复时调用,从停止状态恢复时由于调用onStart,也会调用onResume
onPause:进入暂停、停止状态,或者销毁时会调用
onStop:进入停止状态,或者销毁时会调用
onDestroy:销毁时调用
onRestart:从停止状态恢复时调用
一个应用程序通常由多个activities组成,他们通常是松耦合关系。通常,一个应用程序中的activity被指定为"main"activity,当第一次启动应用程序的时候呈现给用户的那个activity。每一个activity然后可以启动另一个activity为了完成不同的动作。每一次一个activity启动,前一个activity就停止了,但是系统保留activity在一个栈上(“back stack”)。当一个新activity启动,它被推送到栈顶,取得用户焦点。Back Stack符合简单“后进先出”原则,所以,当用户完成当前activity然后点击back按钮,它被弹出栈(并且被摧毁),然后之前的activity恢复。
当一个activity因新的activity启动而停止,它被通知这种状态转变通过activity的生命周期回调函数。有许多回调函数一个activity可能会收到,源于它自己的状态变化-无论系统创建它、停止它、恢复它、摧毁它-并且每个回调提供你完成适合这个状态的指定工作的机会。例如,当停止的时候,你的activity应该释放任何大的对象,例如网络数据库连接。当activity恢复,你可以重新获得必要的资源和恢复被中断的动作。这些状态转换都是activity的生命周期的部分。
(四)启动模式
Ÿ 在AndroidManifest.xml中的<activity>标签中可以配置android:launchMode属性,用来控制Actvity的启动模式
Ÿ 在Android系统中我们创建的Acitivity是以栈的形式呈现的,
Ÿ 每个应用都有独立的任务栈Task.一个栈中可以有多个Activity.
启动另一个应用的Activity,会把那个应用的栈也移到前面,(栈里面可能还有这个应用的其它的Activity)
standard:每次调用startActivity()启动时都会创建一个新的Activity放在栈顶
注:默认都是这个模式
singleTop:启动Activity时,指定Activity不在栈顶就创建,如在栈顶,则不再创建
注:不会出现两个相同的Activity相邻
singleTask:如果启动的Activity不存在就创建Activity,如果存在直接跳转到指定的Activity所在位置
注:在其上面的Activity会被移出栈,也就是一个栈中不能有重复的Activity
singleInstance:如果启动的Activity不存在就创建一个Activity同时创建一个栈,如果存在就将指定的Activity存在的栈移动到栈顶
注:表示这个Activity只能存在于一个独立的任务栈中,同应用的其它Activity与其无关.
<activity
android:name=".EnterPasswrodActivity"
//表示这个Activity不会存在于近期任务中
android:excludeFromRecents="true" android:launchMode="singleInstance" >
</activity>
(五)内存管理
Ÿ Android系统在运行多个进程时,如果系统资源不足,会强制结束一些进程。优先选择哪个进程来结束是有优先级的。
空:进程中所有Activity都已销毁--进程最容易销毁
后台:进程中有一个停止状态的Activity
可见:进程中有一个暂停状态的Activity
前台:进程中正在运行一个Activity