Eventbus event subscribers - java

I was learning Event bus(http://greenrobot.org) in android and i have following code
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
EventBus.getDefault().post(new Message("John Testing this event"));
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventOne(Message message) {
Log.d("ApiCall_1",message.getMessage());
Toast.makeText(getApplicationContext(), message.getMessage(), Toast.LENGTH_SHORT).show();
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEventTwo(Message message) {
Log.d("ApiCall_2",message.getMessage());
Toast.makeText(getApplicationContext(), message.getMessage(), Toast.LENGTH_SHORT).show();
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
The above trigger both subscribers onMessageEventOne and onMessageEventtwo.So my question is
1.Is there any way to trigger particular subscriber ?.

With an EventBus you are subscribing to broadcasts of a certain type. If you want different functions to be called in the same activity you will need to broadcast different types.

I assume event bus are using java pojo object as an identifier and sending events to all registered receiver objects at a time.
http://greenrobot.org/eventbus/documentation/how-to-get-started/
So define 2 pojo classes and you have to change:
EventBus.getDefault().post(new Message("John Testing this event"));
to
// Event type one
EventBus.getDefault().post(new MessageOne("John Testing this event"));
// Event type two
EventBus.getDefault().post(new MessageTwo("John Testing this event"));

Related

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.

Create service to detect any action from the user

I'm trying to create a service where I want to detect something about user, let's say when user lays the device on a table, the thing is that I have that action detected but I have it on a MainActivty and I want it to put on Service.
The thing is that on my MainActivity() I had my registerAction() and on my onResume() were called and in onPause() I call the unregisterListener() from my sensor, as well I have a HandlerThread where I start it on my onCreate() how do I change it to Service? Would be a problem? I see that there aren't the same methods...
I've created my Service and I've got :
public class MyService extends Service {
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
Log.d("CREATE","ONCREATE");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("DESTROY","ONDESTROY");
}
}
Also my MainActivity I have put implements SensorEventListener.
A skeleton of my class is :
public class MainActivity extends Activity implements SensorEventListener {
private HandlerThread mSensorThread;
private SensorManager mSensorManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensorThread = new HandlerThread("sensor_thread");
mSensorThread.start();
}
private void registerSensorListener() {
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST, new Handler(mSensorThread.getLooper()));
}
#Override
public void onSensorChanged(SensorEvent event) {
//DO stuff
if (isLayed()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d("LAY","LAYLAY");
}
});
mSensorManager.unregisterListener(this);
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private boolean isLayed() {
return stuff;
}
#Override
protected void onResume() {
super.onResume();
registerSensorListener();
}
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
}
EDIT
I'm using szamani20 code, but I'm having problems with runOnUiThread because I can not call from my Service also, I'm having this issue
java.lang.RuntimeException: Unable to start service com.example.developer.qwe.MyService#d8c613b with null: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.getAction()' on a null object reference
First of all you need to decide whether you want the user to be aware of your running service or not. Take a review on Background Execution Limits in android Oreo:
To improve the user experience, Android 8.0 (API level 26) imposes limitations on what apps can do while running in the background.
So considering your case where it seems there are lots of work to do in many situations, it would be a better approach to use a foreground service. As android document says about foreground services:
A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under the Ongoing heading. This means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
Since you mentioned that you have the action detected I won't enter that part of your code. So you need to create a subclass of Service as you did and use the startService method to get it's onCreate called. One thing you need to notice is that the onCreate method of service is called once you call startService on that service for the first time, no matter how many times you call startService again the onCreate method won't get called and only the onStartCommand get called. We use that fact alongside that you could provide a string action within your intent to properly register and unregister your listener.
In MainActivity.java:
String action = "start"; // Or to unregister listener "stop"!
final Intent intent = new Intent(this, MyService.class);
intent.setAction(action);
startService(intent);
and then in MyService.java:
#Override
public void onCreate() {
super.onCreate();
// Do initialization or whatever here (executed once per service lifecycle)
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals("start")) {
// Register your listener or whatever
showForegroundNotification();
}
if (intent.getAction().equals("stop")) {
// Unregister your listener or whatever
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
private void showForegroundNotification() {
Intent myServiceNotificationIntent = new Intent(this, MainActivity.class);
myServiceNotificationIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent
.getActivity(this, MY_SERVICE_REQUEST_CODE,
myServiceNotificationIntent, MY_SERVICE_FLAG);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(MY_SERVICE_NOTIFICATION_CONTENT_TITLE)
.setTicker(MY_SERVICE_NOTIFICATION_TICKER)
.setContentText(MY_SERVICE_NOTIFICATION_CONTENT_TEXT)
.setSmallIcon(R.drawable.ic_whatever)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(MY_SERVICE_NOTIFICATION_ID, notification);
}
Finally don't forget to unregister your listener in onDestroy in case of android kill your service (which is very rare):
#Override
public void onDestroy() {
super.onDestroy();
// Unregister your listener
}
You can register SensorManager inside service in OnStartCommand.Also try using startForeground as android os will kill your service when app is killed

Show alert dialog from background process in any activity

How to get result of background process in any Activity?
I'm working with OTA update. App handle that in background with handler. When update is done I have to show alert dialog to the user. I can show it in SettingsActivity where I start with OTA but user can be in any other Activity.
private void checkIsUpdated() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
mDevice.getDevice().read(GattUUID.LS_DEVICE_INFORMATION, GattUUID.LC_FIRMWARE, new
BleDevice.ReadWriteListener() {
#Override
public void onEvent(ReadWriteEvent e) {
if (e.wasSuccess()) {
if (firmwareVersion.equals(e.data_string())) {
showAlertDialog("OTA update failed", "Device is not updated");
} else {
showAlertDialog("OTA update is successful.\nDevice is updated to new " +
"firmware!", "Device is updated");
}
Log.i("OTA", "Read firmware is new success");
} else {
Log.e("OTA", "Read firmware is new success");
}
}
});
}
}, 30000);
}
AlertDialog code
private void showAlertDialog(String message, String title) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext, R.style.SwipeDialogLight);
builder.setTitle(title)
.setMessage(message)
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
if (!alert.isShowing()) {
alert.show();
}
}
As #W4R10CK stated, I thought that too. The BroadcastReceiver might not a very good idea. But later, I gave a thought about it and if you call checkIsUpdated function inside a Service and send the Broadcast from it, it might be a feasible solution.
So basically you need a BaseActivity class and in which you need to have a BroadcastReceiver. You need to register it onResume and again unregister it onPause.
And you need to have an abstract method to be overriden in each of your Activity too.
So your BaseActivity may look like this..
public abstract class BaseActivity extends AppCompatActivity {
private final Context context;
public BaseActivity() {
this.context = setContext();
}
protected abstract Context setContext();
#Override
public void onResume() {
super.onResume();
registerBroadcastReceiver();
}
#Override
public void onPause() {
super.onPause();
unRegisterBroadcastReceiver();
}
// Declare your BroadcastReceiver here
private class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
showAlertDialog(context);
}
}
}
As #rogerwar suggested in the comments, the correct approach is a broadcast receiver.
Vogella has a nice tutorial
Since you want to have it in all activities, you can make a base class for all your activities and in this base class you can register the receiver in the onStart and unregister it in the onStop.

Greenrobot EventBus3 not posting to my subscribers

In my application, I pass a job into the job-queue and in my Job queue, I've registered my EventBus and I am trying to post the event with the hopes that my subscriber method would receive it. I have just recently migrated from Otto's EventBus and while this way had previously worked, it is not working for greenrobots EventBus 3.
Here is a sample case for what I'm trying to achieve:
TestPresenterImpl.class (This class has been instantiated the TestActivity.class)
#Override
public void addJob(JobData jobData) {
jobManager.addJobInBackground(new SendUpdateJob(jobData));
}
#Subscribe
#Override
public void onUpdate(JobAddedEvent event) {
if (event.getStatus() == 1) {
Log.i(LOG_TAG, "test");
}
}
#Override
public void onStart() {
mBus.getDefault().register(this);
}
#Override
public void onStop() {
mBus.getDefault().unregister(this);
}
SendUpdateJob.class (This is the class that handles the jobs in the queue using the android-priority-job queue previously maintained by Path)
#Override
public void onAdded() {
Log.i(LOG_TAG, "On added");
mBus.getDefault().register(this);
JobAddedEvent event = new JobAddedEvent();
event.setStatus(1);
mBus.getDefault().post(event);
}
Normally this works on Otto but since this is a slightly different, I want to know what I'm doing incorrectly. The error I get is: ..."SendJobUpdate and its super classes have no public methods with the #Subscribe annotation". Am I doing something wrong here?
I've also made sure that I'm importing import org.greenrobot.eventbus.Subscribe;
because I've noticed others have pointed out that they have imported googles subscribe.
Your EventBus.getDefault().register(this); should follow your Activity which your #Subscribe method is in, not in mBus.getDefault().post(event); Activity.
FirstActicity
public class FirstActicity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//register should in this activity
EventBus.getDefault().register(this);
}
#Subscribe(threadMode = ThreadMode.MainThread)
public void onEvent(MessageEvent event) {
//eventbus notify
Log.i("2hh", "main --- eventbus ---- updatedata");
queryData();
}
#Override
protected void onDestroy() {
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
}
SecondActivity(don't register in this activity beacuse you didn't hava any #Subscribe method)
public class SecondActivity extends AppCompatActivity implements{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add);
EventBus.getDefault().post(new MessageEvent("updateData"));
}
}

Automatically log Android lifecycle events using ActivityLifecycleCallbacks?

I am trying to automatically capture and log Android lifecycle events using ActivityLifecycleCallbacks, however documentation on this matter is scarce, to say the least:
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
I don't want to have to extend the Activity class or override the existing lifecycle methods (onCreate, onResume, etc...) I'm looking to have a separate class listening for these events and acting accordingly.
Does anyone have any experience in this, or have links to good solid documentation or tutorials on how this works? Specifically, how to register for ActivityLifecycleCallbacks, and how to handle them?
I don't have any firsthand experience but judging from the API you can just write your own class that implements the Application.ActivityLifecycleCallbacks interface and register that class on the provided Application class instance
getApplicaton().registerActivityLifecycleCallbacks(yourCustomClass);
This class will receive the same callbacks as your individual activities. Good luck.
PS. This is API level 14 btw, so it won't work on older phones.
I did my own implementation of Application.ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.
First, I'm creating an interface that have all methods for track the activities lifecycle:
public interface ActivityLifecycleCallbacks{
public void onActivityStopped(Activity activity);
public void onActivityStarted(Activity activity);
public void onActivitySaveInstanceState(Activity activity, Bundle outState);
public void onActivityResumed(Activity activity);
public void onActivityPaused(Activity activity);
public void onActivityDestroyed(Activity activity);
public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}
Second, I implemented this interface in my Application's class:
public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onActivityStopped(Activity activity) {
Log.i("Tracking Activity Stopped", activity.getLocalClassName());
}
#Override
public void onActivityStarted(Activity activity) {
Log.i("Tracking Activity Started", activity.getLocalClassName());
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
}
#Override
public void onActivityResumed(Activity activity) {
Log.i("Tracking Activity Resumed", activity.getLocalClassName());
}
#Override
public void onActivityPaused(Activity activity) {
Log.i("Tracking Activity Paused", activity.getLocalClassName());
}
#Override
public void onActivityDestroyed(Activity activity) {
Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
Log.i("Tracking Activity Created", activity.getLocalClassName());
}
}
Third, I'm creating a class that extends from SherlockActivity:
public class MySherlockActivity extends SherlockActivity {
protected MyApplication nMyApplication;
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nMyApplication = (MyApplication) getApplication();
nMyApplication.onActivityCreated(this, savedInstanceState);
}
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
nMyApplication.onActivityResumed(this);
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
nMyApplication.onActivityPaused(this);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
nMyApplication.onActivityDestroyed(this);
}
#Override
protected void onStart() {
super.onStart();
nMyApplication.onActivityStarted(this);
}
#Override
protected void onStop() {
super.onStop();
nMyApplication.onActivityStopped(this);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
nMyApplication.onActivitySaveInstanceState(this, outState);
}
}
Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity:
public class MainActivity extends MySherlockActivity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication.
UPDATE
This implementation was tested from API Level 9 (Gingerbread), API Level 12 (Honeycomb) and API Level 17 (Jelly Bean) and works fine. Might works in Android's older versions.
Try this: http://engineering.meetme.com/2015/04/android-determine-when-app-is-opened-or-closed/#comment-202
It proposes an AppForegroundStateManager to which each activity reports through its onStop() and onStart() functions like this:
#Override
protected void onStart() {
super.onStart();
AppForegroundStateManager.getInstance().onActivityVisible(this);
}
#Override
protected void onStop() {
AppForegroundStateManager.getInstance().onActivityNotVisible(this);
super.onStop();
}
Your Application class implements a listener like this:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
AppForegroundStateManager.getInstance().addListener(this);
}
#Override
public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND.equals(newState)) {
// App just entered the foreground. Do something here!
Log.i(TAG, "App Just Entered the Foreground with launch mechanism of: " + mLaunchMechanism);
} else {
// App just entered the background. Set our launch mode back to the default of direct.
mLaunchMechanism = LaunchMechanism.DIRECT;
}
}
}
It also includes tips and tricks for determining how the app was opened - from a notification, a URL opening your app or directly from the Apps menu. This is done through an Enum in the Application class:
public enum LaunchMechanism {
DIRECT,
NOTIFICATION,
URL,
BACKGROUND
}
private LaunchMechanism mLaunchMechanism = LaunchMechanism.DIRECT;
public void setLaunchMechanism(LaunchMechanism launchMechanism) {
mLaunchMechanism = launchMechanism;
}
In our implementation of this, we have flags for when we start an activity that will launch a third-party activity, like if the user makes a phone call from our app or if a browser is launched. In the launching activity's onStop() we then do a check like this to only report the activity's not-visibility when those flags are false:
if(!flag_userLaunchedThirdPartyActivity){
AppForegroundStateManager.getInstance().onActivityNotVisible(this);
}
For checking whether or not the application goes into the background - for example when the device's screen goes dark or the user receives a phone call - it works like this:
public static boolean isApplicationGoingToBackground(final Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(context.getPackageName())) {
setLaunchMechanism(LaunchMechanism.BACKGROUND);
return true;
}
}
setLaunchMechanism(LaunchMechanism.DIRECT);
return false;
}
This solution is not dependent on an API level, so it should work all the way back to API level 1.
#Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(MyApplication.this/*(Your Application Name)*/);
}
Only add this line on Application class and all works well.

Categories