7.安卓基础之activity生命周期&receiver广播接收者

1. Activity

Android中的第一个核心的组件,每次创建一个工程,都会创建一个默认的MainActivity.

  • onCreate 在创建对象的时候调用
    Activity启动后第一个被调用的函数,常用来进行Activity的初始化,例如创建View/绑定数据或恢复信息等.

  • onDestory 在对象销毁的时候调用
    在Activity被终止前,即进入非活动状态前,该函数被调用.

  • onStart 在界面可见的时候被调用
    当Activity显示在屏幕时,该函数被调用.

  • onStop 在界面不可见的时候被调用
    当Activity进入停止状态时,该函数被调用.

  • onPause 当界面处于可见,但是又失去焦点这个阶段的时候会被调用
    当Activity进入暂停状态时,该函数被调用.一般用来保持持久的数据或释放占用的资源.

  • onReumse 当界面处于可见到获得焦点这段时间被调用
    当Activity被终止时,即进入非活动状态时,该函数被调用.

1.1 生命周期之记事本的应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class MainActivity extends AppCompatActivity {
private EditText ed_content;
SharedPreferences sp;
//创建时调用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ed_content = (EditText) findViewById(R.id.ed_content);
sp = getSharedPreferences("config",0);
String v1 = sp.getString("content","");
ed_content.setText(v1);
}
//当销毁时调用
@Override
protected void onDestroy() {
super.onDestroy();
String content = ed_content.getText().toString().trim();
SharedPreferences.Editor edit = sp.edit();
edit.putString("content",content);
edit.commit();
Toast.makeText(this,"已默认保存!",0).show();
}
}

1.2 生命周期之格斗小游戏的应用

  • AndroidManifest.xml
    如果配置了这个属性,当我们横竖屏切换的时候会直接调用onCreate方法中的onConfigurationChanged方法,而不会重新执行onCreate方法,那当然如果不配置这个属性的话就会重新调用onCreate方法了.
    1
    <activity android:name=".MainActivity" android:configChanges="keyboardHidden|orientation|screenSize">

默认的情况下,一个activity声明周期在横竖屏切换的时候,会销毁当前的activity,然后去重新创建一个activity.所以在当前游戏中,会影响到用户的感受.

2. Activity的启动模式

Task : 任务,维护记录了当前应用的内存空间中,有哪些组件在运行着.
Stack : 栈,栈的特点(后进先出),队列(先进先出)

  • 启动模式(lauchMode)有四种 :
    • standard : 标准的模式,也是默认模式.
      每次收到intent,那么就会新创建activity的实例出来,放到任务栈中.
    • singleTop : 单一顶部模式
      如果发现当前的任务栈中的栈顶是当前activity实例,那么就直接使用当前的activity实例,不再创建.(源生的mms编辑短信activity启动模式是singleTop,为了提高用户感受,可以很好的提示用户之前的短信还没有编辑完)
    • singleTask : 单一任务模式
      表示当前的activity只会在当前任务栈中创建一个实例.如果再次去尝试启动之前的activity时候,当前的activity不是处于任务栈的栈顶,会清空当前处于activity之上的activity.(如果一个activity启动的时候,占用的CPU资源非常多,非常耗内存.而手机中的内存又非常珍贵,那么这个时候就建议使用activity的启动模式设置为:singleTask).
1
android:launchMode="singleTask"
  • singleInstance : 单一实例模式
    如果某个activity的启动模式设置为singleInstance,那么在整个android手机就只会有一个实例了.(对于一些整个系统中,永远都只存在一个同样的界面的activity就会声明使用这种启动模式)

3. broadcastReceiver(广播接收者)

  • 具体实现步骤 :
    • 写个类,继承BroadcastReceiver的类,那么就等价于拥有了一个收音机
    • 到清单manifest文件中进行装电池,配置的问题
    • 调节频道,设置接受广播的类型

在整个android系统中,有很多系统已经定义好的广播事件,这些事件是在系统启动,运行的时候发出的.

例如 : sd卡被挂载 / 开机完成 / 电话拨出 / 应用被安装/被卸载

3.1 编写开机完成广播接收者

  • AndroidManifest.xml
    • 先开启接收广播权限
1
2
3
4
5
6
7
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name="com.itheima.bootcompletion.BootCompletionReceiver">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
1
2
3
4
5
6
7
8
9
10
11
12
public class BootCompletionReceiver extends BroadcastReceiver {
// 监听开机启动完成
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
System.out.println("开机完成了 .... : " + action);
}
}

3.2 IP拨号器之广播

  • AndroidManifest.xml
1
2
3
4
5
6
7
8
<!--先声明广播权限,允许一个程序接收到 ACTION_BOOT_COMPLETED广播在系统完成启动--><uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!--然后说明那个广播器,接收什么类型的广播-->
<receiver android:name=".OutPhone">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
  • MainActivity.java的代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MainActivity extends AppCompatActivity {
private EditText ed_phone;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ed_phone = (EditText)findViewById(R.id.ed_prefix);
}
public void save(View v){
String prefix = ed_phone.getText().toString().trim();
if(TextUtils.isEmpty(prefix)){
Toast.makeText(this,"ip号码不能为空",0).show();
return;
}
SharedPreferences sp = getSharedPreferences("config",0);
SharedPreferences.Editor editor = sp.edit();
editor.putString("prefix",prefix);
editor.commit();
Toast.makeText(this,"IP前缀保存成功",0).show();
}
}
  • OutPhone.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class OutPhone extends BroadcastReceiver {
//alt+enter补全代码
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sp = context.getSharedPreferences("config",0);
String ipdata = sp.getString("prefix","");
if(ipdata.startsWith("0")){
//说明是长途电话
setResultData(ipdata);
}
}
}

3.2 对应用内的数据进行统计之广播

  • AndroidManifest.xml
1
2
3
4
5
6
7
<receiver android:name="com.javami.bigdatacollect.AppStatusReceiver">
<intent-filter >
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
  • AppStatusReceiver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class AppStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
System.out.println(action);
if("android.intent.action.PACKAGE_ADDED".equals(action)){
System.out.println("应用安装了: " + intent.getData());
}else if("android.intent.action.PACKAGE_REMOVED".equals(action)){
System.out.println("应用卸载了 " + intent.getData());
}
}
}

4. 自定义广播

4.1 无序广播

1
2
3
4
5
6
public void sendBroadcast(View v){
System.out.println("发出自定义的广播了");
Intent intent = new Intent();
intent.setAction("com.javami.honey");
sendBroadcast(intent); // 发送一个广播出去
}

4.2 接收自定义广播

  • AndroidManifest.xml
1
2
3
4
5
<receiver android:name=".MyBroadCastReciver">
<intent-filter>
<action android:name="com.javami.honey"></action>
</intent-filter>
</receiver>
  • MyBroadCastReciver.java
1
2
3
4
5
6
public class MyBroadCastReciver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("收到了广播 : " + intent.getAction());
}

4.2 有序广播

  • AndroidManifest.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<receiver android:name=".ShengZhang">
<!--数字越大,优先级别越高-->
<intent-filter android:priority="1000">
<!--隐式调用广播-->
<action android:name="com.javmai.send.Money"></action>
</intent-filter>
</receiver>
<receiver android:name=".Baixing">
<!--数字越大,优先级别越高-->
<intent-filter android:priority="5000">
<!--隐式调用指定的广播-->
<action android:name="com.javmai.send.Money"></action>
</intent-filter>
</receiver>
  • MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void sendMarshroom(View v){
Intent intent = new Intent();
// intent : 设置一个意图行动
intent.setAction("com.javmai.send.Money");
// intent : 意图对象
// receiverPermission : 接收广播的 组件需要什么样的权限
// resultReceiver : 广播事件的最终 接收者
// scheduler : 调度器
// initialCode : 发送广播时的初始码
// initialData : 广播 发出的 原始数据 -- 未被 修改过的原始数据
// initialExtras : 广播发出时的一些额外的数据
sendOrderedBroadcast(intent,null,new FinalResultReveiver(),null,1,"每人1000元",null);
}
  • ShengZhang.java and BaiXing.java and FinalResultReceiver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ShengZhang extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
String money = getResultData();
setResultData("500元");
System.out.print("收到"+money);
}
public class Baixing extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String money = getResultData();
System.out.print("收到"+money);
}
}
public class FinalResultReveiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//纪委部
String money = getResultData();
System.out.print("实际百姓只收到"+money);
}

有序广播和无序广播的区别

有序广播可以在特定的接收者收到广播后,取消广播的继续发送,并且可以更改广播的数据.而无序广播是不能取消广播的发送,不可以更改广播的内容.

5. 手机锁屏解锁之广播接收者

  • MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private PhoneScreenListener phoneReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册监听手机解锁/锁屏的广播接收者
phoneReceiver = new PhoneScreenListener();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
//注册广播接收者
registerReceiver(phoneReceiver, filter);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
// 解除注册 的 广播接收者
unregisterReceiver(phoneReceiver);
}
  • PhoneScreenListener.java
1
2
3
4
5
6
7
8
9
10
public class PhoneScreenListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("========= 手机 屏幕 解锁或者锁屏了 ");
}
}

6. 总结

  • 先写一个类继承broadCastReceiver的类

    1
    public class SmsListener extends BroadcastReceiver
  • 写清单配置这个类

    1
    2
    3
    4
    5
    <receiver android:name="com.javami.smslistener.SmsListener">
    <intent-filter android:priority="1000">
    <action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
    </intent-filter>
    </receiver>
  • 调节频道接收这个类

    1
    public void onReceive(Context context, Intent intent) {