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"));
}
}
Related
I've created an interface which holds a reference to an interfaces instantiated from an activity.
This is the interface:
public interface Calback {
void fun();
}
This is the activity which instantiates the calback and binds it to asincktask.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView txt = findViewById(R.id.helloTxtv);
txt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Calback call = new Calback() {
#Override
public void fun() {
Log.d("tag","text of destroyed activity: "+((TextView)findViewById(R.id.helloTxtv)).getText());
}
};
Worker worker = new Worker(call);
worker.execute();
}
});
}
}
What's strange is that using that calback I can access textview even if the activity was destroyed.
This is the code from asyncktask:
public class Worker extends AsyncTask<Void, Void, Void> {
private final Calback call;
public Worker(Calback call) {
this.call = call;
}
#Override
protected Void doInBackground(Void... voids) {
try {
sleep(5000);
Log.d("tag","done");
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
call.fun();
}
}
To ensure that the activity it's destroyed I've just rotated the screen.(But I've got the same result after starting another activity and finish the current one)
And here is the log result.
PS: I've used Android Studio 3.0
If you are able to access the text of the TextView after the parent Activity has been destroyed, then you have a memory leak.
However, I'm not convinced that is what is going on here. I think it is more likely that either the activity has not been destroyed, or the activity's state was persistent and you are now looking at the state in the new (reincarnated) activity.
Why? Because, it seems that the callback is being called via an onClick listener for the text view. And that can only occur if the specific text view is still visible. It can't be visible if it is a component of a destroyed activity.
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"));
MyApplication application class has a listener that notifies an event listener (MainActivity - fragment activity) when fetchUpdates method is called.
Setup (showing only relavant part):
(1) MyApplication
public class MyApplication extends Application {
OnFetchStartListener mCallbackFetchStart = null;
public void setOnFetchStartListener(Activity activity) {
try {
mCallbackFetchStart = (OnFetchStartListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFetchStartListener");
}
}
public interface OnFetchStartListener {
public void onFetchStartListener();
}
public synchronized void fetchUpdates() {
// Informing listeners on fetchUpdates() start
if (mCallbackFetchStart != null) {
mCallbackFetchStart.onFetchStartListener();
}
String[] mURLs = getURLs();
new DownloadDataAsyncTask().execute(mURLs[0], mURLs[1]);
}
}
(2) MainActivity - FragmentActivity:
public class MainActivity extends SherlockFragmentActivity implements
MyApplication.OnFetchStartListener
static MyApplication myApp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myApp = (MyApplication) getApplication();
}
#Override
protected void onResume() {
myApp.setOnFetchStartListener(this);
super.onResume();
}
#Override
public void onFetchStartListener() {
//Some stuff
}
}
Question
How can I setup the listener in the application class to notify multiple event listeners? The event listeners may be of different classes, not just FragmentActivities.
I can create different listeners in the application class to notify different event listeners (a listener in the application class for each event listener) when fetchUpdates is called, but this doesn't strike me as very efficient.
About me
I just started programming. So detailed explanations are much appreciated.
Progress
Rciovati Suggested using EventBus. This solution might work, but will have to introduce a new (third-party) library in to the project.
I'm still looking for a solution without having to use a third-party library.
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.
private class ExecuteLocations extends AsyncTask<String, Void, Void>{
private final ProgressDialog dialog = new ProgressDialog(ListProfiles.this);
protected void onPreExecute() {
//this.dialog.setMessage("Starting pre-execute...");
//this.dialog.show();
}
#Override
protected Void doInBackground(String... arg0) {
check_profiles_lm=(LocationManager) ListProfiles.this.getSystemService(LOCATION_SERVICE);
myLocListen = new LocationListener(){
#Override
public void onLocationChanged(Location location) {
HashMap params = new HashMap();
params.put("lat", Double.toString(location.getLatitude()));
params.put("long", Double.toString(location.getLongitude()));
postData("http://mydomain.com",params);
}
#Override
public void onStatusChanged(String provider, int status,Bundle extras) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
};
check_profiles_lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 30000, 0, myLocListen);
return null;
}
protected void onPostExecute(final Void unused) {
if (this.dialog.isShowing()) {
//this.dialog.dismiss();
}
//Do something else here
}
}
Basically, my objective is:
Constantly post the latitude/longitude to my website every minute or so.
Of course, I want to do this in another thread, so it doesn't mess up my UI thread. This AsyncTask is supposed to solve that...but it's bringing up an error and I don't know why.
What can you do to accomplish my objective? It's very simple...just scan location and post to web every minute, in the background.
By the way, my onCreate method is like this. That's basically it.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new ExecuteLocations().execute();
setContentView(R.layout.main_list);
}
Break it into 3 steps:
Make whatever you want to work work w/o AsyncTask
Make sure you've figured out AsyncTask, do a simple Log.e("haha", "gotcha") in doInBackground(...) and check that it shows
Combine the two.
For this case, I'd probably go with a Service triggered by AlarmManager. Guess you'll need the latter anyways.
Create this as a Service. No need to have a Timer or AlarmManager as you register for location events and act appropriately.
An example of listening to location events can be found at
http://code.google.com/p/android-bluetooth-on-motion/source/browse/#svn/trunk/BluetoothOnMotion/src/com/elsewhat
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_NETWORK, MIN_DISTANCE_NETWORK,locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME_GPS, MIN_DISTANCE_GPS,locationListener);