6.广播接收者_服务

来源:互联网 发布:method(i,2))用法Java 编辑:程序博客网 时间:2024/04/30 15:50
%title broadcast-receiver_service
%toc
 
= BroadcastReceiver =
android为了方便开发者对系统中发生的事件进行处理, 在Intent中定义了很多事件类型.
当事件发生时, 会发出一个广播, 将此事件发送到一个公共的消息邮箱里, 程序员可以从中
获取这些广播, 从而做一些事情.
 
广播接收者(BroadcastReceiver)用于接收广播Intent,广播Intent的发送是通过调用
Context.sendBroadcast()、Context.sendOrderedBroadcast()来实现的。通常一个广播Intent
可以被订阅了此Intent的多个广播接收者所接收。
 
广播接收者会在其订阅的广播发出的时候由系统启动, 无需我们自己关心.
Android 3.2 版本以后, 发送一个广播时, 默认不会启动那些从来都没启动过的应用,
这是为了用户的安全考虑. 所以, 3.2以后, 写一个广播接收者, 还要写一个 activity
 
== 自定义广播接收者 ==
要实现一个广播接收者方法如下:<br/>
第一步:继承BroadcastReceiver,并重写onReceive()方法
{{{class="brush:java"
public class IncomingSMSReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // do something
        }
}
}}}
第二步:订阅感兴趣的广播Intent,订阅方法有两种:
- 第一种:使用代码进行订阅
{{{class="brush:java"
    IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
    IncomingSMSReceiver receiver = new IncomingSMSReceiver();
    registerReceiver(receiver, filter);
}}}
 
- 第二种:在AndroidManifest.xml文件中的<application>节点里进行订阅:
{{{class="brush:xml"
    <receiver android:name=".IncomingSMSReceiver">   
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
    </receiver>
}}}
 
== 自动IP拨号 ==
自动在外拨电话前加 17951 等等
{{{class="brush:java"
public class MainActivity extends Activity {
    private EditText et_number;
    private SharedPreferences sp;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_number = (EditText) findViewById(R.id.et_number);
        sp = getSharedPreferences("config", MODE_PRIVATE);
    }
    public void click(View view){
        String ipnumber = et_number.getText().toString().trim();
        Editor editor = sp.edit();
        editor.putString("ipnumber", ipnumber);
        editor.commit();
    }
}
public class OutCallReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String number = getResultData();
        System.out.println("有电话打出来了............哈哈哈"+number);
        SharedPreferences  sp = context.getSharedPreferences("config", Context.MODE_PRIVATE);
        String ipnumber = sp.getString("ipnumber", "");
        setResultData(ipnumber+number);
    }
 
}
}}}
{{{class="brush:xml"
<!--权限-->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!--receiver配置-->
<receiver android:name="com.itheima.ipcall.OutCallReceiver" >
<intent-filter>
    <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
}}}
 
 
== 短信拦截器 ==
当系统收到短信时, 会发一个广播,短信应用就有一个BR, 会收到这个广播, 之后在消息栏显示消息
{{{class="brush:java"
public class SmsReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("短信到来了");
        //获取到 intent里面存放的一组短信对象
        Object[] objs = (Object[]) intent.getExtras().get("pdus");
        for(Object obj : objs){
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) obj);
            String content = smsMessage.getMessageBody();
            String sender = smsMessage.getOriginatingAddress();
            if(sender.equals("15555215556")){//情敌的号码 短信拦截掉
                System.out.println("号码来自于情敌...");
                //终止掉短信
                abortBroadcast();
                SmsManager  smsManager = SmsManager.getDefault();
                smsManager.sendTextMessage(sender, null, "go to hell...", null, null);
            }
        }
    }
}
}}}
{{{class="brush:xml"
<!--权限-->
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<!--receiver配置-->
<receiver android:name="com.itheima.smslistener.SmsReceiver" >
    <intent-filter android:priority="1000">
        <!--4.1后的sdk为了用户的安全, 这个action提示不出来, 但是手动写还是可以的-->
        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>
}}}
 
关于优先级: api里说的是 -1000 到 1000, 但是其实可以设置的更大, 最大是int最大值.
 
广播接收者只有来短信广播, 没有发短信广播
 
== 有序/无序广播 ==
无序广播是不可以修改数据的, 也不能终止广播
 
== 自定义广播事件 ==
很简单, 创建个 intent, 调用 sendBroadcast(intent); 或者 sendOrderdBroadcast(intent);
{{{class="brush:java"
// 发送广播
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    public void click(View view){
        Intent intent = new Intent();
        //指定一个广播事件的动作.  自定义的动作
        intent.setAction("aaa.bbb.ccc");
        intent.putExtra("name", "张三");
        Bundle extras = new Bundle();
        extras .putString("action", "看电影");
        intent.putExtras(extras);
        //发送一个无序广播 ,  不可以被终止掉
        //sendBroadcast(intent);
        //发送一个有序的广播   可以被终止
        sendOrderedBroadcast(intent, null);
    }
}
// 在其他应用中接收广播, 如果是有序广播, 还可以修改intent中的数据.
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("1 接收到了自定义的广播事件....");
        String name = intent.getStringExtra("name");
        String action = intent.getExtras().getString("action");
        System.out.println(name+action);
        String data = getResultData();
        System.out.println("1接受者:"+data);
    }
}
public class MyReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("2 接收到了自定义的广播事件....");
        String name = intent.getStringExtra("name");
        String action = intent.getExtras().getString("action");
        System.out.println(name+action);
        String data = getResultData();
        System.out.println(data);
        setResultData("给下一层拨款5万");
    }
}
public class MyReceiver3 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        System.out.println("3 接收到了自定义的广播事件....");
        String name = intent.getStringExtra("name");
        String action = intent.getExtras().getString("action");
        System.out.println(name+action);
        System.out.println("我是3,优先级高,省级部门,中央拨款了100万");
        setResultData("给下一层拨款50万");
    }
}
}}}
{{{class="brush:xml"
        <receiver android:name="com.itheima.receiver.MyReceiver3" >
            <intent-filter android:priority="1000">
                <action android:name="aaa.bbb.ccc" >
                </action>
            </intent-filter>
        </receiver>
        <receiver android:name="com.itheima.receiver.MyReceiver" >
            <intent-filter android:priority="100">
                <action android:name="aaa.bbb.ccc" >
                </action>
            </intent-filter>
        </receiver>
        <receiver android:name="com.itheima.receiver.MyReceiver2" >
            <intent-filter android:priority="500">
                <action android:name="aaa.bbb.ccc" >
                </action>
            </intent-filter>
        </receiver>
}}}
 
-------
3.2之后, 系统默认不会启动从未启动过的广播所在应用. 如何配置成会启动?
-------
 
== 广播的权限 ==
通过配置权限, 只收听有某个权限的应用的广播, 或者只有有某个权限的应用才能收听某广播.
 
清单文件中, permission 节点用于配置权限, uses-permission 用户配置使用的权限
 
 
---------
怎样防止别的程序开机启动?
---------
 
 
= Service =
在 Window 下, 服务就是一个没有界面的进程.
Android中的服务和windows中的服务有点类似,但是, android中的服务是个没有界面,
长期运行在后台的组件 它是个线程, 可以简单理解为是一个没有界面的 activity,.
Service 运行于系统中, 不容易被用户发觉,可以使用它开发如监控之类的程序。
 
== 开发一个服务 ==
服务的开发比较简单,如下:
- 第一步:继承Service类
    public class XxxService extends Service { }
- 第二步:在AndroidManifest.xml文件中的<application>节点里对服务进行配置:
    <service android:name=".XxxService" />
 
{{{class="brush:java"
public class PhoneListenService extends Service {
    // 在Service创建时调用, 只会被调用一次
    @Override
    public void onCreate() {
        super.onCreate();
    }
    // Service启动时调用, 替代了已过时的onStart方法, 多次开启服务,
    // 每次都会调用这个方法, onCreate方法只调用一次
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }
    // Service销毁时调用, 之后如果再开启服务, 则会调用onCreate, onStartCommand
    @Override
    public void onDestroy() {
        super.onDestroy();
    }
    // 绑定Service, 后面会讲
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
// 在Activity中开启和关闭Service
public void onClick(View v) {
    Intent intent = new Intent(this, PhoneListenService.class);
    switch (v.getId()) {
    case R.id.bt_start:
        startService(intent);
        break;
    case R.id.bt_stop:
        stopService(intent);
        break;
    }
}
}}}
通过看源码我们可以知道, Activity的"爷爷"和 Service的"爸爸"是同一个类 ContextWraper,
祖先类都是 Context, 所以二者有很一些共同的生命周期方法.
 
为什么Service没有 onPause, onResume, onStop, onRestart方法?
Activity在被别的界面覆盖但仍可见时调用 onPause方法, 恢复时调用onResume,
完全不可见时调用onStop方法,恢复时调用onRestart, onResume方法,
Service根本没有界面,所以也就没有这些个方法.
 
应用程序退出时, Service并不会销毁, 而是长期在后台运行. 可以通过
设置-应用程序管理-正在运行的服务 查看
 
== 电话监听器 ==
 
 
== 为什么要使用Service ==
服务可以提高当前应用程序进程的优先级. 关于进程优先级, 可以参看文档 Processes and Threads.
 
android系统会尽可能的保持一个进程, 即使应用关闭了, 但是应用所在进程依然不会被销毁.
这样做的目的是为了加快应用下次的启动. 但是问题就是会导致内存不足. 所以, 系统在必要时会
按照一定的优先级回收这些进程:
- 前台进程(Foreground process)
     应用中有Activity可见, 或应用中的service, receiver处于生命周期方法中.
    优先级最高,最不容易被系统回收掉.
- 可见进程(Visible process)
     如果一个应用程序的activity用户仍然可见, 但不处于最前端, 即onPause方法调用而onStop方法没调用
    也是很不容易被回收的
- 服务进程(Service process)
     应用程序进程里面有一个服务正在运行, 并且服务是通过startService() 方法开启的
- 后台进程(Background process)
     应用程序没有activity可见, 即调用了onStop方法, 且没有服务运行. 很容易被回收
- 空进程(Empty process)
     没有任何正在运行的组件, 极易被回收.
 
当我们在应用中执行一个耗时操作时, 如播放音乐, 网络下载等, 如果直接在activity中开启
子线程, 是有很大的安全隐患的, 当activity退出或最小化时, 应用所在进程很容易被回收掉.
最好的作法是在Service中开启新线程. 这样即使应用退出, Service依然在, 进程不容易被回收.
 
服务也是在主线程中执行的, 所以即使在服务中进行耗时操作, 也要起新线程.
 
服务存在的意义是: 如果一个进程的所有activity都退出或者回到桌面了, 此进程会变成空进程或者后台进程,
很有可能被系统杀死, 所以在 activity中启动新线程执行耗时操作是不合适的.
但是如果进程中还有服务运行, 那么进程则很难被杀死, 所以在服务里启动新线程执行耗时操作是很安全的.
 
== 服务的两种开启方式 ==
服务不能自己运行,需要通过调用Context.startService或Context.bindService方法启动服务。
这两个方法都可以启动服务,但是它们的使用场合有所不同。
 
使采用startService方法启动服务,只能调用stopService方法结束服务,
服务结束时会调用onDestroy()方法。用startService方法启用服务,调用者与服务之间没有关连,
即使调用者退出了,服务仍然运行。
 
使用bindService方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,
有点“不求同时生,必须同时死”的感觉,但是这是单方面的,可以理解为人和风筝之间的关系,
人为调用者,风筝为服务,人挂了,风筝也就挂了,但是风筝挂了人没事。
 
通过startService()和stopService()启动关闭服务。适用于服务和访问者之间没有交互的情况。
如果服务和访问者之间需要方法调用或者传递参数,侧需要使用bindService()和unbindService()方法
启动关闭服务。
 
具体如何使用bindService, 后面会详细讲
 
== 服务的生命周期 ==
使用startService开启服务
 - onCreate() - > onStartCommand() ->onStart() ->onDestroy();  (其实这个onStart已经过时了)
 - 服务只会被创建一次  多次开启服务 只会执行 startCommand() ->onStart() ;
 - 服务只可以被停止一次  执行 onDestroy() 多次的停止服务 没有反应.
 
使用bindService绑定服务
- onCreate()-> onBind() -->onUnbind() ---> onDestroy();
- 服务只会被成功的绑定一次, 多次调用绑定服务的方法 不会重复执行 onbind();
- 调用bindService()方法前服务已经被绑定,多次调用bindService()方法并不会导致
     多次创建服务及绑定(也就是说onCreate()和onBind()方法并不会被多次调用),
    但是, 调用多次会导致无法解绑
- 在绑定的服务的时候 不要多次的重复绑定服务, 否则会导致服务不能被解绑.
    服务只可以被显示地解除绑定一次, 多次的解除绑定服务, 应用程序会报错.
- 如果访问者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法
     也会导致系统调用服务的onUnbind()-->onDestroy()方法。
 
== 绑定方式开启服务 ==
如果我们想要调用服务里面的某个方法, 该怎么办?<br/>
能不能直接new一个服务对象? 好像可以. 但是, 直接我们调用直接new出来的对象的方法时,
这个方法里是不能够调用系统相关的方法的, 因为我们自己new出来的一个"服务对象",
那就不是Service了, 只是一个普通的类而已.
 
android四大组件都不是new出来的, 都是由系统创建提供给我们的, 系统在创建时,
会为其指定上下文环境, 这是我们无法做到的.
 
为了解决这个问题, 我们就要使用另外一种方式.
首先举个例子, 假设政府部门是Service, 为人民服务, 但是政府除了每天例行公事外,
还有一些其他为人民服务的方法, 但是对于我们普通人让他办事, 它是不办的, 要想让他办事
必须找个中间人, 给中间人点钱, 让他去找政府相关人员帮我们办事
 
这个中间人和政府(Service)有着千丝万缕的联系, 他除了能找政府人员办事外, 还有一些其他
的方法, 比如和领导打牌什么的, 这些方法他是不想让我们知道的, 所以他一般会乔装打扮一番,
 
这个情景用图表示如下: <br/>
 
<br/>代码如下:
{{{class="brush:java"
/**
* 声明一个接口, 即中间人, 他只告诉我们他能办的事
*/
public interface IService {
    public void callMethodInService(int money);
}
// activity
public class MainActivity extends Activity {
    private Intent intent;
    private MyConn conn;
    /**
     * 中间人
     */
    private IService myBinder;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent(this, TestService.class);
    }
 
    /**
     * 绑定服务
     * @param view
     */
    public void bind(View view) {
        conn = new MyConn();
        // 2.绑定的方式开启服务
        System.out.println("1.绑定的方式开启服务");
        // 第一个参数是intent不用说, 第二个是ServiceConnection,
        // 它是我们程序和服务之间的一个连接桥梁
        // 第三个参数是绑定时的操作选项, 暂时不用管它
        bindService(intent, conn, BIND_AUTO_CREATE);
    }
 
    /**
     * 解除绑定服务
     * @param view
     */
    public void unbind(View view) {
        // 注意一定要判断一下
        if (conn != null) {
            unbindService(conn);
            conn = null;
        }
    }
 
    /**
     * 调用服务里面的方法
     * @param view
     */
    public void call(View view){
        System.out.println("4.调用代理对象的方法");
        myBinder.callMethodInService(3000);
 
    }
    // ServiceConnection是我们的程序和服务之间的桥梁, 就像风筝线
    private class MyConn implements ServiceConnection {
        //当服务被成功绑定的时候调用的方法.
        //IBinder  就是一个中间人, 通过它, 我们可以调用服务中的方法
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //4.在服务成功绑定的时候  服务端的代理对象就会被返回回来.获取这个代理对象.
            System.out.println("//3.在服务成功绑定的时候  服务端的代理对象就"+
                "会被返回回来.获取这个代理对象.");
            System.out.println("activity:"+service.toString());
            // 把IBinder强转成 我们定义的 IService, 然后就可以调用其中的
            // callMethodInService方法了
            myBinder = (IService) service;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {    }
    }
}
// 服务
public class TestService extends Service {
    /**
     * 服务在成功绑定的时候  会执行onbind方法.
     */
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("onbind");
        //3.服务成功绑定,返回一个中间人代理对象 IBinder
        System.out.println("2.服务成功绑定,返回一个中间人代理对象 IBinder,里面有一个方法");
        MyBinder binder = new MyBinder();
        System.out.println("服务binder:"+binder.toString());
        return binder;
    }
 
    /**
     * 创建一个代理人对象实现 IBinder接口, 这个MyBinder其实就是
     * ServiceConnection 的 onServiceConnected方法形参中的 IBinder
     * 这里继承 Binder, 因为 Binder 是 IBinder的一个简单实现
     */
    private class MyBinder extends Binder implements IService{
        /**
         * 代理人间接的调用服务里面的方法
         * @param money 钱
         */
        public void callMethodInService(int money){
            if(money<500){
                System.out.println("钱太少了.回去再准备点...");
            }else{
                methodInService();
            }
        }
 
        // 这个中间人还有一些其他方法, 是不希望暴露的, 所以才
        // 需要我们自己写一个接口 IService
        public void playPoker(){}
    }
 
    @Override
    public boolean onUnbind(Intent intent) {
        System.out.println("onunbind");
        return super.onUnbind(intent);
    }
    /**
     * 服务里面的方法
     */
    public void methodInService(){
        Toast.makeText(this, "我是服务里面的方法,我被调用了...", 0).show();
    }
 
    @Override
    public void onCreate() {
        System.out.println("服务 oncreate");
        super.onCreate();
    }
    @Override
    public void onDestroy() {
        System.out.println("服务 ondestroy");
        super.onDestroy();
    }
}
}}}
 
== 远程服务与AIDL ==
前面介绍了绑定服务, 其实是用于调用服务中的方法. 在同一个应用中, 这样做的意义其实不大.
毕竟我们可以直接使用startService 和 stopService.
 
绑定服务的主要用途在于, 访问另外一个应用中的服务. 这种应用场景并不多见. 有一种情况,
比如支付宝的支付服务. 要想使用这种服务, 就必须用绑定方法的方式.
 
为什么不能使用startService? 我们不能直接把另一个应用中的Service拷贝过来用, 因为这个Service
和其所在应用可能有很大的联系, 我们无法直接使用.而使用绑定服务, 我们面对的就只是他暴露给我们
的接口(乔装打扮的中间人).
 
但是这样后不够, 别人应用中的接口我们不能直接拿来用, 还要使用AIDL技术.
 
AIDL: Android Interface Definition Language, 安卓接口定义语言.
*提供两个应用程序之间交互的接口*

使用步骤:
1.首先在一个应用中写好一个服务, 采用绑定服务的方式(IService接口也要写好).
{{{class="brush:java"
public class RemoteService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    // 关于这个 IService.Stub 是怎么来的后面会讲
    private class MyBinder extends IService.Stub{
        @Override
        public void callMethodInService(int money) {
            if(money>500){
                methodInService();
            }
        }
    }
    @Override
    public void onCreate() {
        System.out.println("远程服务被创建了....");
        super.onCreate();
    }
    public void methodInService(){
        System.out.println("我是远程服务里面的方法..我被调用了");
    }
}
// 这个接口一定要写
public interface IService {
    public void callMethodInService(int money);
}
}}}
 
2. 在清单文件中配置, 注意一定要写intent-filter, 但是5.0以后好像不能使用隐式意图启动服务了.
{{{class="brush:xml"
<service android:name="com.example.remoteservice.RemoteService" >
    <intent-filter >
        <action android:name="com.hahha.remote.service"/>
    </intent-filter>
</service>
}}}
 
3. 把IService的后缀名改为 aidl, 并且把其中的权限修饰符去掉
{{{class="brush:java"
interface IService {
     void callMethodInService(int money);
}
}}}
然后eclipse会自动在gen 目录下生成相应的.java文件
{{{class="brush:java"
public interface IService extends android.os.IInterface{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.remoteservice.IService{
private static final java.lang.String DESCRIPTOR = "com.example.remoteservice.IService";
/** Construct the stub at attach it to the interface. */
public Stub(){this.attachInterface(this, DESCRIPTOR);}
// 后面省去很多没拷贝
}
}}}
我们可以看到这个IService有个内部类叫 Stub, 他实现了Binder和原先IService,
所以我们只需要让我们的Service里的MyBinder继承这个 Stub即可.
 
IPC: 进程间通讯
 
4. 将IService.aidl文件拷贝到另一个应用中, 要保证包名相同. eclipse也会在gen目录自动生成IService.java文件
{{{class="brush:java"
public class MainActivity extends Activity {
    private Intent intent;
    private IService iService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intent = new Intent();
intent.setAction("com.hahha.remote.service");
    }
    public void bind(View view){
        bindService(intent, new MyConn(), BIND_AUTO_CREATE);
    }
    public void call(View view){
        try {
            iService.callMethodInService(3000);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
    private class MyConn implements ServiceConnection{
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 使用下面的方式将 IBinder 转为 对应的 接口 IService
            iService = IService.Stub.asInterface(service);
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {    }   
    }
}
}}}


从5.0以后, 启动服务必须要用显示意图, 不能用隐式意图. 解决方法如下:

Android L (API 21) - java.lang.IllegalArgumentException: Service Intent must be explicit

Android new version - "Lollipop" (API 21) brings quite a few changes with it, but it comes with some price if you wish to target your app to that API.

When we started adapting our apps to the new API, one of the first problems we've encountered is the `IllegalArgumentException: Service Intent must be explicit`



If you have encountered the problem, and you are actually intending to use your intent in explicit way (meaning that when starting the service you are expecting to hit exactly 1 service action),here's a quick fix for turning implicit --> explicit:
123456789101112131415161718192021222324252627282930313233343536
/***
* Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
* "java.lang.IllegalArgumentException: Service Intent must be explicit"
*
* If you are using an implicit intent, and know only 1 target would answer this intent,
* This method will help you turn the implicit intent into the explicit form.
*
* Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
* @param context
* @param implicitIntent - The original implicit intent
* @return Explicit Intent created from the implicit original intent
*/
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
view rawgistfile1.java hosted with ? by GitHub
That should do it. Please feel free to comment for additional insights on this new issue.

来源: <http://blog.android-develop.com/2014/10/android-l-api-21-javalangillegalargumen.html>
 
 
 
 
 
 
 
 
 
 
 
 


来自为知笔记(Wiz)


1 0
原创粉丝点击