BroadcastReceiver not called at launch - java

I need to detect when wired headset or a bluetooth one is plugged/connected so I create and register two BroadcastReceiver(s) like the following:
file ReceiverHeadsetWired.java
public class ReceiverHeadsetWired extends BroadcastReceiver {
ActivityMain main;
public ReceiverHeadsetWired(
ActivityMain activityMain
){
main = activityMain;
}
#Override
public void onReceive(
Context context,
Intent intent
) {
if (TextUtils.isEmpty(intent.getAction())) { return; }
if (Objects.equals(intent.getAction(), "android.intent.action.HEADSET_PLUG")) {
Log.d("[ReceiverHeadsetWired]", "onReceive()");
...
}
}
}
file ReceiverHeadsetBluetooth.java
public class ReceiverHeadsetBluetooth extends BroadcastReceiver {
ActivityMain main;
public ReceiverHeadsetBluetooth(
ActivityMain activityMain
){
main = activityMain;
}
#Override
public void onReceive(
Context context,
Intent intent
) {
if (TextUtils.isEmpty(intent.getAction())) { return; }
if (Objects.equals(intent.getAction(), "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED")) {
Log.d("[ReceiverHeadsetBluetooth]", "onReceive()");
...
}
}
}
Both of them are dynamically registered in onCreate method of MainActivity's Fragment and unregisterd onDestroy.
#Override
public void onCreate(
Bundle savedInstanceState
) {
super.onCreate(savedInstanceState);
ActivityMain main = (ActivityMain) getActivity();
...
registerHeadsetWiredReceiver();
registerHeadsetBluetoothReceiver();
...
}
private void registerHeadsetWiredReceiver() {
wiredHeadsetReceiver = new ReceiverHeadsetWired(main);
IntentFilter hwFilter = new IntentFilter("android.intent.action.HEADSET_PLUG");
main.registerReceiver(wiredHeadsetReceiver, hwFilter);
}
private void registerHeadsetBluetoothReceiver() {
bluetoothHeadsetReceiver = new ReceiverHeadsetBluetooth(main);
IntentFilter hbFilter = new IntentFilter("android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED");
main.registerReceiver(bluetoothHeadsetReceiver, hbFilter);
}
Now the point is that at launch only the onReceive of ReceiverHeadsetWired is called (Logcat shows the textline), but after app started both of them work as expected except a strange behaviour: the first time I connect a Bluetooth headset the related Log is written twice.
In other words when app is launched if a wired headset is plugged it will be detected but a connected bluetooth one won't.
Does anybody knows what's the problem?
Thanks in advance

Related

Keep changes made by BroadcastReceiver

I'm stuck at this point:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
String number = bundle.getString("Time");
GameTime.setText("" +number + " hours");
}
};
In another Activity, when a Button is pressed, the MainActivity get's an int.
Whenever I open the Activity, I cannot see the GameTime TextView with the number variable in it.
I know that the OnReceive method works, beacause I had put a toast in it, and I could see the toast after sending the int from the other Activity.
How can I keep the changes made to the TextView while changing Activities?
Thank you.
One way:
Define an interface in your activity & Implement the interface inside your activity and pass its reference to the other class and call that reference whenever you need.
Example:
a) Create an interface
public interface MyBroadcastListener{
public void doSomething(String result);
}
b) Initialize BroadCastReceiver
public class TestNotifAlarm extends BroadcastReceiver {
private MyBroadcastListener listener;
#Override
public void onReceive(Context context, Intent intent) {
listener = (MyBroadcastListener)context;
listener.doSomething("Some Result");
}
}
c) Implement the interface in Activity
public YourActivity extends AppCompatActivity implements MyBroadcastListener{
// Your Activity code
public void updateTheTextView(String t) {
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(t);
}
#Override
public void doSomething(String result){
updateTheTextView(result); // Calling method from Interface
}
}
Another Way :
a) Put a Receiver inside your Activity class
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
textView.setText(intent.getStringExtra("extra"));
}
};
b) Register BroadCastReceiver
registerReceiver(broadcastReceiver , new IntentFilter("trigger_broadcust"));
c) Call sendBroadcast
Intent intent = new Intent("trigger_broadcust");
intent.putStringExtra("extra", "data");
sendBroadcast(intent);

Receive broadcast in MainActivity with non static inner class

I need to call certain non static methods in an activity when the user interacts with buttons in notification, I tried to do it in a standalone class the extends BroadcastReceiver it works, but I don't know how call a method on the activity mentioned earlier, I tried to make an inner class, non static, edited the manifest file it was first :
<receiver android:name=".Activity$NotificationBroadcast" >
<intent-filter>
.
.
.
</intent-filter>
</receiver>
and that gives me an error saying :
FATAL EXCEPTION: main
Process: com.example.app, PID: 3189
java.lang.RuntimeException: Unable to instantiate receiver
com.example.app.Activity$NotificationBroadcast:
java.lang.InstantiationException:
the class is :
public class NotificationBroadcast extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent){
if (intent.getAction().equals(Activity.ACTION1)){
// do things
} else if (intent.getAction().equals(Activity.ACTION1)){
// do things
}else if (intent.getAction().equals(Activity.ACTION2)){
// do things
}else if (intent.getAction().equals(Activity.ACTION3)){
// do things
}else if (intent.getAction().equals(Activity.ACTION4)){
// do things
}
}
}
I'm afraid you can't make the receiver as an inner class, because when the receiver is statically instantiated, the "holder" class has to be instantiated as well. The activity instance is only created when it is meant to be active, and that's why you got the exception.
If you want the receiver to interact with the activity (by calling non-static methods in the activity class), I suggest that you should make the receiver a non-static one. This means that you need to register an instance of the receiver in OnCreate() and unregister it in OnDestroy().
For a better design, the activity instance should be passed into the receiver via its constructor as an interface, so that the receiver does not get access to the whole activity object, but is only able to access the functionality.
Manifest should have:
<receiver android:name=".NotificationBroadcast" android:enabled="false" />
An interface for the interaction (IWorker.java for example):
public interface IWorker {
public void doThis();
public void doThat();
}
The receiver (a class on its own) takes the IWorker and does something when a broadcast is received:
public class NotificationReceiver extends BroadcastReceiver {
public static final string ACTION1 = "com.yourpackage.action1";
public static final string ACTION2 = "com.yourpackage.action2";
private IWorker worker;
public NotificationReceiver() {
}
public NotificationReceiver(IWorker worker) {
this.worker = worker;
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION1)) {
worker.doThis();
} else if (intent.getAction().equals(ACTION2)) {
worker.doThat();
}
}
}
And the activity takes care of the receiver on its life cycle:
public class MyActivity extends Activity implements IWorker {
private NotificationReceiver receiver;
#override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// create the receiver
receiver = new NotificationReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(NotificationReceiver.ACTION1);
filter.addAction(NotificationReceiver.ACTION2);
// register it
registerReceiver(receiver, filter);
}
#override
protected void onDestroy() {
super.onDestroy();
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
}
#override
public void doThis() {
System.out.println("Doing this...");
}
#override
public void doThat() {
System.out.println("Doing that...");
}
}
P.S. The above codes are for reference only, they're not tested and may not compile.

How to check internet connectivity using broadcast receiver and Change the intent

I am working on an Android application which requires constant listener of Internet connectivity. I am using Broadcast listener and successfully applied it. But my code only shows the Toast message.
I want to stop the current activity and show a default XML file which says "No Internet Connection". and whenever it connect the Internet, previous activity resumes.
ExampleBradcastReceiver.java
public class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false
);
if (noConnectivity) {
Toast.makeText(context, "Disconnected", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
}
In the place of Toast Message, I want to show a default XML file whenever disconnected and resume activity whenever connected.
You can move ExampleBroadcastReceiver to MainActivity as an inner class. And since in Java inner classes have access to their parent classes' methods and fields, you can in onReceive method consider showing/hiding the Internet disconnected view.
public class MainActivity extends AppCompatActivity {
ExampleBroadcastReceiver exampleBroadcastReceiver = new ExampleBroadcastReceiver();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(exampleBroadcastReceiver, filter);
}
#Override
protected void onStop() {
super.onStop();
unregisterReceiver(exampleBroadcastReceiver);
}
private void showInternetDisconnectedView(boolean disconnected){
// show or hide based on 'disconnected'
}
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
boolean noConnectivity = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
showInternetDisconnectedView(noConnectivity);
}
}
}
}
You need to move Broadcast receiver code into Activity and on receiving internet connection events you can stop current in progress activity and make internet failure layout visible there only as it is part of Activity class. If it is required through out the Application, then create Base activity and handle this there to avoid duplicating code on every screen.

calling a method after starting an activity

I'm making an Android whack a mole game. I have the main activity which is basically the launcher, when you press the Play button the game activity starts. This works fine as it shows the background image and all molehills but I don't know how to call the method to start the game.
I've tried to call it from inside onCreate() but this ends up "playing the game" itself.
I've tried to call it right after the startActivity(intent) but the app crashes. And also I've tried to create an instance of the game class and call the play() method after the start activity but it doesn't work aswell. I don't know how to start the game method once the game activity is loaded.
I hope I explained well, thank you.
public class MainActivity extends AppCompatActivity {
ImageButton btnStart;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_main);
btnStart = (ImageButton)findViewById(R.id.btnStart);
btnStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(getApplicationContext(), GameView.class);
startActivity(intent);
}
});
}
And this is the code for the game_activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide TitleBar
try { this.getSupportActionBar().hide();}
catch (NullPointerException e){}
setContentView(R.layout.activity_game_view);
game();
}
The game() method is a typical game loop.
public void game() {
Random random = new Random();
int index;
/*
* Casting array to store all ImageView on the game
*/
imgViewArray[0] = (ImageView)findViewById(R.id.img1);
imgViewArray[1] = (ImageView)findViewById(R.id.img2);
imgViewArray[2] = (ImageView)findViewById(R.id.img3);
imgViewArray[3] = (ImageView)findViewById(R.id.img4);
imgViewArray[4] = (ImageView)findViewById(R.id.img5);
imgViewArray[5] = (ImageView)findViewById(R.id.img6);
imgViewArray[6] = (ImageView)findViewById(R.id.img7);
imgViewArray[7] = (ImageView)findViewById(R.id.img8);
imgViewArray[8] = (ImageView)findViewById(R.id.img9);
imgViewArray[9] = (ImageView)findViewById(R.id.img10);
int j=0;
while (j < 10) {
// Get a random image to animate
index = random.nextInt(10);
switch(index) {
case 0: imgViewArray[0].setImageResource(images[6]);
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
imgViewArray[0].setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
imgViewArray[0].setImageResource(images[0]);
}
});
}
},
300 // The code executes after 300ms
);
break;
I think you should put the game() call inside onResume().
There are many ways to solve the problem:
Using EventBus
Send the start game Event from Main Activity and register for the Event in the Game activity.
This is my favorite way to handle the problem. It's because the simplicity and prevent us from tightly coupled code. The major problem with using EventBus is we will lost in the sea of Event if there are too much Event in the the app.
How to do:
First, create the Event. This is just a simple class:
public class StartGameEvent {
}
Second, register for the event in the game activity:
public class GameActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
EventBus.getDefault().register(this);
}
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
Third, subscribe for the event:
public class GameActivity extends Activity {
...
#Subscribe
public void onMessageEvent(StartGameEvent event) {
game();
}
}
Last, send the event from Main activity:
EventBus.getDefault().post(new StartGameEvent());
Using LocalBroadcastManager
You need to create the message and broadcast it in from your Main activity:
Intent intent = new Intent("playEvent");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Then, in the game activity, you need to register as receiver:
#Override
public void onCreate(Bundle savedInstanceState) {
// register for the event
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("playEvent"));
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
game();
}
};
#Override
protected void onDestroy() {
// Unregister here
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(mReceiver);
super.onDestroy();
}
I slightly modifying the code from How to use LocalBroadcastManager? for your case.
Using a static method in Game activity
This is the simplest way but highly discouraged. Because we can't ensure the state of the activity. Do not use this in production code. This is for learning sake only.
You can make the game() method as a static method like this:
public class GameActivity extends Activity {
...
public static void game() {
// game logic.
}
}
Then call the method when you want with:
GameActivity.game();

FindViewById in a non activity class

How can I use findViewById() in a non activity class. Below is my code snippet. I get the error message: "can't resolve method findViewById" if used directly. And if i try to use the class constructor (Where the imageView is available) i get this error "cannot resolve symbol context"
public class MyBroadcastReceiver extends FirstBroadcastReceiver {
Activity activity;
public MyBroadcastReceiver(Context context, Activity activity){
this.context=context; // error here(cannot resolve symbol context)
this.activity=activity;
}
#Override
protected void (Context context) {
// content
}
#Override
public void onButton(Context context, boolean isClick) {
if(isClick) {
ImageView blueImage = (ImageView)activity.findViewById(R.id.imageView);
blueImage.setColorFilter(0xff000000);
}
}
.......
....
// and so on
And below is my MainActivity with MybroadcastReceiver class instance.Is it correct?
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// and so on
}
}
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver(MainActivity.this,this);
#Override
public void onActivityResult() {
// some code
}
#Override
public void onInitialized(MyManager manager){
// some code
}
A BroacastReceiver runs entirely in the background, listening for Intents sent either by the OS or other apps. It is not responsible for any UI interactions, and cannot access any views. Therefore, findViewById cannot be used within a BroadcastReceiver.
See also - What is BroadcastReceiver and when we use it?
You have to pass View to the non activity class, before using findViewByid
and
try using
view.findViewByid(R.id.view_id);
Because context is null in Broadcast class. use Broadcast class constructor to pass parent_activity(Where the imageView is available) context in Broadcast to access the context:
public class Broadcast extends BroadCastReceiver {
Activity activity;
public Broadcast(Context context,Activity activity){
this.context=context;
this.activity=activity;
}
.......
....... //so on
and in parent_activity create Broadcast class instance by passing parent_activity context as:
Broadcast broadcast = new Broadcast(parent_activity.this,this);
Use activity instance as:
#Override
public void onButton(Context context, boolean isClick) {
if(isClick) {
ImageView blueImage = (ImageView) activity.findViewById(R.id.imageView); //<--- here
}
}
.........
......... //so on

Categories