[mobilesafe] 09_采用代码的方法动态的注册广播接收者及和清单文件注册的区别

Android 4.0

采用代码的方法动态的注册广播接收者及和清单文件注册的区别

需求:来电归属地显示已经实现,现在还需要拨号出去时,也显示归属地
方式1
:在外拨电话的广播接收者的 onReceive ()方法中,实现逻辑
// 2、外拨电话时,以吐丝显示电话号码归属地,只有开启服务来电归属地打电话出去号码才会有归属地显示
// 不专业, 不管什么情况 这个广播接受者都会执行代码
/*if (ServiceStatusUtils.isServiceOpen(context, ShowAddressService.class)) {
    String address = AddressDao.getAddress(context, outNumber);
    Toast.makeText(context, address, Toast.LENGTH_LONG).show();
}*/  
但这种方式有个问题,当用户取消了显示归属地功能,该代码还是会执行,不够专业

方式2:让外拨电话时,也显示号码的归属地,让外拨电话广播接收者和显示归属地服务的生命周期绑定在一起,当显示归属地服务创建时,也将外拨电话广播接收者也注册,服务停止时,卸载广播接收者。
实现:采用代码的方式注册广播接收者:可以动态的控制广播接收者的存活。
ShowAddressService.java
package cn.zengfansheng.mobilesafe.service;
 
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
import cn.zengfansheng.mobilesafe.dao.AddressDao;
 
/**
* 2、显示来电归属地Service
* @author hacket
*/

public class ShowAddressService extends Service {
 
    private MyPhoneStateListener listener;// 电话状态监听器
    private TelephonyManager manager;// 电话管理器
    private OutCallReveiver outCallReveiver;// 外拨电话的广播接收者
 
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
 
    // 广播接受者的有效周期 与 服务的生命周期关联.
    // 广播接受者 不仅可以通过清单文件注册 还可以通过 代码注册.
    /**
     * 2、查询号码归属地内部类的外拨电话的广播接收者
     * @author hacket
     */

    private class OutCallReveiver extends BroadcastReceiver {
 
        private static final String TAG = "Inner OutCallReveiver";
 
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "我是ShowAddressService中的OutCallReveiver,我被开启了。。。");
            String address = AddressDao.getAddress(context, getResultData());
            Toast.makeText(context, address, Toast.LENGTH_LONG).show();
        }
    }

 
    @Override
    public void onCreate() {
 
        // 2、服务开启,注册外拨电话的广播接收者
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
        outCallReveiver = new OutCallReveiver();
        // 在服务被创建的时候,注册广播接收者
        registerReceiver(outCallReveiver, filter);

 
        // 1、服务创建,开始电话状态监听
        manager = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
 
        // PhoneStateListener listener = new MyPhoneStateListener();
        // 注意,定义成了成员变量,就不能再这样定义了,否则该服务已开启就没有关闭,当卸载服务时,卸载的是外部定义的服务,
        // 这个没有卸载,就一直这样存活着,当有来电的时候,还是会显示来电归属地
        listener = new MyPhoneStateListener();// 这就正常了。
        manager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
        super.onCreate();
    }
 
    @Override
    public void onDestroy() {
 
        // 2、服务停止时,卸载掉外拨电话的广播接收者,防止报异常。
        unregisterReceiver(outCallReveiver);
        outCallReveiver = null;

 
        // 1、当服务停止的时候 取消电话监听
        manager.listen(listener, PhoneStateListener.LISTEN_NONE);
        listener = null;
        super.onDestroy();
    }
 
    /**
     * 1、电话状态监听器
     * @author hacket
     */

    private class MyPhoneStateListener extends PhoneStateListener {
 
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            super.onCallStateChanged(state, incomingNumber);
 
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:// 电话响铃时
                String phoneAddress = AddressDao.getAddress(getApplicationContext(), incomingNumber);
                Toast.makeText(getApplicationContext(), phoneAddress, Toast.LENGTH_LONG).show();
                break;
            }
        }
    }
}

注意1:使用代码方式注册了广播接收者,但没有卸载广播接收者
注册了广播接收者,一定要记得卸载广播接收者,否则不报,广播接收者绑定的对象销毁,但该广播接收者还是会销毁。

解决:
@Override
public void onDestroy() {
    
    // 2、服务停止时,卸载掉外拨电话的广播接收者,防止报异常。
    unregisterReceiver(outCallReveiver);
    outCallReveiver = null;
    
    // 1、当服务停止的时候 取消电话监听
    manager.listen(listener, PhoneStateListener.LISTEN_NONE);
    listener = null;
    super.onDestroy();
}
注意2:控制广播接收者的生命周期
Service.registerReceiver(outCallReveiver, filter);  //和服务生命周期一致
Context.registerReceiver(outCallReveiver, filter);   //和上下文存活的周期长,存活周期长

动态的注册广播接收者及和清单文件注册的区别
两种广播接受者注册的优缺点:
 
1. 清单文件注册.
一旦应用程序被部署到手机上, 立刻生效了.
不管应用程序的进程是否开启,接收到了广播事件后,立刻执行onReceive()方法.
 
 
2. 代码注册
只有执行了 registerReceiver(receiver, filter); 生效
执行  unregisterReceiver(receiver);  失效,如果注册了,却没有卸载掉,那么会报错。
我们可以手工的控制这个广播接受者的有效期.