Lollipop+ Unbind BeaconManager not working - java

I am trying to implement beacon functionality in my Android application.
Unfortunately there are a few strange behaviours I couldn't solve yet.
I am using the Android Beacon Library in Version 2.15 and Android 6.0.1.
I have an Activity
class MainActivity extends AppCompatActivity implements BeaconConsumer
where I want to search for nearby beacons. I initialize the BeaconManager like
private BeaconManager m_beaconManager;
[...]
m_beaconManager = BeaconManager.getInstanceForApplication(this);
m_beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT));
m_beaconManager.bind(this);
in the onCreate() method.
The way I search for beacons
#Override
public void onBeaconServiceConnect() {
m_beaconManager.addRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
// do something
}
});
try {
m_beaconManager.startRangingBeaconsInRegion(m_region);
} catch(RemoteException e) {
e.printStackTrace();
}
}
works perfectly fine.
In my application I want to display these beacons in a list and if I click onto one of them I want to start a new activity with more informations about the beacon (MAC address, distance etc.).
My current approach is to unbind my BeaconManager in the onPause() method and create a whole new BeaconManager in my new Activity. This also works flawless.
But a soon as I finish() my second activity it does not stop searching for beacons. I also unbind my BeaconManager like so
#Override
public void onPause() {
super.onPause();
m_beaconManager.unbind(this);
}
#Override
public void onDestroy() {
super.onDestroy();
m_beaconManager.unbind(this);
}
#Override
public void onStop() {
super.onStop();
m_beaconManager.unbind(this);
}
but back in my MainActivity I get 2 searches for beacons. One from my MainActivity and the other one from my already finished second activity.
Furthermore if I click on another item of my list which means I create my second activity again, it looks for the beacon from the first start and the new one. Each new click on the list adds a new search to the existing ones.
I already searched for known Bugs but there is nothing similar.
What am I doing wrong?

In order to prevent duplicate callbacks, in addition to unbinding, you should call (a) stopRangingBeaconsInRegion(...) and (b) removeRangeNotifier(...). To remove the notifier you will need to keep a reference to your callback class.

Related

Is there a way to exactly detect when an activity is destroyed in android?

I am making an android app in java in which I need to trigger some database requests whenever an activity is completely destroyed which would probably happen if the user presses the back button or leaves the app itself... But the onDestroy() function in my app is randomly getting triggered even when the user is still on the activity... I guess the probable reason for this is configuration changes but I am not able to figure out a proper solution for this.
Is there a way we could exactly detect when an activity is left by a user avoiding any in-page configuration changes??
The onDestroy() that I am using is this:
#Override
protected void onDestroy() {
/// do smthng
super.onDestroy();
}
Any help would be appreciated!!
Solved:
Thank you for the answer guys... For me onStop() worked out perfectly and it is working in every case whether it might be pressing the back button or exiting the activity or the app itself!!
If you want to check if the user ended the activity, meaning pressed back, do this:
#override
public void onBackPressed(){
//do something before we finish the activity
super.onBackPressed();
}
If you want to check when user, goes to next activity, then resturns to the same activity:
#override
public void onResume(){
//do something when return back to this activity
super.onResume();
}
#override
public void onPause(){
//do something before going to another activity
super.onPause();
}
onDestroy is called when the activity is destroyed or finished and not guaranteed to be called always, don't depend on it
We can check on whether our application is foreground or background based on the activity entering and exiting the foreground by implementing ActivityLifecycleCallbacks.
Good reference : https://medium.com/#iamsadesh/android-how-to-detect-when-app-goes-background-foreground-fd5a4d331f8a
Quoting from the above article,
#Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
and,
#Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
by which we can make sure that our app is in foreground or not. Here you always have the control of what activity is in foreground based on which you can check and execute the logic.

Add data to recyclerView from Sqlite in realtime?

I've made an app that is receiving some data from a TCP Client to my TCP Server that store the data in SQlite DB, and actually i've made a recyclerView where to visualize all that data but now my issue is what i'm trying like 2 weeks to refresh the recyclerView in real Time, i mean if a TCP Client will send a new package to my TCP Server and if i'm in the activity with the recyclerView the data have to be added dynamically.
I will also accept any type of tips and suggestions on how to improve my app.
Actually it's my 1st app i've ever created in Android.
HERE you can find my Server(TCPServer),RecyclerViewAdapter,Adapter(constructor),allert.java(class where i invoke the RecyclerViewAdapter.
Hope someone will be able to help me and ill be very grateful.
Try sending broadcast method. Here are the steps :
Make a inner class that extends BroadcastReceiver in your activity.
private class ExampleBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//do stuffs here, e.g. getting extras from intent
}
Declare a instance of the class outside any methods.
public class MainActivity extends AppCompatActivity {
private ExampleBroadcastReceiver exampleBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
//stuffs
}
}
Override onResume method. Initialize the instance you just made in this method. Then, register it with a intent-filter. This will make sure that your broadcast receiver ready when user open the activity.
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction("com.example.MainActivity");
exampleBroadcastReceiver = new ExampleBroadcastReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(exampleBroadcastReceiver, filter);
}
Override onPause method and unregister your receiver.
#Override
protected void onPause() {
super.onPause();
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(exampleBroadcastReceiver);
} catch (IllegalArgumentException e) {
if (!e.getMessage().contains("Receiver not registered")) {
// unexpected, re-throw
throw e;
}
Make sure you use ArrayList for dynamic data.
Whenever you receive data from server, after you store them in your database, send a broadcast with extras contains data you want to display in your activity.
EDITED
I registered the receiver using an instance of LocalBroadcastManager.

Handle calls of onStart and onStop only from outside my app

I want to make a cloud synchronization everytime my app is brought to front and a second time if the app disappears in background.
So I overwrote the onStart and onStop event methods of my activity:
#Override
protected void onStart() {
super.onStart();
doSync();
}
#Override
protected void onStop() {
doSync();
super.onStop();
}
Ok, that works fine for me but I found out that these methods are also called if I start a new activity (f.e. SettingsActivity.class) within my app (onStop) and come back to the main activity (onStart).
Is there a good way to ignore the calls of my own activities and only react on calls from "outside", f.e. I only want to synchronize if the user stops the app by pressing the home button and I also want to synchronize only if the user returns to the app by starting it from the app dreawer or app switcher?
+++ SOLUTION +++
Now I found a solution for my problem and I want to share it. Maybe it's not the best way because it's no SDK-based functionality but it works and it's quite simple.
I declared a flag, set it to false when the activity is created. Everytime I start another activity in the same app, I will set the flag to true and check its state in onPause and onResume.
public class MainActivity extends Activity {
private boolean transition;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
transition = false;
}
private void startSettingsActivity() {
transition = true;
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
}
private void doSync() {
// all steps for the cloud synchronization
}
#Override
protected void onResume() {
super.onResume();
if (!transition) {
// this is the case the user returns from
// the app drawer or app switcher or starts
// the app for the first time, so do sync
doSync();
} else {
// this is the case the user returns from another
// activity, so don't sync but reset the flag
transition = false;
}
}
#Override
protected void onPause() {
if (!transition) {
// this is the case the user presses the home button or
// navigate back (leaves the app), so do final sync
doSync();
} else {
// this is the case the user starts another activity, but
// stays in the app, so do nothing
}
super.onPause();
}
}

Method unnecessarily getting called?

I have a BaseActivity that gets extended by every other activity. The thing is, I have the music muted whenever the user leaves (onPause) the activity. I also stop listening for telephone calls. The problem is, onPause is getting called whenever the user switches between activities, meaning the app is unnecessarily muting and stopping telephonymanager, even though it should only be muting and stopping telephonymanager if the user were to leave the app.:
#Override
protected void onPause() {
Log.v(TAG, "IN onPause!");
// unregister phone listener to telephony manager
tManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
mute();
super.onPause();
}
Now say I switch between public class myClass extends BaseActivity and switch to public class myOtherClass extends BaseActivity. This switch is unnecessarily executing onPause, even though I only want onPause to be called when the user leaves the app. What should I do?
Thanks for the expert advice,
Rich
From my understanding you are muting your music playing in onPause of BaseActivity, instead of that write it inside your Music play activity
Ex :
public class BaseActivity extends AppCompatActivity{
#Override
public void onPause(){
//do things that common for all activities
}
}
public void MusicPlayActivity extends AppCompatActivity{
#Override
public void onPause(){
music.mute()
}
}
This will work
UPDATE
There are few ways to detect whether your application is running in the background, but only one of them is completely reliable:
Track visibility of your application by yourself using Activity.onPause, Activity.onResume methods. Store "visibility" status in some other class.
Example
: Implement custom Application class (note the isActivityVisible() static method):
public class MyApplication extends Application {
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
private static boolean activityVisible;
}
Register your application class in AndroidManifest.xml:
<application
android:name="your.app.package.MyApplication"
android:icon="#drawable/icon"
android:label="#string/app_name" >
Add onPause and onResume to every Activity in the project (you may create a common ancestor for your Activities if you'd like to, but if your activity is already extended from MapActivity/ListActivity etc. you still need to write the following by hand):
#Override
protected void onResume() {
super.onResume();
MyApplication.activityResumed();
}
#Override
protected void onPause() {
super.onPause();
MyApplication.activityPaused();
}
ActivityLifecycleCallbacks were added in API level 14 (Android 4.0). You can use them to track whether an activity of your application is currently visible to the user. Check Cornstalks' answer below for the details.
From your comments you only want to stop the music when the last Activity of your application is exiting. Overriding the finish() method of your BaseActivity like this should accomplish what you want:
#Override
public void finish() {
super.finish();
if (isTaskRoot()) {
// This is the last Activity in the stack so mute your music here...
}
}
Actually you probably want onDestroy() or onStop() as I'm not sure finish() executes unless you call it but the idea is the same:
#Override
protected void onDestroy() {
super.onDestroy();
if (isTaskRoot()) {
// This is the last Activity in the stack so mute your music here...
}
}
Here's info on isTaskRoot():
Return whether this activity is the root of a task. The root is the first activity in a task.
Returns
True if this is the root activity, else false.

Best way to implement "check if app comes from background" in android

I have been reading the answers in other post about this topic, but i have not found what is the best of all the approaches.
This is my approach i have now, but i do not know if it worst all the time (as far as i tested every worked for my) or if there is a better way.
public class FatherClass extends Activity {
private static int activities = 0;
public void onCreate(Bundle savedInstanceState, String clase) {
super.onCreate(savedInstanceState);
}
protected void onRestart()
{
super.onRestart();
if(activities == 0){
Log.i("APP","BACK FROM BACKGROUND");
}
}
protected void onStop(){
super.onStop();
activities = activities - 1;
}
protected void onStart(){
super.onStart();
activities = activities + 1;
}
}
Explanation: the onStart is executed one the activity is "visible" and the onStop when the activity is "not visible". So when your APP (it says APP not activity) goes to background all the activities are "not visible" so they execute the onStop method, so the idea behind this is to add one each time an activity es started, and subtract one each time an activity es hided, so if the value of the variable "activities" is 0 "zero" that means that all the activities that where started in some point are now not visible, so when you APP returns from background and executes the onRestart method on the activity in "front" you can check whether comes from background or is just restarting an activity.
I would appreciate some feedback regarding this topic.

Categories

Resources