Reputation: 585
as the title says, I got a trouble with my broadcast. I got a Service that sends some of intents to the main activity (that receive those messages with the broadcast).
I got this Log:
08-03 18:23:11.581: E/AndroidRuntime(776): FATAL EXCEPTION: main
08-03 18:23:11.581: E/AndroidRuntime(776): java.lang.RuntimeException: Unable to instantiate receiver com.example.proyectjane_smartphone.Main.$IncomingBroadcaster: java.lang.ClassNotFoundException: com.example.proyectjane_smartphone.Main.$IncomingBroadcaster in loader dalvik.system.PathClassLoader[/data/app/com.example.proyectjane_smartphone-1.apk]
08-03 18:23:11.581: E/AndroidRuntime(776): at android.app.ActivityThread.handleReceiver(ActivityThread.java:1777)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.app.ActivityThread.access$2400(ActivityThread.java:117)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:985)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.os.Handler.dispatchMessage(Handler.java:99)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.os.Looper.loop(Looper.java:130)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.app.ActivityThread.main(ActivityThread.java:3687)
08-03 18:23:11.581: E/AndroidRuntime(776): at java.lang.reflect.Method.invokeNative(Native Method)
08-03 18:23:11.581: E/AndroidRuntime(776): at java.lang.reflect.Method.invoke(Method.java:507)
08-03 18:23:11.581: E/AndroidRuntime(776): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
08-03 18:23:11.581: E/AndroidRuntime(776): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
08-03 18:23:11.581: E/AndroidRuntime(776): at dalvik.system.NativeStart.main(Native Method)
08-03 18:23:11.581: E/AndroidRuntime(776): Caused by: java.lang.ClassNotFoundException: com.example.proyectjane_smartphone.Main.$IncomingBroadcaster in loader dalvik.system.PathClassLoader[/data/app/com.example.proyectjane_smartphone-1.apk]
08-03 18:23:11.581: E/AndroidRuntime(776): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
08-03 18:23:11.581: E/AndroidRuntime(776): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
08-03 18:23:11.581: E/AndroidRuntime(776): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
08-03 18:23:11.581: E/AndroidRuntime(776): at android.app.ActivityThread.handleReceiver(ActivityThread.java:1768)
08-03 18:23:11.581: E/AndroidRuntime(776): ... 10 more
Here is the code of the broadcastReceiver (It's defined as an inner class, so the name in the manifest is "com.example.proyectjane_smartphone.Main.$IncomingBroadcaster", using "$"):
class IncomingBroadcaster extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_CHANGE_TEXT_IO)) {
textIO.setText("OUTUT: " + intent.getStringExtra("text"));
} else if (action.equals(ACTION_SPEAK)) {
JANEvoi.speak(intent.getStringExtra("speak"));
} else if (action.equals(ACTION_CHANGE_LIGHT)) {
if (intent.getBooleanExtra("light", false)) {
connLight.setImageResource(R.drawable.lighton);
} else {
connLight.setImageResource(R.drawable.lightoff);
}
} else if (action.equals(ACTION_ENABLE_BT)) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
BluetoothManager.REQUEST_ENABLE_BT);
}
}
}
I need the broadcast to be defined as an inner class, becouse it changes some texts and call a "activityforResult", and it's only possible in the main activity.
The calls are made for the service, here is an example that shoot the exception:
public void enableBluetoothAdapter() {
if (blueManager.getAdapter() == null) {
Log.d("BLUETOOTHMANAGER", "There's no bluetooth adapter");
} else if (!blueManager.getAdapter().isEnabled()) {
Intent enableBTIntent = new Intent(Main.ACTION_ENABLE_BT);
sendBroadcast(enableBTIntent);
Log.d("BLUETOOTH", "BLUETOOTH ENCENDIDO");
}
}
What I cant understand, is that (For example with "ACTION_ENABLE_BT") the intent is send and received, becouse while the activity is crashing the "popup-menu" that activate the bluetooth appears... So The broadcast crash before was used (In spite of receiving an error saying that the broadcast cannot be instanciated...).
Finally here is the Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.proyectjane_smartphone"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="10" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.proyectjane_smartphone.Main"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="com.example.proyectjane_smartphone.Main.$IncomingBroadcaster"
android:exported="false" >
<intent-filter>
<action android:name="es.jane.SpeakAction" />
<action android:name="es.jane.ChangeTextIOAction" />
<action android:name="es.jane.ChangeLight" />
<action android:name="es.jane.EnableBT" />
</intent-filter>
</receiver>
<service android:name="com.example.proyectjane_smartphone.Bluetooth.BluetoothService" >
</service>
</application>
</manifest>
I was searching but I didn't find the solution. Thanks in advance
Upvotes: 1
Views: 649
Reputation: 585
The trouble was thar if I use the BroadcastReceiver, it's neednt to be declarated in the Manifest. Then I declare the broadcast with the following code in the activity:
private BroadcastReceiver inBroadcast = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_CHANGE_TEXT_IO)) {
textIO.setText("OUTUT: " + intent.getStringExtra("text"));
} else if (action.equals(ACTION_SPEAK)) {
JANEvoi.speak(intent.getStringExtra("speak"));
} else if (action.equals(ACTION_CHANGE_LIGHT)) {
if (intent.getBooleanExtra("light", false)) {
connLight.setImageResource(R.drawable.lighton);
} else {
connLight.setImageResource(R.drawable.lightoff);
}
} else if (action.equals(ACTION_ENABLE_BT)) {
Intent enableBtIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent,
BluetoothManager.REQUEST_ENABLE_BT);
}
}
};
And finally, it works!
Upvotes: 0
Reputation: 41972
Even if you fixed the class name it still wouldn't work since the BroadcastReceiver
is not a static inner class. An instance of the activity would be required to instantiate it and that isn't possible with how you can define it in the Manifest.
The proper way to use a BroadcastReceiver
that works on behalf of an Activity
is to register and unregister it in Activity#onResume
and Activity#onPause
. This way the receiver is listening for events when the Activity is active and can interact with it properly as an inner class.
In onCreate()
you need to create an instance of your receiver then in onResume()
you'd need something similar to:
final IntentFilter filter = new IntentFilter();
this.populateFilter(filter);
filter.addAction("es.jane.SpeakAction");
...
registerReceiver(this.receiver, filter);
And in onPause()
:
unregisterReceiver(this.receiver)
Upvotes: 1