为什么BroadcastReceiver没有在后台运行?

时间:2014-04-18 13:13:27

标签: android broadcastreceiver

在一个应用程序(App1)中,我正在播放一条消息。以下代码是正确的 - >如果我尝试在同一个项目中播放广播,则会检测到广播。

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

我创建的App2有一个BroadcastReceiver,等待广播的Intent,但方法onReceive永远不会被调用。

如何更改BroadcastReceiver应用以使服务始终在后台运行?


App2清单和代码:

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>

播音员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

我创建了另一个MainActivity的应用程序,我创建了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;
        }
    }

}

清单:

<?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>

但我得到了一个例外:

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)

1 个答案:

答案 0 :(得分:4)

v6 - github上的示例代码

如果它有帮助,我会组建一个非常快速的演示应用程序(对于Eclipse),它包含一个导出的,不安全的BroadcastReceiver,您可以将其用作模板。我已将其存储在我的github帐户中:

您可以使用它来遵循我的答案第3步中给出的建议,第2步,我建议您使用简单的导出BroadcastReceiver

我确信一旦你完成并运行,其余的过程将非常简单。


v5 - Manifest接收器作为单独的类

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

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

在另一个类中声明时,您需要使用方法ContextWrapper.registerReceiver()ContextWrapper.unregisterReceiver()来注册意图。您的代码需要执行此操作,因此您的应用必须正在运行才能接收广播。

如果您想通过广播“唤醒”您的应用,那就是您在清单中声明接收器(就像您所做的那样)。在这种情况下,您的BroadcastReceiver将是一个单独的类文件:

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
    }
}

看起来你正在混合这两种技术。我认为你需要第二种技术:

  • 在清单
  • 中声明
  • 根据代码
  • 创建单独的类文件

v4 - 手动启动两个应用

我现在能想到的最后一件事是,我认为您需要在系统允许BroadcastReceiver工作之前手动启动您的应用。

因此,请务必在测试前在应用中启动任何Activity

以下是关于此的博文:


v3 - 为您的应用授予自定义权限

哦等等 - 你没有在你的清单中宣布<uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" />

但我通常希望logcat告诉你,你有权限问题。

对于它的价值,我会将这个问题分解为几个步骤:

  1. 从两个应用中删除所有必需的自定义权限
  2. 调试您的广播接收器,使其在这种不安全的配置中工作
  3. 最后添加自定义权限
  4. 通过这种方式,您可以隔离潜在的问题,因此您一次只能处理一个棘手的问题。它可以更容易地专注于问题,而无需追踪其他可能性。

    此外,通过在开发时删除自定义权限,您可以使用ADB来测试接收器,这可以节省大量时间。在这里查看adb shell am broadcast ...的详细信息:


    v2 - 签署您的应用以使用自定义权限

    原始问题已更新为exported="true"

    使用自定义权限需要使用相同的签名密钥对两个应用进行签名。

    然而我过去遇到过未解决的“自定义权限”问题。基本上我的新自定义权限未在设备上授予。卸载并重新安装应用程序没有任何区别 - 系统似乎将自定义权限存储在我无法更新的地方。

    以下是此论坛上的相关帖子 - 遗憾的是我无法解决此问题,并且不得不接受提供的解决方法:


    v1 - 导出BroadcastReceiver

    您需要通过将BroadcastReceiver放入接收者的清单声明中来“导出”您的exported="true"

    请参阅以下更改:

        <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>
    

    注意:此答案的未来读者,请注意原帖包含permission。这可以防止出现安全问题,并要求使用相同的签名对呼叫应用进行签名。