Receive Android activity events from outside the activity? - java

Is there a way for us to receive events such as onResume, onWindowFocusChanged, etc., from outside the activity? I would like to run some code when these events are raised in another class, which only has a reference to the activity.
EDIT: In my case, I can't modify the Activity class, or override it in a subclass.

These methods are called by the Android OS. The best you could do is for your Activity to have an instance of this other class, and you would make similar methods in that class that your Activity will call in its own lifecycle methods.
public class SomeOtherClass {
public void onResume() {
...
}
public void onPause() {
...
}
/* other similar methods */
}
public class MyActivity extends Activity {
private SomeOtherClass someOtherClass; // make sure to initialize this somewhere
#Override
protected void onResume() {
super.onResume();
someOtherClass.onResume();
}
#Override
protected void onPause() {
super.onPause();
someOtherClass.onPause();
}
/* and so one */
}

I ended up using Application.registerActivityLifecycleCallbacks for onResume, and Window.getCallback() for onWindowFocusChanged. Thank you #Karakuri for mentioning the first method in the comments.

Related

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.

Call method from another object-java

I'm doing some Android development and I have an object, which doing a specific task. When that task is done I need to inform my main method (Main Activity), which is constantly running, that the process has been finished and pass some information about it.
This may sound a bit unclear, so I'll give you an example:
Take a look at the setOnClickListener() method in Android:
Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
//This method is called on click
#Override
public void onClick(View v) {
//The View is passed in an anonymous inner class
}
});
It waits for a button to be clicked and calls the onClick(View v) method. I am seeking to achieve the same code structure. How to do this?
You mentioned "process". If you are truly doing something in a different process, then you need to look at interprocess communications (IPC). Otherwise, you can use an interface:
Create a class called MyListener:
public interface MyListener {
void onComplete();
}
In your class that will notify your activity:
MyListener myListener;
public void setMyListener(MyListener myListener){
this.myListener = myListener;
}
Then, when you are ready to notify your main activity, call this line:
myListener.onComplete();
Last, in your MainActivity implement MyListener:
public class MyListener extends Activity implements MyListener {
///other stuff
#Override
public void onComplete(){
// here you are notified when onComplete it called
}
}
Hope this helps. Cheers.
This is exactly Listener pattern that you use with views in android. What you want to do is declare an interface in your class that's doing the job, and pass an instance of this interface. Raw example:
TaskDoer.java:
public class TaskDoer {
public interface OnTaskDoneListener {
void onDone(Data data);
}
public void doTask(OnTaskDoneListener listener) {
// do task...
listener.onDone(data);
}
}
Activity:
public void doTaskAndGetResult() {
new TaskDoer().doTask(new TaskDoer.OnTaskDoneListener() {
public void onDone(Data data) {
// do something
}
}
}

Fragment communicating with an Activity

I am confused about how communication with a Fragment and an Activity is made. For example, an interface was defined here (https://developer.android.com/training/basics/fragments/communicating.html).
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
...
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// The user clicked on a list item.
mCallback.onArticleSelected(position);
}
}
Eventually, the following method is called from the MainActivity.
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// Do something
}
}
My questions are:
How does mCallback "know" which onArticleSelected method to call (as there might be other classes that have implemented OnHeadlineSelectedListener).
mCallback.onArticleSelected(position);
I wouldn't be confused if it went:
mCallback = new OnHeadSelectedListener() {
#Override
public void onArticleSelected(int position)
// Do something
}
and then mCallback is referred in some way in MainActivity to utilize the onArticleSelected method in some way. In the example code, however, the line intelligently sticks to "an" interface. How does that happen?
Also, I found that the Log I implemented onArticleSelected method from MainActivity is called previously to the one in onListItemClick method in HeadlineFragment. Is it expected?
Since you defined the OnHeadlineSelectedListener interface with only one method, and your activity implements it, there's no ambiguity in choosing the method when you use the activity as instance of this interface, 'cause all you know about activity while using it as instance of OnHeadlineSelectedListener interface is a presence of onArticleSelected(int) method in it.
It depends on when you call the logging function - before or after calling the callback method.
P.S. While this kind of communication between Activity and Fragment (or any other objects) is perfectly fine, personally I prefer the Event Bus approach, 'cause it gives us a possibility to organize code in a low coupled manner. Here are some nice implementations of Event Bus pattern:
https://github.com/greenrobot/EventBus
http://square.github.io/otto/
Take a look at them if you are interested in this approach.
Your mCallback is your activity, in the onAttach method of your fragment, you will set the activity as listener for your fragment. By this way, this is normal that the activity is notified when you call mCallback.onArticleSelected(position);
For your first part of question
You should have a look on onAttach and onDetach methods-
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException("Activity must implement OnHeadlineSelectedListener.");
}
}
#Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
Second part-
The behavior is not expected.
You should not make your activity class static as well.

In android, when is a context different from "this"?

I am at baby step level of programming on Android (and in Java in general). I do understand that Activity inherits from the Context class. However in every code snippet I have come across, every time a context must be mentionned, it is set to "this".
My question is : when is a context different from "this" ? Could you provide an real life example of context needing to be different from "this"?
Thank you very much.
Typically, you will want to use this when you are "inside" of an Activity. However, when you are using for example a Helper class, the reference this will not work. An example can be something like this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
A case, where you cannot:
public class MyHelper
{
/* some code of yours */
public void lockOrientation(Activity activity)
{
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
}
}
The above code locks the orientation to the current orientation. Notice that you need to supply the method with an Activity parameter, since you cannot use:
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
In the first example, you could use this to achieve this, because you were "inside" of an Activity.
Another type of example, how do you set onClickListener.
First example, when you use this:
public class MyActivity extends Activity implements View.OnClickListener
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(this);
}
#Override
public void onClick(View v)
{
//handle the click event
}
}
In this example, you can use this because in the first line, we wrote implements View.OnClickListener, so the class inherits from the given interface. Without the implements thingie, you couldn't do it. An example of setting the onClickListener without this:
public class MyActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Button btn=(Button)findViewById(R.id.mybutton);
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
//handle the click event
}
});
}
}
In the second example, we are defining an Anonymous Inner Class, which will handle the click event of the button. Notice that in this case, our Activity does NOT implements View.OnClickListener.
In Outer Class you directly use "this" reference
In Inner Class Or Abstract Class implementation Or Interface implementation use "classname.this" reference
Example:
class Example{
int number = 0;
public Example(int number){
this.number = number;
}
}
notice that number in the contructor and number in the class are not the same. Altough they have the same name. Saying number = number doesn't make sense. Be using this you can asses number in the class.
For example when you are implementing an OnClickListener the "this" is different.
this is a reference to the current object — the object whose method or constructor is being called.
Inside an Activity's method this can be used as a Context object because Activity inherits from ContextThemeWrapper, which inherits from ContextWrapper, which inherits from Context.
A Fragment on the other hand does not inherit from Context. So to get the Context inside a Fragment you would have to call getActivity() for example.
This applies to any object you are calling this from.
Consider you are inside the OnClick() method of a View.OnClickListener and you want to start an Activity:
button.setOnClickListener (new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(this, NextActivity.class); // wrong because 'this' is the OnClickListener object
Intent intent = new Intent(CurrentActivity.this, NextActivity.class); // correct because 'this' is the CurrentActivity object
startActivity(intent);
}
});

add functionality to an onClickListener in a derived class

I've read many threads on how to create and handle Button clicks using onClickListener. However, I couldn't find anything that solved this problem.
I have a class myActivity and I would like to create a second class myExtendedActivity which extends myActivity by adding some extra functionality.
The class myActivity contains a lot of code which, for maintainability reasons, I don't want to duplicate. myExtendedActivity should behave exactly as myActivity with some extra function.
In particular in the onCreate method in myActivity I have the following code that add an onClickListener to my_button. The extended activity should just append a call to myExtraMethod.
myButton = (Button)findViewById(R.id.my_button);
myButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
[...] //a lot of code here
myExtraMethod();
}
});
Note that myExtraMethod simply broadcasts an Intent and it is not affected by any other part of the code in the Listener.
What I would like to do is to extend the OnClickListener in myExtendedActivity so that it first executes exactly the code written for myActivity and than myExtraMethod defined in myExtendedActivity.
I don't want to modify myActivity which should be completely unaware if myExtendedActivity is included in the project or not.
Thank you very much
Completely without modifying myActivity is barely possible.
You could use something like this in MyActivity (Some variant of the Template method pattern):
onCreate() {
myButton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
myMethod();
}
});
}
protected void myMethod() {
[...] //a lot of code here
}
And then in MyExtendedActivty:
#Override
protected void myMethod() {
super.myMethod();
myExtraMethod();
}
If I understood your question right, the solution might be something like this:
In your layout for button you define the onClickListener from xml:
<Button
android:id="#+id/myButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="handleButtonClick"
/>
Then, in MyActivity you implement method:
public void handleClick(View view) {
}
And in MyExtendedActivity you override it:
public class MyExtendedActivity extends MyActivity {
#Override
public void handleClick(View view) {
super.handleClick(view);
//your code goes here
}
}
Without modifying myActivity, you can't because you're instantiating an anonymous class, and the subclass has no way to "hook in" to that anonymous class.
If you can modify myActivity, then you could make the anonymous class from myButton.setOnClickListener(...) a static class, and in your subclass extend the listener class calling super.onClick(v), followed by the functionality you expect.
Then add a method to get the correct listener
myButton.setOnClickListener(createMyButtonsListener())
that you can then override in the subclass providing the extended version.
Alternatively, add a method that can be overriden in a subclass (i.e. myExtraMethod()). that is called within your anonymous class.

Categories

Resources