由于手机端应用的响应,与当时的无线通信网络状况有很大的关联。而通信网络往往具有不稳定,延迟长的特点。所以,在我们的应用程序中,当我们请求网络的时候,超时机制的应用就显得特别重要。
超时机制主要有:
1、HTTP请求超时机制
2、Socket通信超时机制
HTTP请求超时机制
- public static void main(String[] args){
- long a=System.currentTimeMillis();
- try{
- URL myurl = new URL(“http://www.linuxidc.com”);
- URLConnection myurlcon = myurl.openConnection();
- myurlcon.setConnectTimeout(1000);
- myurlcon.setReadTimeout(1000);
- BufferedReader in = new BufferedReader(new InputStreamReader(myurlcon.getInputStream(),”UTF-8″));
- String inputLine;
- while ((inputLine = in.readLine()) != null){
- System.out.println(inputLine);
- in.close();
- System.out.println(System.currentTimeMillis()-a);
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- 如果超时 将 抛出 以下 异常
- java.net.SocketTimeoutException: Read timed out
- at java.net.SocketInputStream.socketRead0(Native Method)
- at java.net.SocketInputStream.read(SocketInputStream.java:129)
- at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
- at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
- at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
- at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:606)
- at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:554)
- at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:940)
- at com.Test.main(Test.java:52)
补充内容:
在Android项目中,如果有用到http请求,就必须也应该加上http请求的超时管理,异常管理,项目中遇到这个需求,google上搜索到了一大堆,但是写的都比较简单,做个demo还行,用在项目中还是不够完善。自己写了一个例子,有不完善之处,欢迎大家指正。
需要注意的地方:有三个方面
如何控制超时机制
如何处理异常
如何处理请求错误的
- private class XmlAsyncLoader extends XmlResourceRequest {
- private boolean mIsCancle = false;
- private HttpGet mGet;
- private HttpClient mHttp;
- public XmlAsyncLoader(MxActivity<?> activity, String url)
- throws MalformedURLException {
- super(activity, url);
- }
- @Override
- protected void doTaskInBackground() {
- // 请求数据
- if (mUrl.toLowerCase().startsWith("http://")) {
- mGet = initHttpGet(mUrl);
- mHttp = initHttp();
- try {
- HttpResponse response = mHttp.execute(mGet);
- if (mIsCancle) {
- return;
- }
- if (response != null) {
- if(response.getStatusLine().getStatusCode()!=HttpStatus.SC_OK){
- onResponseError("network error");
- Log.v(TAG, "the code is :"+response.getStatusLine().getStatusCode());
- return;
- }
- notifyUpdateProgress(70);
- Document doc = getDocumet(response);
- Element root = doc.getDocumentElement();
- NodeList appList = root
- .getElementsByTagName(Item_ELEMENT_NAME);
- final int len = appList.getLength();
- if (len <= 0) {// 没有items
- onFoundNoItems();
- return;
- }
- for (int i = 0; i < len; i++) {
- Element item = (Element) appList.item(i);
- if (item.getNodeType() == Node.ELEMENT_NODE) {
- HahaItemInfo info = createHahaItemIno(item);
- if (mIsCancle){
- return;
- }
- onFoundItem(info, 80 + 20 * (i + 1) / len);
- addUrlToQueue(info.userIconUrl);
- }
- };
- }
- }catch(ConnectTimeoutException e){
- onResponseError("time out");
- } catch (ClientProtocolException e) {
- --mCurrentPage;
- e.printStackTrace();
- } catch (IOException e) {
- --mCurrentPage;
- e.printStackTrace();
- } catch (XmlPullParserException e) {
- --mCurrentPage;
- e.printStackTrace();
- }finally{
- notifyLoadFinish();
- notifyLoadImages();
- mHttp.getConnectionManager().shutdown();
- }
- }
- }
- private HttpClient initHttp() {
- HttpClient client = new DefaultHttpClient();
- client.getParams().setIntParameter(
- HttpConnectionParams.SO_TIMEOUT, TIME_OUT_DELAY); // 超时设置
- client.getParams().setIntParameter(
- HttpConnectionParams.CONNECTION_TIMEOUT, TIME_OUT_DELAY);// 连接超时
- return client;
- }
- private HttpGet initHttpGet(String mUrl) {
- HttpGet get = new HttpGet(mUrl);
- initHeader(get);
- return get;
- }
- @Override
- public boolean tryCancel() {
- Log.i(TAG, "tryCanle is working");
- mGet.abort();
- mIsCancle = true;
- mHttp.getConnectionManager().shutdown();
- notifyLoadFinish();
- return true;
- }
- }
这是一个异步任务类,发送get请求请求数据,解析服务器的响应数据,同时通知ui线程更新ui
在Android中,互联网交互的写法有很多,可以使用apache提供的包,也可以使用google提供的api,我不知道那种更好,只是习惯于使用
apache的api。
1. 设置超时机制
client.getParams().setIntParameter( HttpConnectionParams.SO_TIMEOUT, TIME_OUT_DELAY); // 超时设置 client.getParams().setIntParameter( HttpConnectionParams.CONNECTION_TIMEOUT, TIME_OUT_DELAY);// 连接超时
这里设置了两种超时,第一种是请求超时,第二种时连接超时。
当向服务器发出请求后,请求和服务器建立socket连接,但是很长时间内都没有建立socket连接,这就时第一种请求超时,这种情况主要发生在请求了
一个不存在的服务器。超时之后,会抛出InterruptedIOException异常。
Timeout for blocking operations. The argument value is specified in milliseconds. An InterruptedIOException is thrown if this timeout expires.
客户端已经与服务器建立了socket连接,但是服务器并没有处理客户端的请求,没有相应服务器,这就是第二种连接超时。这中超时会抛出
ConnectTimeoutException异常,ConnectTimeoutException继承自InterruptedIOException,所以只要捕获ConnectTimeoutException 就可以了。
2. 分析一下请求的过程
2.1 HttpResponse response = mHttp.execute(mGet);
执行请求方法,获取服务器响应,(这里有个不太成熟的看法,response不可能为null,还有待验证)。
2.2 获取请求响应码
if(response.getStatusLine().getStatusCode()!=HttpStatus.SC_OK){ onResponseError("network error"); Log.v(TAG, "the code is :"+response.getStatusLine().getStatusCode()); return; }
即使连接上服务器,并且从服务器上获取了数据,也有可能时服务器返回的错误信息,因此也需要特殊处理。
2.3 异常处理
对于异常,不能简单的捕获就完事,例如上面的代码中,我请求第三页的数据,如果发生异常,请求不成功,那么我就需要让当前页数回滚,
如果成功了就不用回滚了,所以需要对异常进行处理
2.4 finally关键字
不管是请求成功,还是失败,都需要关闭链接。
写这例子的初衷是想模仿通讯录列表,实现了一些效果,也没法做到100%相像,自己也认为还有一些不足(存在些内存上的浪费)。
这个阶段先这样了,代码量比较大,就不贴代码了,只上效果图。
源码下载地址:
免费下载地址在 http://linux.linuxidc.com/
用户名与密码都是www.linuxidc.com
具体下载目录在 /2012年资料/1月/26日/Android开发教程:仿通讯录ListView小例子/
效果图如下:
1.实现根据字母进行分类。
2.实现快速滑动及修改快速滑动条的图标。
3.实现快速滑动时的字母提示。
4.实现快捷操作框及其的动画显示/隐藏,上箭头与下箭头的选择性显示及位置匹配。
5.顺便做了个自定义Dialog和完整的发送邮件的实现(主送、抄送、密送、附件、标题、正文)。
部分实现细节介绍:
1.快速滑动时的字母提示框
该显示组件为TextView,实例索引名为txtOverlay,执行WindowManager.addView(txtOverlay, layoutParams)后添加于WindowManager上。通过设置ListView.OnScrollListener监听到滚动时则将 txtOverlay设置可见性为View.VISIBLE,当滚动结束时可见性调为View.INVISIBLE。
为了提升用户体验,避免在短时间内,用户再次拖动时字母提示框又执行显示和隐藏命令,将隐藏的操作设置在DisapearThread线程实例中,通过 handler.postDelayed(disapearThread, 1500)延时1.5秒后再执行字母提示框的隐藏。
2.快速滚动图标的修改
Android Api并未公开修改图标的接口,本处通过调用Java的反射机制修改了快速滚动的图标。替换代码见MainAct类中的changeFastScrollerDrawable()。
补充:Android对ListView设置了优化,对于少于4页内容的List即使设置了fastScrollEnabled=true也不会显示FastScroller。
参考资料查看:<Android_Source>/frameworks/base/core/java/android/widget/FastScroller.java:其中常量MIN_PAGES及其相关。
3.获取List中“咧牙”ImageView在屏幕中的绝对位置
代码如下:anchor为“咧牙”ImageView。
- int[] location = new int[2];
- anchor.getLocationOnScreen(location);
- Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(),
- location[1] + anchor.getHeight());
这个步骤也是为上箭头与下箭头的自动选择做好铺垫。
4.为快捷按钮组成的LinearLayout设置反弹动画
设置LinearLayout沿直线轨迹从从屏幕右边滑动到左边这个部分的动画定义文件是res/anim/anim_actionslayout.xml,代码如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- 本文件指定了actionsLayout的出现动画。 -->
- <!-- translate定义了垂直或水平方向或两者混合的一种运动。 -->
- <!-- formXDelta:赋值为浮点数或百分比。百分号后面'p'表示相对于父控件的相应位置。当只有百分号时表示相对于控件本身的位置。 -->
- <!-- 查看@Android:integer/config_longAnimTime的具体值可于<SDK_PATH>/platforms/<android-level>/data/res/values/config.xml -->
- <translate xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:fromXDelta="100%p"
- Android:toXDelta="0"
- Android:duration="@android:integer/config_longAnimTime"
- ></translate>
需要反弹的效果还得对Animation设定Interpolator(插值器),插值器的设定需要一些数学基础了,得找到合适的函数对动画速率进行修正。本例中使用的插值器代码如下:
- package lab.sodino.list_quickaction;
- import Android.util.Log;
- import Android.view.animation.Interpolator;
- /**
- * @author Sodino E-mail:sodinoopen@hotmail.com
- * @version Time:2011-5-3 下午08:02:01
- */
- public class CustomInterpolator implements Interpolator {
- /**
- * @param input
- * A value between 0 and 1.0 indicating our current point in the
- * animation where 0 represents the start and 1.0 represents the
- * end
- * @return Returns The interpolation value. This value can be more than 1.0
- * for Interpolators which overshoot their targets, or less than 0
- * for Interpolators that undershoot their targets.
- */
- public float getInterpolation(float input) {
- Log.d("Android_LAB", "input=" + input);
- // 设定动画的加速度变化值。此例的效果是使用actionsLayout超过目标旋转区后再反弹回来。
- // 插值计算公式: 1.2-((x*1.55f)-1.1)^2
- // 画出函数图的话即可观察出动画执行过程中越过目标区再反弹的详细过程。
- // x :0 <= v <= 1.0
- // (x*1.55f) :0 <= v <= 1.55
- // ((x*1.55f)-1.1) :-1.1 <= v <= 0.45
- // ((x*1.55f)-1.1)^2 :0<= v <= 1.21
- // 1.2-((x*1.55f)-1.1)^2 :-0.1 <= v <= 1.2
- final float inner = (input * 1.55f) - 1.1f;
- // 如果返回值为常量1的话,则相当于没有动画效果。
- return 1.2f - inner * inner;
- }
- }
ToggleButton常用的XML属性
| 属性名称 | 描述 |
| Android:disabledAlpha | 设置按钮在禁用时透明度。 |
| Android:textOff | 未选中时按钮的文本 |
| Android:textOn | 选中时按钮的文本 |
下面是具体的例子:
第一个例子是通过Toast显示ToggleButton不同的状态时的信息
MainActivity.java
- package com.Android.togglebutton;
- import Android.app.Activity;
- import Android.os.Bundle;
- import Android.view.View;
- import Android.view.View.OnClickListener;
- import Android.widget.Toast;
- import Android.widget.ToggleButton;
- public class MainActivity extends Activity {
- //声明ToggleButton
- private ToggleButton togglebutton;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- togglebutton = (ToggleButton) findViewById(R.id.togglebutton);
- togglebutton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- // 当按钮第一次被点击时候响应的事件
- if (togglebutton.isChecked()) {
- Toast.makeText(MainActivity.this, "你喜欢球类运动", Toast.LENGTH_SHORT).show();
- }
- // 当按钮再次被点击时候响应的事件
- else {
- Toast.makeText(MainActivity.this, "你不喜欢球类运动", Toast.LENGTH_SHORT).show();
- }
- }
- });
- }
- }
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:orientation="vertical"
- Android:layout_width="fill_parent"
- Android:layout_height="fill_parent"
- >
- <TextView
- Android:layout_width="fill_parent"
- Android:layout_height="wrap_content"
- Android:text="@string/hello"
- />
- <ToggleButton
- Android:id="@+id/togglebutton"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:textOn="喜欢"
- Android:textOff="不喜欢"
- />
- </LinearLayout>
strings.xml
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <string name="hello">你喜不喜欢球类运动?</string>
- <string name="app_name">测试ToggleButton</string>
- </resources>
效果图:
第二个例子通过图片的变化显示ToggleButton不同的状态时的图片
MainActivity.java
- package com.Android.togglebutton;
- import Android.app.Activity;
- import Android.os.Bundle;
- import android.widget.CompoundButton;
- import Android.widget.CompoundButton.OnCheckedChangeListener;
- import android.widget.ImageView;
- import Android.widget.ToggleButton;
- public class MainActivity extends Activity {
- //声明ImageView,ToggleButton
- private ImageView imageView;
- private ToggleButton toggleButton;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- //通过findViewById获得ImageView,ToggleButton
- imageView=(ImageView) findViewById(R.id.imageView);
- toggleButton=(ToggleButton)findViewById(R.id.toggleButton);
- toggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener(){
- public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
- toggleButton.setChecked(isChecked);
- //使用三目运算符来响应按钮变换的事件
- imageView.setImageResource(isChecked?R.drawable.pic_on:R.drawable.pic_off);
- }
- });
- }
- }
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- Android:layout_width="fill_parent"
- android:layout_height="fill_parent">
- <ImageView
- Android:id="@+id/imageView"
- Android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- Android:src="@drawable/pic_off"
- android:layout_gravity="center_horizontal"
- />
- <ToggleButton
- Android:id="@+id/toggleButton"
- android:layout_width="130dip"
- Android:layout_height="wrap_content"
- android:textOn="开灯"
- Android:textOff="关灯"
- android:layout_gravity="center_horizontal"
- />
- </LinearLayout>
效果图:
Intent寻找目标组件的两种方式:
- 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的。
- 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间。
一.显式Intent
一般情况下,一个Android应用程序中需要多个屏幕,即是多个Activity类,并且在这些Activity之间进行切换通过Intent机制来实现的。在同一个应用程序中切换Activity时,我们通常都知道要启动的Activity具体是哪一个,因此常用显式的Intent来实现的。
下 面的例子是在同一应用程序中MainActivity启动SecondActivity,下面的代码中,主要是为“转到SecondActivity”按 钮添加了OnClickListener,使得按钮被点击时执行onClick()方法,onClick()方法中则利用了Intent机制,来启动 SecondActivity,关键的代码是22~25行。
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:orientation="vertical"
- Android:layout_width="fill_parent"
- Android:layout_height="fill_parent"
- >
- <TextView
- Android:layout_width="fill_parent"
- Android:layout_height="wrap_content"
- Android:text="@string/hello1"
- />
- <Button
- Android:id="@+id/btn"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:text="转到SecondActivity"
- />
- </LinearLayout>
second.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:orientation="vertical"
- Android:layout_width="fill_parent"
- Android:layout_height="fill_parent"
- >
- <TextView
- Android:layout_width="fill_parent"
- Android:layout_height="wrap_content"
- Android:text="@string/hello2"
- />
- <Button
- Android:id="@+id/secondBtn"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:text="返回"
- />
- </LinearLayout>
MainActivity.java
- package com.Android.test.activity;
- import Android.app.Activity;
- import Android.content.Intent;
- import Android.os.Bundle;
- import Android.view.View;
- import Android.view.View.OnClickListener;
- import Android.widget.Button;
- public class MainActivity extends Activity {
- private Button btn;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btn = (Button)findViewById(R.id.btn);
- //响应按钮btn事件
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //显示方式声明Intent,直接启动SecondActivity
- Intent it = new Intent(MainActivity.this,SecondActivity.class);
- //启动Activity
- startActivity(it);
- }
- });
- }
- }
SecondActivity.java
- package com.Android.test.activity;
- import Android.app.Activity;
- import Android.content.Intent;
- import Android.os.Bundle;
- import Android.view.View;
- import Android.view.View.OnClickListener;
- import Android.widget.Button;
- public class SecondActivity extends Activity {
- private Button secondBtn;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.second);
- secondBtn=(Button)findViewById(R.id.secondBtn);
- //响应按钮secondBtn事件
- secondBtn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //显示方式声明Intent,直接启动MainActivity
- Intent intent = new Intent(SecondActivity.this,MainActivity.class);
- //启动Activity
- startActivity(intent);
- }
- });
- }
- }
AndroidManifest.xml清单文件,16~18行为SecondActivity在清单文件里的声明
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:Android="http://schemas.android.com/apk/res/android"
- package="com.Android.test.activity"
- Android:versionCode="1"
- Android:versionName="1.0">
- <uses-sdk Android:minSdkVersion="10" />
- <application Android:icon="@drawable/icon" android:label="@string/app_name">
- <activity Android:name=".MainActivity"
- Android:label="@string/app_name">
- <intent-filter>
- <action Android:name="android.intent.action.MAIN" />
- <category Android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity Android:name=".SecondActivity"
- Android:label="@string/app_name">
- </activity>
- </application>
- </manifest>
效果图:
二.隐式Intent
下面是同一应用程序中的Activity切换的例子,需要AndroidManifest.xml中增加Activity的声明,并设置对应的Intent Filter和Action,才能被Android的应用程序框架所匹配。
MainActivity.java
- package com.Android.change.activity;
- import Android.app.Activity;
- import Android.content.Intent;
- import android.os.Bundle;
- import Android.view.View;
- import android.view.View.OnClickListener;
- import Android.widget.Button;
- public class MainActivity extends Activity {
- private Button btn;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btn = (Button) findViewById(R.id.btn);
- // 响应按钮btn事件
- btn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // 实例化Intent
- Intent it = new Intent();
- //设置Intent的Action属性
- it.setAction("com.Android.activity.MY_ACTION");
- // 启动Activity
- startActivity(it);
- }
- });
- }
- }
SecondActivity.java
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- Android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- Android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- <Button
- Android:id="@+id/btn"
- android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- android:text="转到SecondActivity"
- />
- </LinearLayout>
seond.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- Android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- Android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- Android:text="@string/second"
- />
- </LinearLayout>
AndroidManifest.xml 文件的18,19行修改了Intent Filter,这样SecondActivity才能够接收到MainActivity发送的Intent。因为在MainActivity的 Intent发送的动作为"com.android.activity.MY_ACTION",而在18行里,SecondActivity设置的 Action也为"com.android.activity.MY_ACTION",这样就能进行匹配。
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:Android="http://schemas.android.com/apk/res/android"
- package="com.android.change.activity"
- Android:versionCode="1"
- android:versionName="1.0">
- <uses-sdk Android:minSdkVersion="10" />
- <application Android:icon="@drawable/icon" android:label="@string/app_name">
- <activity android:name=".MainActivity"
- Android:label="@string/app_name">
- <intent-filter>
- <action Android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity Android:name=".SecondActivity" >
- <intent-filter>
- <action Android:name = "com.android.activity.MY_ACTION" />
- <category android:name = "android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
效果图:
对于显示Intent,Android不 需要再去做解析,因为目标组件很明确。Android需要解析的是隐式Intent,通过解析,将Intent映射给可以处理该Intent的 Activity,Service等。Intent的解析机制主要是通过查找已经注册在AndroidManifest.xml中的所有 IntentFilter以及其中定义的Intent,最终找到匹配的Intent。
BraodcastReceiver(广播接收器)是为了实现系统广播而提供的一种组件,它和事件处理机制类似,但是事件处理机制是程序组件级别的,而广播事件处理机制是系统级别的。比如,我们可以发出一种广播来测试手机电量的变化,这时候就可以定义一个BraodcastReceiver来接受广播,当手机电量较低时提示用户。我们既可以用Intent来启动一个组件,也可以用sendBroadcast()方法发起一个系统级别的事件广播来传递消息。我们同样可以在自己的应用程序中实现BroadcastReceiver来监听和响应广播的Intent。
在程序中使用BraodcastReceiver是比较简单的。首先要定义一个类继承BraodcastReceiver,并且覆盖onReceiver()方法来响应事件。然后注册在程序中BraodcastReceiver。最后构建Intent对象调用sendBroadcast()方法将广播发出。
二.BroadcastReceiver的注册方式
1.静态注册方式
静态注册方式是在AndroidManifest.xml的application里面定义receiver并设置要接收的action。静态注册方式的特点:不管改应用程序是否处于活动状态,都会进行监听,比如某个程序时监听 内存 的使用情况的,当在手机上安装好后,不管改应用程序是处于什么状态,都会执行改监听方法中的内容。
下面是具体的例子:
MainActivity.java
- package com.Android.broadcast;
- import Android.app.Activity;
- import Android.content.Intent;
- import Android.os.Bundle;
- import Android.view.View;
- import Android.view.View.OnClickListener;
- import Android.widget.Button;
- public class MainActivity extends Activity{
- //定义action常量
- protected static final String ACTION = "com.Android.broadcast.RECEIVER_ACTION";
- //定义Button对象
- private Button btnBroadcast;
- @Override
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnBroadcast=(Button)findViewById(R.id.btnBroadcast);
- //为按钮设置单击监听器
- btnBroadcast.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v){
- //实例化Intent
- Intent intent=new Intent();
- //设置Intent的action属性
- intent.setAction(ACTION);
- //发出广播
- sendBroadcast(intent);
- }
- });
- }
- }
在“com.Android.broadcast”包中定义一个MyReceiver类,继承于BroadcastReceiver,覆盖onReceive()方法。
MyReceiver.java
- package com.Android.broadcast;
- import Android.content.BroadcastReceiver;
- import Android.content.Context;
- import Android.content.Intent;
- import Android.util.Log;
- public class MyReceiver extends BroadcastReceiver{
- //定义日志标签
- private static final String TAG = "Test";
- @Override
- public void onReceive(Context context, Intent intent){
- //输出日志信息
- Log.i(TAG, "MyReceiver onReceive--->");
- }
- }
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:orientation="vertical"
- Android:layout_width="fill_parent"
- Android:layout_height="fill_parent"
- >
- <Button
- Android:id="@+id/btnBroadcast"
- Android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- Android:text="发送Broadcast"
- />
- </LinearLayout>
在AndroidManifest.xml配置文件中16~20行声明receiver
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:Android="http://schemas.android.com/apk/res/android"
- package="com.Android.broadcast"
- Android:versionCode="1"
- Android:versionName="1.0">
- <uses-sdk Android:minSdkVersion="10" />
- <application Android:icon="@drawable/icon" android:label="@string/app_name">
- <activity Android:name=".MainActivity"
- Android:label="@string/app_name">
- <intent-filter>
- <action Android:name="android.intent.action.MAIN" />
- <category Android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <receiver Android:name="MyReceiver">
- <intent-filter>
- <action Android:name="com.android.broadcast.RECEIVER_ACTION"/>
- </intent-filter>
- </receiver>
- </application>
- </manifest>
效果图:
当我们点击按钮的时候,程序会调用onReceive()方法,LogCat输出信息如下:
2.动态注册方式
动态注册方式在activity里面调用函数来注册,和静态的内容差不多。一个形参是receiver,另一个是IntentFilter,其中里面是要接收的action。动态注册方式特点:在代码中进行注册后,当应用程序关闭后,就不再进行监听。
下面是具体的例子:
MainActivity.java
- package com.Android.broadcast;
- import Android.app.Activity;
- import Android.content.Intent;
- import android.content.IntentFilter;
- import Android.os.Bundle;
- import android.view.View;
- import Android.view.View.OnClickListener;
- import android.widget.Button;
- public class MainActivity extends Activity{
- //定义Action常量
- protected static final String ACTION = "com.Android.broadcast.RECEIVER_ACTION";
- private Button btnBroadcast;
- private Button registerReceiver;
- private Button unregisterReceiver;
- private MyReceiver receiver;
- @Override
- public void onCreate(Bundle savedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- btnBroadcast=(Button)findViewById(R.id.btnBroadcast);
- //创建事件监听器
- btnBroadcast.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v){
- Intent intent=new Intent();
- intent.setAction(ACTION);
- sendBroadcast(intent);
- }
- });
- registerReceiver=(Button)findViewById(R.id.btnregisterReceiver);
- //创建事件监听器
- registerReceiver.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v){
- receiver=new MyReceiver();
- IntentFilter filter=new IntentFilter();
- filter.addAction(ACTION);
- //动态注册BroadcastReceiver
- registerReceiver(receiver, filter);
- }
- });
- unregisterReceiver=(Button)findViewById(R.id.btnunregisterReceiver);
- //创建事件监听器
- unregisterReceiver.setOnClickListener(new OnClickListener(){
- @Override
- public void onClick(View v){
- //注销BroadcastReceiver
- unregisterReceiver(receiver);
- }
- });
- }
- }
在“com.Android.broadcast”包中定义一个MyReceiver类,继承于BroadcastReceiver,覆盖onReceive()方法。
MyReceiver.java
- package com.Android.broadcast;
- import Android.content.BroadcastReceiver;
- import Android.content.Context;
- import android.content.Intent;
- import Android.util.Log;
- public class MyReceiver extends BroadcastReceiver{
- //定义日志标签
- private static final String TAG = "Test";
- @Override
- public void onReceive(Context context, Intent intent){
- //输出日志信息
- Log.i(TAG, "MyReceiver onReceive--->");
- }
- }
main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- Android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <Button
- Android:id="@+id/btnBroadcast"
- android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- android:text="发送广播"
- />
- <Button
- Android:id="@+id/btnregisterReceiver"
- android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- android:text="注册广播接收器"
- />
- <Button
- Android:id="@+id/btnunregisterReceiver"
- android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- android:text="注销广播接听器"
- />
- </LinearLayout>
效果图:
①当我们首先点击按钮的时候,因为程序没有注册BraodcastReceiver,所以LogCat没有输出任何信息。
②当我们先点击再点击
按钮的时候,这时程序会动态的注册BraodcastReceiver,之后会调用onReceive()方法,LogCat输出信息如下:
③当我们点击按钮的时候,这时程序会注销BraodcastReceiver,再点击
,LogCat没有输出任何信息。
三.BroadcastReceiver 的生命周期
一个BroadcastReceiver 对象只有在被调用onReceive(Context, Intent)的才有效的,当从该函数返回后,该对象就无效的了,结束生命周期。






