为什么BroadcastReceiver的是不是在后台运行? [英] Why BroadcastReceiver is not running in the background?

查看:609
本文介绍了为什么BroadcastReceiver的是不是在后台运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个应用程序(程序App1)我广播的消息。这code以下是正确的 - >广播检测,如果我试图让广播在同一个项目

  sendBroadcast(新的意向书(com.example.MESSAGE_INTENT)。putExtra(消息,((的EditText)findViewById(R.id.textField))。gettext的()) );
 

我创建App2的具有的BroadcastReceiver 这等待广播意图但该方法的onReceive 永远不会被调用。

如何修改的BroadcastReceiver 应用程序,以使服务工作在后台所有的时间?


App2的清单和code:

 包com.example;

进口android.content.BroadcastReceiver;
进口android.content.Context;
进口android.content.Intent;
进口android.util.Log;
进口android.widget.Toast;

公共类MyReceiver扩展的BroadcastReceiver {
    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图){
        Log.i(工程,!!!!!!!!!!);
        Toast.makeText(背景下,CAUGHTt \ N+ intent.getExtras()的getString(消息),Toast.LENGTH_LONG。).show();
    }
}
 


 <舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
        包=com.jjoe64>

        <权限组
            机器人:名称=com.examples.my_permissions
            机器人:标签=我的权限D组/>

        <许可
            机器人:名称=com.examples.my_permissions.MY_PERMISSION
            机器人:标签=我的权限
            机器人:permissionGroup =com.examples.my_permissions/>

        <应用>
            <接收器
                机器人:名称=MyReceiver
                机器人:出口=真
                机器人:权限=com.examples.my_permissions.MY_PERMISSION>
                <意向滤光器>
                    <作用机器人:名称=com.example.MESSAGE_INTENT/>
                &所述; /意图滤光器>
            < /接收器>


            <服务机器人:名称=BackgroundService/>
        < /用途>

    < /舱单>
 


广播清单

 <舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    包=为com.example
    机器人:出口=真正的>

    <使用-权限的Andr​​oid:名称=com.examples.my_permissions.MY_PERMISSION/>

    <权限组
        机器人:名称=com.examples.my_permissions
        机器人:标签=我的权限D组/>

    <许可
        机器人:名称=com.examples.my_permissions.MY_PERMISSION
        机器人:标签=我的权限
        机器人:permissionGroup =com.examples.my_permissions/>

    <应用>
        <接收器
            机器人:名称=com.example.MyReceiver
            机器人:出口=真
            机器人:权限=com.examples.my_permissions.MY_PERMISSION>
            <意向滤光器>
                <作用机器人:名称=com.example.MESSAGE_INTENT/>
                <作用机器人:名称=android.intent.action.AIRPLANE_MODE/>
            &所述; /意图滤光器>
        < /接收器>
    < /用途>

< /舱单>
 

主要修改

我已创建了 MainActivity 的另一个应用程序那里,我已经创建了最后的BroadcastReceiver

code:

 包com.example.receiver2;

进口android.content.BroadcastReceiver;
进口android.content.Context;
进口android.content.Intent;
进口android.os.Bundle;
进口android.support.v4.app.Fragment;
进口android.support.v7.app.ActionBarActivity;
进口android.util.Log;
进口android.view.LayoutInflater;
进口android.view.Menu;
进口android.view.MenuItem;
进口android.view.View;
进口android.view.ViewGroup;
进口android.widget.Toast;

公共类MainActivity扩展ActionBarActivity {
最后的BroadcastReceiver BR =新的BroadcastReceiver(){

    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图){
        Log.i(工程,!!!!!!!!!!);
        Toast.makeText(背景下,CAUGHTt \ N+ intent.getExtras()的getString(消息),Toast.LENGTH_LONG。).show();
    }
};
    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_main);

        如果(savedInstanceState == NULL){
            。getSupportFragmentManager()的BeginTransaction()加(R.id.container,新PlaceholderFragment())提交()。
        }
    }

    @覆盖
    公共布尔onCreateOptionsMenu(功能菜单){

        //充气菜单;这增加了项目操作栏,如果它是present。
        。getMenuInflater()膨胀(R.menu.main,菜单);
        返回true;
    }

    @覆盖
    公共布尔onOptionsItemSelected(菜单项项){
        //处理动作栏项目点击这里。将操作栏
        //自动在主/向上按钮操作的点击,只要
        //你在AndroidManifest.xml中指定一个父活动。
        INT的id = item.getItemId();
        如果(ID == R.id.action_settings){
            返回true;
        }
        返回super.onOptionsItemSelected(项目);
    }

    / **
     *包含一个简单的视图的占位符片段。
     * /
    公共静态类PlaceholderFragment扩展片段{

        公共PlaceholderFragment(){
        }

        @覆盖
        公共查看onCreateView(LayoutInflater充气,容器的ViewGroup,捆绑savedInstanceState){
            查看rootView = inflater.inflate(R.layout.fragment_main,集装箱,假);
            返回rootView;
        }
    }

}
 

清单:

 < XML版本=1.0编码=UTF-8&GT?;
<舱单的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    包=com.example.receiver2
    安卓版code =1
    机器人:VERSIONNAME =1.0>

    <用途-SDK
        安卓的minSdkVersion =8
        机器人:targetSdkVersion =19/>

    <使用-权限的Andr​​oid:名称=com.examples.my_permissions.MY_PERMISSION/>
    <使用-权限的Andr​​oid:名称=android.permission.RECEIVE_BOOT_COMPLETED/>

    <权限组
        机器人:名称=com.examples.my_permissions
        机器人:标签=我的权限D组/>

    <许可
        机器人:名称=com.examples.my_permissions.MY_PERMISSION
        机器人:标签=我的权限
        机器人:permissionGroup =com.examples.my_permissions/>

    <应用
        机器人:allowBackup =真
        机器人:图标=@可绘制/ ic_launcher
        机器人:标签=@字符串/ APP_NAME
        机器人:主题=@风格/ AppTheme>
        <接收器
            机器人:名称=com.example.MyReceiver
            机器人:出口=真正的>
            <意向滤光器>
                <作用机器人:名称=com.example.MESSAGE_INTENT/>
                <作用机器人:名称=android.intent.action.BOOT_COMPLETED/>
            &所述; /意图滤光器>
        < /接收器>

        <活动
            机器人:名称=com.example.receiver2.MainActivity
            机器人:标签=@字符串/ APP_NAME>
            <意向滤光器>
                <作用机器人:名称=android.intent.action.MAIN/>

                <类机器人:名称=android.intent.category.LAUNCHER/>
            &所述; /意图滤光器>
        < /活性GT;
    < /用途>

< /舱单>
 

但我得到一个异常:

 十月4日至18日:16:46.332:E / AndroidRuntime(1244):致命异常:主要
10月4号至18号:16:46.332:E / AndroidRuntime(1244):工艺:com.example.receiver2,PID:1244
10月4号至18号:16:46.332:E / AndroidRuntime(1244):java.lang.RuntimeException的:无法实例接收com.example.MyReceiver:抛出java.lang.ClassNotFoundException:没有找到类com.example.MyReceiver在路径:DexPathList [zip文件"/data/app/com.example.receiver2-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.receiver2-1, /系统/ lib目录]
10月4号至18号:16:46.332:E / AndroidRuntime(1244):在android.app.ActivityThread.handleReceiver(ActivityThread.java:2400)
 

解决方案

V6 - 样品code在github

在情况下,它可以帮助,我组建了一个非常快速的演示应用程序(用于Eclipse),它包含一个出口,没有安全感的BroadcastReceiver ,您可以作为一个模板。我已存储在我的github上的帐户:

您可以用它来跟随我的答案,第2步,在这里我建议你得到的V3我的建议给予了简单的出口的BroadcastReceiver 工作

我相信,一旦你有这样的启动和运行过程中的其余部分将是相当简单的。


V5 - 接收清单作为单独的类

您可以用两种不同的方式声明的BroadcastReceiver

  • 作为另一个类的字段(如在 MainActivity
  • 或作为一个单独的类

当在另一个类中声明,您需要使用方法 ContextWrapper.registerReceiver() ContextWrapper.unregisterReceiver()以注册意图。您的code需要做到这一点,那么你的应用程序必须运行,以接收广播。

如果要唤醒

有广播你的应用程序,那就是当你声明清单中的接收器(像你一样)。在这种情况下,你的的BroadcastReceiver 将是一个单独的类文件:

 包mobiric.demo;

进口android.content.BroadcastReceiver;
进口android.content.Context;
进口android.content.Intent;

/ **
 *必须在清单中声明。
 * /
公共类MobiricReceiver扩展的BroadcastReceiver
{
    @覆盖
    公共无效的onReceive(上下文的背景下,意图意图)
    {
        // 做一点事
    }
}
 

它看起来像你混淆这两个技术。我认为你需要的第二个技巧:

  • 申报清单
  • 创建基于code单独的类文件

V4 - 手动启动这两个应用程序

过去的事我能想到的此刻,我认为你需要手动启动应用程序的系统允许的BroadcastReceiver 工作之前。

所以一定在测试前启动任何活动在你的应用程序。

下面是关于一个博客文章:


V3 - 授予您的应用程序自定义权限

哦,等一下 - 你还没有宣布&LT;使用-权限的Andr​​oid:名称=com.examples.my_permissions.MY_PERMISSION/&GT; 在清单<。 / P>

不过,我通常会想到的logcat告诉你,你有一个权限问题。

有关它的价值,我会下跌打破了这个问题变成几个步骤:

  1. 从两个应用程序中删除所有必需的自定义权限
  2. 在调试广播接收器,使得它在这个不安全的配置。
  3. 最后添加自定义权限

这样,你找出潜在的问题,所以你永远只能有一个棘手的问题处理的时间。它会更容易集中于该问题,而无需其他的可能性来跟踪。

此外,在开发时删除自定义权限,它使您能够使用亚行来测试你的接收器,它可以节省大量的时间。寻找对 ADB壳AM广播... 这里的细节:


V2 - 注册您的应用程序使用自定义权限

原题更新了导出=真正的

使用自定义权限,既需要应用程序进行签名,使用相同的签名密钥。

然而我遇到了过去悬而未决的自定义权限的问题。基本上我的新的自定义权限没有被授予在设备上。卸载和重新安装应用程序,没有任何区别 - 它似乎是系统存储在一个地方自定义权限,我无法更新

下面是这个论坛的相关帖子 - 不幸的是我从来没有能够解决的问题,而不得不忍受所提供的解决方法:


V1 - 导出的BroadcastReceiver

您需要出口你的的BroadcastReceiver 通过将导出=真正的中的清单声明接收器。

请参阅更改如下:

 &LT;接收器
        机器人:名称=MyReceiver
        机器人:权限=com.examples.my_permissions.MY_PERMISSION
        机器人:出口=真正的&GT;

        &LT;意向滤光器&gt;
            &lt;作用机器人:名称=com.example.MESSAGE_INTENT/&GT;
        &所述; /意图滤光器&gt;
    &LT; /接收器&GT;
 

注意:这个答案未来的读者,请注意,原来的职位包括许可。这prevent安全问题,并要求调用应用程序是用相同的签名。

In one application (App1) I am broadcasting a message. This code below is correct -> the broadcast is detected if I try to get Broadcast in the same project.

sendBroadcast(new Intent("com.example.MESSAGE_INTENT").putExtra("MESSAGE", ((EditText) findViewById(R.id.textField)).getText()));

I created App2 which has a BroadcastReceiver which waits for the broadcasted Intent but the method onReceive is never invoked.

How to change the BroadcastReceiver app to make the service work in background all the time?


App2 manifest and code:

package com.example;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("WORKS" , "!!!!!!!!!!");
        Toast.makeText(context, "CAUGHTt\n" + intent.getExtras().getString("MESSAGE"), Toast.LENGTH_LONG).show();
    }
}


           <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.jjoe64" >

        <permission-group
            android:name="com.examples.my_permissions"
            android:label="my permissions groupd" />

        <permission
            android:name="com.examples.my_permissions.MY_PERMISSION"
            android:label="my permission"
            android:permissionGroup="com.examples.my_permissions" />

        <application>
            <receiver
                android:name="MyReceiver"
                android:exported="true"
                android:permission="com.examples.my_permissions.MY_PERMISSION" >
                <intent-filter>
                    <action android:name="com.example.MESSAGE_INTENT" />
                </intent-filter>
            </receiver>


            <service android:name="BackgroundService" />
        </application>

    </manifest>


Broadcaster MANIFEST

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example"
    android:exported="true" >

    <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" />

    <permission-group
        android:name="com.examples.my_permissions"
        android:label="my permissions groupd" />

    <permission
        android:name="com.examples.my_permissions.MY_PERMISSION"
        android:label="my permission"
        android:permissionGroup="com.examples.my_permissions" />

    <application>
        <receiver
            android:name="com.example.MyReceiver"
            android:exported="true"
            android:permission="com.examples.my_permissions.MY_PERMISSION" >
            <intent-filter>
                <action android:name="com.example.MESSAGE_INTENT" />
                <action android:name="android.intent.action.AIRPLANE_MODE" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

MAJOR EDIT

I have created an another application with MainActivity there I have created final BroadcastReceiver:

CODE:

package com.example.receiver2;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
final BroadcastReceiver br = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("WORKS" , "!!!!!!!!!!");
        Toast.makeText(context, "CAUGHTt\n" + intent.getExtras().getString("MESSAGE"), Toast.LENGTH_LONG).show();
    }
};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;
        }
    }

}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.receiver2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <permission-group
        android:name="com.examples.my_permissions"
        android:label="my permissions groupd" />

    <permission
        android:name="com.examples.my_permissions.MY_PERMISSION"
        android:label="my permission"
        android:permissionGroup="com.examples.my_permissions" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver
            android:name="com.example.MyReceiver"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.example.MESSAGE_INTENT" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity
            android:name="com.example.receiver2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

BUT I GET AN EXCEPTION:

04-18 10:16:46.332: E/AndroidRuntime(1244): FATAL EXCEPTION: main
04-18 10:16:46.332: E/AndroidRuntime(1244): Process: com.example.receiver2, PID: 1244
04-18 10:16:46.332: E/AndroidRuntime(1244): java.lang.RuntimeException: Unable to instantiate receiver com.example.MyReceiver: java.lang.ClassNotFoundException: Didn't find class "com.example.MyReceiver" on path: DexPathList[[zip file "/data/app/com.example.receiver2-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.receiver2-1, /system/lib]]
04-18 10:16:46.332: E/AndroidRuntime(1244):     at android.app.ActivityThread.handleReceiver(ActivityThread.java:2400)

解决方案

v6 - Sample code on github

In case it helps, I put together a very quick demo app (for Eclipse) which contains a single exported, insecure BroadcastReceiver which you can use as a template. I have stored it on my github account:

You can use it to follow my advice given in v3 of my answer, step 2, where I suggested you get a simple exported BroadcastReceiver working.

I am sure the rest of the process will be quite simple once you have this up and running.


v5 - Manifest receiver as separate class

You can declare a BroadcastReceiver in two different ways:

  • as a field in another class (as in your MainActivity)
  • or as a separate class

When declared in another class, you need to use the methods ContextWrapper.registerReceiver() and ContextWrapper.unregisterReceiver() to register for intents. Your code needs to do this, so your app must be running in order to receive the broadcast.

If you want to "wake up" your app with a broadcast, that is when you declare the receiver in the manifest (like you did). In that case, your BroadcastReceiver will be a separate class file:

package mobiric.demo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

/**
 * Must be declared in the manifest.
 */
public class MobiricReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        // do something
    }
}

It looks like you are mixing up these 2 techniques. I think you need the 2nd technique:

  • declare in manifest
  • create separate class file based on code

v4 - Manually launch both apps

The last thing I can think of at the moment is that I think you need to manually launch your app before the system allows a BroadcastReceiver to work.

So be sure to launch any Activity in your app before testing.

Here's a blog post about that:


v3 - Grant your app the Custom Permission

Oh wait - you haven't declared <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" /> in your manifest.

But I would normally expect logcat to tell you that you have a permission issue.

For what it's worth, I would break this issue down into a couple of steps:

  1. remove all required custom permissions from both apps
  2. debug your broadcast receiver so that it works in this insecure configuration
  3. finally add the custom permissions

That way you isolate potential problems so you are only ever dealing with one tricky issue at a time. It will make it easier to focus on the problem without having other possibilities to track down.

In addition, by removing the custom permissions at development time, it enables you to use ADB to test your receiver, which can save a lot of time. Look for details on the adb shell am broadcast ... here:


v2 - Sign your apps to use Custom Permissions

Original question updated with exported="true".

Using custom permissions requires both apps to be signed, using the same signing key.

However I have run into unsolved "custom permission" issues in the past. Basically my new custom permissions were not being granted on the device. Uninstalling and reinstalling the app did NOT make any difference - it seemed that the system stored that custom permission in a place that I could not update it.

Here is the related post on this forum - unfortunately I was never able to solve the issue, and had to live with the provided workaround:


v1 - Export the BroadcastReceiver

You need to "export" your BroadcastReceiver by putting exported="true" in the manifest declaration of the receiver.

See change below:

    <receiver
        android:name="MyReceiver"
        android:permission="com.examples.my_permissions.MY_PERMISSION"
        android:exported="true" >

        <intent-filter>
            <action android:name="com.example.MESSAGE_INTENT" />
        </intent-filter>
    </receiver>

Note: future readers of this answer, please note that the original post included a permission. This prevent security issues, and requires that the calling app is signed with the same signature.

这篇关于为什么BroadcastReceiver的是不是在后台运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆