1.获取被开启的的Activity的返回值
步骤:
1.调用系统提供的startActivityForResult(Intent intent,int requestCode)方法打开指定的Activity,这样新的Activity关闭会向前面的Activity返回数据.
2.得到返回数据,在前面的Activity中复写onActivityResult(int requestCode, int resultCode, Intent data)方法.
public void selectContact(View view) {
Intent intent = new Intent(this, SelectContactActivity.class);
// 开启一个新的activity
// startActivity(intent);
// 开启一个新的activity 并且获取这个新开启的activity执行完毕后返回的结果
startActivityForResult(intent, 1);
}
//当新开启的activity 关闭的时候 调用的方法.
//第一个参数为请求码,即调用startActivityForResult()传递过去的值
//第二个参数为结果码,结果码用于标识返回数据来自哪个新Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
System.out.println("onActivityResult");
if (data != null) {
String number = data.getStringExtra("number");
if (requestCode == 1) {
et_number.setText(number);
}else if(requestCode==2){
et_number2.setText(number);
}
}
super.onActivityResult(requestCode, resultCode, data);
}
新的Activity返回数据:
//传递数据给调用他的activity
Intent data = new Intent();
data.putExtra("number", number);
setResult(100, data);
//关闭当前的activity 然后传递数据给 调用者 调用者就会执行 onactivityResult的方法
请求码的作用:
使用startActivityForResult(Intent intent, int requestCode)方法打开新的Activity,我们需要为startActivityForResult()方法传入一个请求码(第二个参数)。请求码的值是根据业务需要由自已设定,用于标识请求来源。例如:一个Activity有两个按钮,点击这两个按钮都会打开同一个Activity,不管是那个按钮打开新Activity,当这个新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。在onActivityResult()方法如果需要知道新Activity是由那个按钮打开的,并且要做出相应的业务处理,这时可以这样做:
public void onCreate(Bundle savedInstanceState) {
....
button1.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 1);
}});
button2.setOnClickListener(new View.OnClickListener(){
public void onClick(View v) {
startActivityForResult (new Intent(MainActivity.this, NewActivity.class), 2);
}});
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode){
case 1:
//来自按钮1的请求,作相应业务处理
case 2:
//来自按钮2的请求,作相应业务处理
}
}
}
结果码的作用:
在一个Activity中,可能会使用startActivityForResult()方法打开多个不同的Activity处理不同的业务,当这些新Activity关闭后,系统都会调用前面Activity的onActivityResult(int requestCode, int resultCode, Intent data)方法。为了知道返回的数据来自于哪个新Activity,在onActivityResult()方法中可以这样做(ResultActivity和NewActivity为要打开的新Activity)
public class ResultActivity extends Activity {
.....
ResultActivity.this.setResult(1, intent);
ResultActivity.this.finish();
}
public class NewActivity extends Activity {
......
NewActivity.this.setResult(2, intent);
NewActivity.this.finish();
}
public class MainActivity extends Activity { // 在该Activity会打开ResultActivity和NewActivity
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(resultCode){
case 1:
// ResultActivity的返回数据
case 2:
// NewActivity的返回数据
}
}
}
2.广播接收者
广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收,这个特性跟JMS中的Topic消息接收者类似。要实现一个广播接收者方法如下:
第一步:继承BroadcastReceiver,并重写onReceive()方法。
public class IncomingSMSReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
第二步:订阅感兴趣的广播Intent,在AndroidManifest.xml文件中的<application>节点里进行订阅:
<receiver android:name=".IncomingSMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
利用广播实现ip拨号
写一个类继承BroadcastReceiver,覆写onReceive方法:
public class OutCallReceiver extends BroadcastReceiver {
//当有广播事件产生的时候 就会执行onrecevie方法
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("onreceiver 发现了新的外拨电话...");
String number = getResultData();//外拨的电话号码
System.out.println("number="+number);
//替换掉这个号码
SharedPreferences sp = context.getSharedPreferences("config", Context.MODE_PRIVATE);
String ipnumber = sp.getString("ipnumber", "");
String newnumber = ipnumber+number;
//设置外拨的电话号码
setResultData(newnumber);
//不会生效的 广播终止不了 显示的指定了接受者
abortBroadcast();
}
}
在AndroidManifest.xml文件中的<application>节点里进行配置:
<receiver android:name=".SmsReceiver" >
<intent-filter android:priority="1000" ><!-- 设置优先级 -->
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
abortBroadcast();此方法被调用之后,广播会被中止
利用广播实现短信的拦截
pdus”即可从Intent中获取到短信内容。
public class SmsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("短信收到了...");
//在intent中得到短信的相关数据
Object[] pdus = (Object[]) intent.getExtras().get("pdus");
for (Object pdu : pdus) {
//利用相关api将每一条短信的数据转化为SmsMessage对象
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
//得到短信的各种属性
String body = smsMessage.getMessageBody();
String sender = smsMessage.getOriginatingAddress();
System.out.println("body:" + body);
System.out.println("sender:" + sender);
if ("5556".equals(sender)) {
// 短信的拦截,终止广播,其他的广播接收不到
abortBroadcast();
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(sender, null, "我已经喜欢上 xxx了 ,你去死吧", null, null);
}
}
}
}
在AndroidManifest.xml文件中的<application>节点里对接收到短信的广播Intent进行订阅:
<receiver android:name=".SmsReceiver">
<intent-filter android:priority="1000"><!-- 设置优先级为最高 -->
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
在AndroidManifest.xml文件中添加以下权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/><!-- 接收短信权限 -->
<uses-permission android:name="android.permission.SEND_SMS"/><!-- 发送短信权限 -->
自定义广播事件
测试代码,第一步,首先创建一个用于接收广播的客户端:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("reveriver 1 接收到了广播");
Toast.makeText(context, "检查到了 自定义的广播事件", 1).show();
}
}
在AndroidManifest中配置订阅相关的广播:
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter android:priority="1000">
<action android:name="com.itheima.xxxooo" >
</action>
</intent-filter>
</receiver>
第二步,创建一个用于发送广播的客户端:
public void click(View view){
Intent intent = new Intent();
intent.setAction("com.itheima.xxxooo");
//把这个自定义的广播发送出去
//sendBroadcast(intent); //发送一条无序的广播事件
//如果广播事件是无序发送出去的 所有的广播接受者 都会接受到这个事件
//如果广播是有序的发送出去的, 广播接收者会按照优先级 接受到广播事件
// 有序广播 特点: 高优先级的广播接受者 可以终止掉 广播事件
//sendOrderedBroadcast(intent, null);
sendOrderedBroadcast(intent, null, new FinalRecevier(), null, 0, null, null);
}
FinalRecevier.java
public class FinalRecevier extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("我是final的receiver");
}
}
3.Service
Android中的服务和windows中的服务是类似的东西,服务一般没有用户操作界面,它运行于系统中不容易被用户发觉,可以使用它开发如监控之类的程序。服务的开发比较简单,如下:
第一步:继承Service类
public class SMSService extends Service { }
第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
<service android:name=".SMSService" />
服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。使用startService()方法启用服务,访问者与服务之间没有关连,即使访问者退出了,服务仍然运行。使用bindService()方法启用服务,访问者与服务绑定在了一起,访问者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
startService()方法启动服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。
电话监听器
1.新建一个类继承Service,实现监听的相关方法
public class PhoneStatusService extends Service {
/**
* 长期在后台运行的组件,如果用户不手动的关闭 , 不会停止的.
*/
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
super.onCreate();
System.out.println("服务被创建了 ");
// 监视用户电话状态的变化...
// 电话管理器 电话管理的服务
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
// 监听手机的通话状态的变化
tm.listen(new MyPhoneStatusLinstener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
private class MyPhoneStatusLinstener extends PhoneStateListener {
private MediaRecorder recorder;
@Override
public void onCallStateChanged(int state, String incomingNumber) {
try {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // 空闲状态 ,没有通话 没有响铃
if (recorder != null) {
recorder.stop();
recorder.reset(); // You can reuse the object by going back
recorder.release(); // Now the object cannot be reused
recorder = null;
}
break;
case TelephonyManager.CALL_STATE_RINGING: // 响铃状态.
System.out.println("发现来电号码 :" + incomingNumber);
// 1.创建出来一个录音机
recorder = new MediaRecorder();
// 设置录制的音频源 从话筒里面获取声音
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置输出文件格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//设置音频编码
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile("/sdcard/" + System.currentTimeMillis()
+ ".3gp");
recorder.prepare();
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // 通话状态
if (recorder != null) {
recorder.start(); // Recording is now started
}
break;
}
} catch (Exception e) {
e.printStackTrace();
}
super.onCallStateChanged(state, incomingNumber);
}
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("服务被销毁了...");
}
}
2.在AndroidManifest中的application注册服务
<application
... >
<activity
...
</activity>
<service android:name=".PhoneStatusService"></service>
</application>
3.在ManiActivity中开启服务
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//开启服务
Intent intent = new Intent(this,PhoneStatusService.class);
startService(intent);
}
}
服务的生命周期
1.当采用Context.startService()方法启动服务,与之有关的生命周期方法
onCreate()-->onStart()-->onDestroy()
onCreate()该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startService()或bindService()方法,服务也只被创建一次。
onStart() 只有采用Context.startService()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startService()方法尽管不会多次创建服务,但onStart() 方法会被多次调用。
onDestroy()该方法在服务被终止时调用。
2.当采用Context.bindService()方法启动服务,与之有关的生命周期方法
onCreate()-->onBind()-->onUnbind()-->onDestroy()
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。
onUnbind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
如果先采用startService()方法启动服务,然后调用bindService()方法绑定到服务,再调用unbindService()方法解除绑定,最后调用bindService()方法再次绑定到服务,触发的生命周期方法如下:
onCreate()-->onStart()-->onBind()-->onUnbind()[重载后的方法需返回true]-->onRebind()
安卓进程优先级->为什么要采用服务
应用程序:一组组件(Activity Service Provider Receiver)的集合
一般情况一个应用程序会对应一个进程,当这个应用被关闭的时候(关闭掉所有的界面,关闭所有的Activity),应用程序的进行是不会被关闭掉的,仍然在后台长期运行。
这是Google采用的一组策略,帮助我们自动的管理进程。
进程,按照优先级分为不同的等级:
1.前台进程 用户可以看到这个进程里面的某个Activity的界面,可以操作这个界面
2.可见进程 用户仍然可以看到这个进程里面的某个Activity的界面,但是不可以操作这个界面
3.服务进程 如果一个应用程序有一个服务在后台运行,那么所在的进程就是服务进程
4.后台进程 没有任何服务的进行,打开一个Activity之后,按了home键最小化
5.空进程 没有任何活动组件存在的进程
当安卓系统内存不足的时候,系统会释放一部分进程的内存,是按优先级来释放的,从低到高。而服务进程都是比较稳定的,基本上不会因为内在不足而被释放掉,就算是释放掉,在一定的时间段之内,也会被重新开启。
绑定方式开启服务&调用服务的方法
使用bindService()方法启用服务,调用者与服务绑定在一起了,调用者一旦退出,服务也就自动终止。
1)启动流程:
如果调用前服务没有被创建,则会引起onCreate()->onBind();
如果已被创建但没有被绑定,则会引起onBind();
如果服务已被绑定,则多次调用bindService并不会引起onCreate()和onBind()被多次调用。
2)结束方式:
调用者退出,系统会自动调用服务到onUnbind()->onDestroy()方法。
如果调用者希望与正在绑定的服务解除绑定,可以调用Context.unbindService(),该方法会导致系统调用服务的onUnbind()-->onDestroy()方法。
示例代码:(春哥唱歌)
服务类:
package com.itheima.testservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
/**
* 在后台长期运行的组件 唱歌
* @author Administrator
*
*/
public class CungeService extends Service {
@Override
public IBinder onBind(Intent intent) {
System.out.println(" onBind 春哥服务被成功的绑定了....");
//步骤2: 服务在成功绑定的时候 会调用onbind方法 返回一个ibinder对象.
//返回自定义的代理人对象
MyBinder mybinder = new MyBinder();
System.out.println(mybinder.toString());
return mybinder;
}
private class MyBinder extends Binder implements IService{
//间接的利用代理人 调用了春哥的方法
public void callChangeSing(String name){
changeSing(name);
}
public void peiCungeWatchTV(){
}
public void peiCungeCountMoney(){
}
}
@Override
public void onCreate() {
super.onCreate();
System.out.println("onCreate 服务开始了 ,春哥 开始唱歌");
}
/**
* 更改唱的歌曲
* @param singName
*/
public void changeSing(String singName){
Toast.makeText(getApplicationContext(), "开始唱"+singName, 0).show();
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("onunbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("onDestroy 服务销毁了 ,春哥停止唱歌");
}
}
MainActivity类
package com.itheima.testservice;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
public class MainActivity extends Activity {
//步骤4: 在activity里面得到服务 ibinder对象的引用.
private IService myBinder;
private MyConn conn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/**
* 开启服务
*
* @param view
*/
public void start(View view) {
Intent intent = new Intent(this, CungeService.class);
// 采用api 创建 服务 ,服务对象是被系统(框架 )new 出来
startService(intent);
}
/**
* 停止服务
*/
public void stop(View view) {
Intent intent = new Intent(this, CungeService.class);
stopService(intent);
}
public void bind(View view){
Intent intent = new Intent(this, CungeService.class);
//intent 激活服务的意图
// conn 代理人 中间人对象 用来跟服务建立联系 不能为空
// BIND_AUTO_CREATE 在绑定服务的时候 如果服务不存在 就自动的创建
//步骤1: 采用绑定服务的方式 开启服务
conn = new MyConn();
bindService(intent,conn , BIND_AUTO_CREATE);
}
//接触绑定服务的方法
public void unbind(View view){
unbindService(conn);
}
@Override
protected void onDestroy() {
try{
unbindService(conn);
}catch (Exception e) {
}
super.onDestroy();
}
private class MyConn implements ServiceConnection{
// 在服务被成功绑定的时候 调用的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("春哥把代理人返回回来了...");
//步骤3: 服务返回的ibinder对象 会被传递给 MyConn 的回调方法
System.out.println(service);
myBinder = (IService) service;
}
// 在服务失去绑定的时候 调用的方法 只有程序异常 终止,
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
/**
* 调用服务里面的方法 ,换首歌
*/
public void change(View view) {
// 由于系统框架在创建服务的时候 会创建与之对应的上下文,
// 下面的代码 是直接new对象 .
// CungeService service = new CungeService();
// service.changeSing("月亮之上");
//步骤5: 利用ibinder 对象 间接的调用了服务里面的方法
myBinder.callChangeSing("月亮之上");
}
}
IService类
package com.itheima.testservice;
//春哥代理人的接口
public interface IService {
public void callChangeSing(String name);
}
bindService() 绑定服务 可以得到服务的代理人对象,间接调用服务里面的方法.
绑定服务: 间接调用服务里面的方法.
如果调用者activity被销毁了, 服务也会跟着销毁
(不求同时生,但求同时挂)
开启服务: 不可以调用服务里面的方法.
如果调用者activity退出了, 服务还会长期的在后台运行
生命周期:
1.单独调用
startService() - oncreate
stopService() ondestroy
-----------------------------------
bind ->oncreate -> onbind
unbind -> onunbind ->ondestroy
服务只能被解绑一次,多次的解除绑定服务 应用程序会报错.
2.混合调用.
需求: 既要保证服务长期的在后台运行,又想去调用服务里面的方法.
技巧: 1.先开启服务 2.绑定服务.
步骤:1.开启服务 startService()- oncreate();
2.绑定服务 bindService() - onbind();
3.关闭程序 ,调用者退出, 服务被解绑.
4.stopService() 停止服务.
注:解除绑定只能调用一次,否则会出现异常