必威体育Betway必威体育官网
当前位置:首页 > IT技术

广播onReceive()方法的context类型探究

时间:2019-06-03 12:43:05来源:IT技术作者:seo实验室小编阅读:102次「手机版」
 

onreceive

1. 铺垫

1). 非Activity类型的context并没有所谓的任务栈;

2). 出于安全原因的考虑,Android是不允许Activity或Dialog凭空出现的,一个Activity的启动必须要建立在另一个Activity的基础之上,也就是以此形成的返回栈。而Dialog则必须在一个Activity上面弹出(除非是System alert类型的Dialog),因此在这种场景下,我们只能使用Activity类型的context,否则将会出错。

2. 动态、静态注册的广播,其onreceive()方法里的context类型

1). 静态注册广播,如果没声明android:process,那么BroadcastReceiver和Activity是在同一个进程的;onReceive()里传进来的context的类型最初以为是APPlication,但打印发现是android.app.ReceiverrestrictedContext,。此context非Activity类型,不可直接用来构造alertdialog

    @Override
    protected void onCreate(Bundle savedinstanceState) {
        super.onCreate(savedInstanceState);
        setcontentView(R.layout.activity_main);

        Log.e("main", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
        Thread thread = Thread.currentThread();
        Log.e("main", "tid = " + thread.getId() + ", name = "+ thread.getName());
    }

    //static receiver
    public static class MyReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, intent intent) {
            Log.e("static receiver", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
            Thread thread = Thread.currentThread();
            Log.e("static receiver", "tid = " + thread.getId() + ", name = "+ thread.getName());

            Log.e("static receiver", "Context class = " + context.getClass().getName());
            Log.e("static receiver", "Application Context class = "
                    + context.getApplicationContext().getClass().getName());
        }
    }

输出结果:

2). 动态注册中BroadcastReceiver和Activity也是运行在同一个进程中的,因此调用sendBraodcast()时,传入onReceive()方法里的Context对象context其实就是调用sendBroadcast()的Activty对象,这里的context可以直接用来构造AlertDialog。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter filter = new IntentFilter("my.action_LYL");
        registerreceiver(receiver, filter);

        Log.e("main", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
        Thread thread = Thread.currentThread();
        Log.e("main", "tid = " + thread.getId() + ", name = "+ thread.getName());
    }

   //dynamic receiver
    private BroadcastReceiver receiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("dynamic receiver", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
            Thread thread = Thread.currentThread();
            Log.e("dynamic receiver", "tid = " + thread.getId() + ", name = "+ thread.getName());

            Log.e("dynamic receiver", "Activity Context class  = "
                    + MainActivity.this.getClass().getName());
            Log.e("dynamic receiver", "Context class  = " + context.getClass().getName());

            Log.e("dynamic receiver", "Application Context class  = "
                    + context.getApplicationContext().getClass().getName());
        }
    };

输出结果:

故:

静态注册时,onRecice()方法的context不是Activity类型,故此时不能在接收器中弹出对话框。

动态注册时,BroadcastReceiver的onRecice()方法的context来自Activity,可弹框提示。

同时,在源码中,我们也可以看到,在onReceive()方法前有这么一句注释:* @param context The Context in which the receiver is running.


    /**
     * This method is called when the BroadcastReceiver is receiving an Intent
     * broadcast.  During this time you can use the other methods on
     * BroadcastReceiver to view/modify the current result values.  This method
     * is always called within the main thread of its process, unless you
     * explicitly asked for it to be scheduled on a different thread using
     * {@link android.content.Context#registerReceiver(BroadcastReceiver,
     * IntentFilter, String, android.os.handler)}. When it runs on the main
     * thread you should
     * never perform long-running operations in it (there is a timeout of
     * 10 seconds that the system allows before considering the receiver to
     * be blocked and a candidate to be killed). You cannot launch a popup dialog
     * in your implementation of onReceive().
     *
     * @param context The Context in which the receiver is running.
     * @param intent The Intent being received.
     */
    public abstract void onReceive(Context context, Intent intent);

在onReceive()方法的解释中,不要在广播的onReceive()方法中执行耗时操作,也不要添加过多的逻辑。因为广播接收器中不允许开启线程,当onReceive()运行较长时间而没有结束,程序就会报错。广播接收器的作用是用于打开其他组件。

在Android四大组件:BroadcastReceiver史上最全面解析一文中,作者介绍了OnReceive()的context类型:

对于不同注册方式的广播接收器回调OnReceive(Context context,Intent intent)中的context返回值是不一样的:
    对于静态注册(全局+应用内广播),回调onReceive(context, intent)中的context返回值是:ReceiverRestrictedContext;
    对于全局广播的动态注册,回调onReceive(context, intent)中的context返回值是:Activity Context;
    对于应用内广播的动态注册(localBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Application Context。
    对于应用内广播的动态注册(非LocalBroadcastManager方式),回调onReceive(context, intent)中的context返回值是:Activity Context;

3. 在打印线程id的时候,使用到了Process.myTid() 和Thread.currentThread().getId()

在Android: Process.myTid() VS Thread.currentThread().getId()一文中,作者对二者做出了解释:

Process.myTid()返回linux内核给出的线程ID。
Thread.getId(),对每个线程来说,只是“java层”静态自增长的long型数据

4. 代码

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        IntentFilter filter = new IntentFilter("my.action_LYL");
        registerReceiver(receiver, filter);

        Log.e("main", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
        Thread thread = Thread.currentThread();
        Log.e("main", "tid = " + thread.getId() + ", name = "+ thread.getName());
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(receiver);
        super.onDestroy();
    }

    public void send_bc(View v){
        Intent intent = new Intent("my.action_LYL");
        intent.setPackage("test.com.testforbc_20180718");//static register must set package name
        sendBroadcast(intent);
    }

    //dynamic receiver
    private BroadcastReceiver receiver = new BroadcastReceiver(){
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("dynamic receiver", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
            Thread thread = Thread.currentThread();
            Log.e("dynamic receiver", "tid = " + thread.getId() + ", name = "+ thread.getName());

            Log.e("dynamic receiver", "Activity Context class  = "
                    + MainActivity.this.getClass().getName());
            Log.e("dynamic receiver", "Context class  = " + context.getClass().getName());

            Log.e("dynamic receiver", "Application Context class  = "
                    + context.getApplicationContext().getClass().getName());
        }
    };

    //static receiver
    public static class MyReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("static receiver", "pid = " + Process.myPid() + ", tid = "+ Process.myTid());
            Thread thread = Thread.currentThread();
            Log.e("static receiver", "tid = " + thread.getId() + ", name = "+ thread.getName());

            Log.e("static receiver", "Context class = " + context.getClass().getName());
            Log.e("static receiver", "Application Context class = "
                    + context.getApplicationContext().getClass().getName());
        }
    }
}

输出结果:

5. 参考

Context是什么,怎么用

Android中,Context,什么是Context?

Android四大组件:BroadcastReceiver史上最全面解析

What is the Context passed into onReceive() of a BroadcastReceiver?

能否在BroadcastReceiver里创建AlertDialog并显示?

Context都没弄明白,还怎么做Android开发

Broadcast的onReceive方法中弹出AlertDialog

Android: Process.myTid() VS Thread.currentThread().getId()

相关阅读

美国广播公司、新华网专访乐森机器人:中国黑科技引领世

美国时间2019年1月7日,下午3点,国内乐森机器人作为特邀嘉宾参加China Tech For First Look(中国科技CES媒体提前见面会)。国外媒体:&

沸点天下与辽宁广播电视台宜佳购物频道签约仪式成功举

927北方社群团购大会于9月2日在沈阳召开,本次社群团购大会是首届北方社群团购大会,深受行业人士的重视。沈阳高新区电商产业促进办

基于密码技术的应急广播安全解决方案

当发生重大自然灾害、事故灾难等公共危机时,应急广播能够通过迅速的信息传输通道,在第一时间把灾害消息或灾害可能造成的危害传递到

电车帮创始人王晨松做客天津经济广播“财富聊聊吧”

随着电商时代来临,电动物流车也有着广阔的发展前景。继菜鸟、京东之后,顺丰也宣布将在今年投入8000辆新能源物流车,京东、阿里巴巴更

冲突域与广播域

冲突域是一种物理分段,指连接到同一导线上所有工作站的集合、同一物理网段上所有节点的集合或是以太网上竞争同一带宽节点的集合。

分享到:

栏目导航

推荐阅读

热门阅读