I have a service which has a method that downloads an image from an URL and returns an Uri.
That service will get more complex when it has all the intended features. Therefore,
I'm invoking its methods within a thread.
My problem is how to warn the activity that the service has done it's work.
I could change a class isFinished variable but the activity had to be constantly checking
for its value.
I just want the service to tell the activity that it's work is done and the resources are
available for use.
I thought something in the lines of the service calling stopSelf() and the activity was
warned through "onServiceDisconnected" but that didn't seem very "political correct".
Thanks in advance
There are two ways to do it.
1. You can start your activity using by firing an intent.
2. You can Broadcast an intent and write receiver for it in your app when your receiver receives intent and onreceive method is called in this method you can start your activity using intent.
cheers...
public class MyActivity extends Activity{
public MyActivity() {
...
MyThread thread = new MyThread(this);
thread.start();
}
public void onFinishedThread(...) {
}
}
class MyThread extends Thread {
MyActivity activity;
public MyThread(MyActivity activity) {
this.activity = activity;
}
public void run() {
// do work
...
this.activity.onFinishedThread(...);
}
}
Related
First question:
How can we use
ActivityManager activity =(ActivityManager)getSystemService(ForegroundApp.ACTIVITY_SERVICE)
And also
getPackageManager in a class that extends Thread?? I'm trying to fetch the Foreground activity's package name, its start time and end time in the foreground. I know this is Context based but I need to run this is in a thread.
Second Question:
How can we call an abstract class that extends thread in a service??
This thread only runs when the screen is ON. So, I'll be registering for Screen ON and OFF intents in a service. In this service, when the screen is on, i need to call this Thread.
Example:
abstract class A extends Thread {
abstract method met();
public void run() {
//Find out foreground's app name and its start and end time.
}
}
class B extends service {
//Here i need to call A.
}
All what you have to do is simply pass an reference to your Activity in first case to class A, and reference to class A to class B. Easiest way is to pass by constructor.
abstract class A extends Thread {
protected Activity activity;
public A(Activity activity) {
this.activity = activity;
}
abstract method met();
public void run() {
// activity.yourmethods()
//Find out foreground's app name and its start and end time.
}
}
I pass a handler created on mainUI thread from Activity and passed to a thread which performs some network operation and when i obtain result i send the result back to the activity using the handler.
This approach had issue in memory leaks when i went through these links: Inner ClassHandler Memory Leak Android Developers
So i had implemented WeakReference, and kept the activity instance using WeakReference. But i am still seeing Activity instance alive even after activity is destroyed.
I created a Handler inside activity and passed activity instance as weakreference to handler.
By the time my Handler responds with a message delivered to it after 10secs, Activity is destroyed. But the weak reference still has the Activity instance and i am seeing the Toast, after Activity is destroyed.
Is there some where my understanding wrong ? Can someone explain how to handle messages delivered to a handler,but the UI is not around ?
import java.lang.ref.WeakReference;
import android.os.Handler;
import android.os.Message;
public abstract class SingleParamHandler <T> extends Handler
{
private WeakReference<T> mActivityReference;
public SingleParamHandler(T activity) {
mActivityReference = new WeakReference<T>(activity);
}
#Override
public void handleMessage(Message msg) {
if (mActivityReference.get() == null) {
return;
}
handleMessage(mActivityReference.get(), msg);
}
protected abstract void handleMessage(T activity, Message msg);
}
import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.widget.Toast;
public class MainActivity extends Activity {
MyHandler<MainActivity> handler;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main1);
handler = new MyHandler<MainActivity>(this);
new Thread(new MyRunnable(handler)).start();
}
public void onDestroy() {
super.onDestroy();
System.out.println("######## Activity onDestroy() ###### ");
}
private class MyRunnable implements Runnable {
private Handler mHandler;
public MyRunnable(Handler handler) {
mHandler = handler;
}
public void run() {
try {
Thread.sleep(10000);
mHandler.sendMessage(Message.obtain(handler, 1));
} catch ( Exception e) {
e.printStackTrace();
}
}
}
private static class MyHandler<T> extends SingleParamHandler<T> {
public MyHandler(T activity) {
super(activity);
}
#Override
public void handleMessage(T act, Message msg) {
if(msg.what == 1) {
Toast.makeText((MainActivity)act, "Called after activity destroyed", Toast.LENGTH_LONG).show();;
}
}
}
}
Based on the response obtained, i am updating the answer here. You may do it in the way u liked. But this is one way.
Added the below function in SingleParamHandler
public void clear() {
mActivityReference.clear();
}
And in Activity onDestroy()
public void onDestroy() {
super.onDestroy();
System.out.println("######## Activity onDestroy() ###### ");
handler.clear();
}
You don't need a WeakReference here. The Handler can just contain a reference to the Activity. In activity's onDestroy() just call a method on MyHandler that sets the reference to the Activity to null. Check for null in handleMessage().
Another choice would be this: in activity's onDestroy() call a method that interrupts the sleeping thread so that it shuts down before sending the message.
There's no guarantee that Android will really delete an object from memory if it's not required to do so. In other words, Activity objects can stay in memory even after onDestroy() has been called (if there's enough memory available). On the other hand, there's no guarantee that onDestroy() will be called if there's not enough memory; quite to the contrary, Android is allowed to kill your whole process after calling onPause() on your current Activity (depending on the Android version).
I think there's a better path to follow for your purpose. What you may want to do is attach, detach and possibly re-attach (e.g. on configuration changes) Activities to your Service. Don't hope for the garbage collector to do the work for you. Rather, make it explicitly.
Subclass Activity and override the lifecycle methods as well as startActivity() and startActivityForResult() to let your Service know who's in charge right now. Of course, that's only a best-effort approach since some callbacks aren't guaranteed, but that only matters in certain situations which aren't dangerous. For example, your Activity won't detach from your Service in onPause(), but it could get killed right afterwards. But either your Service runs in the same process, so it gets killed at the same time. Or it runs in a different process, but then Android will notice the broken connection and may or may not kill the service as well; if not, then all you need to do is implement it in a robust fashion to be able to deal with the connection loss.
Update
After reading your comment: You're right, I didn't address that specifically.
i am figuring out how to avoid messages being sent to a handler which is created in a activity which is destroyed
Given your code above, and assuming that you really just want to display Toasts with an Activity as long as it exists, the following approach should help.
If your Thread is supposed to serve more than one Activity, extend it such that Activities can register with the Thread after it is created. If your Thread just serves one Activity, pass the Activity reference along with the Handler reference upon your Thread's (Runnable's) construction.
Before your Thread sends the message via the Handler, check activity.isDestroyed(). If the Activity is not destroyed, send the message. If the Activity is destroyed, do not send the message.
Depending on whether your Thread should server more than one Activity, either exit it's Runnable's run() method or set it's Activity reference to null if it finds that the Activity has been destroyed.
This should fix your above code. However, if your scenario grows, other approaches may be more suitable.
I have several activities which use several audio features. For that, I have a MediaPlayer in a singleton java class, so the activities interact with that class and just exist on the media player.
One of the features is to stop automatically the media player after X minutes. So I created a timer in the singleton class and stops perfectly the radio streaming. the problem is that there is no feedback or callback to the running activity. There is a play/stop button wich has to change the image and I do not know how can I capture that onStop event or whatever....or can be called from a single java class the current activity class running, so I could call a function of the activity in order to change the image?
You probably want to use a broadcast receiver for this.
From your singlton class which does the stopping, when your timer stops the music, call this method:
public void broadcastMusicPaused(View v){
Intent broadcast = new Intent();
broadcast.setAction("MUSIC_STOPPED");
sendBroadcast(broadcast);
}
Then, from your controlling activity, set up your receiver like this:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(), "Music Paused", Toast.LENGTH_SHORT).show();
displayMusicStopped(); //switches images
}
};
#Override
protected void onResume() {
IntentFilter filter = new IntentFilter();
filter.addAction("MUSIC_STOPPED");
registerReceiver(receiver, filter);
super.onResume();
}
#Override
protected void onPause() {
unregisterReceiver(receiver);
super.onPause();
}
First of all, thanks jameo for his answer, sounds pretty good, but i do not know if i will have time to try, i promise i will if i can this week or next time i have a similar issue.
Finally i did the trick this way:
1 - Create a Interface with Method onStopMediaPlayer(); //For example call MediaPlayerStopInterface
public interface MediaPlayerStopInterface {
/**
* Called when the player timer ends
*/
public void onStopMediaPlayer();
}
2 - My activities classes implements the interface switching images.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onStopMediaPlayer(){
//Switch images or whatever
}
}
3 - My singletton class has an object of the type of the interface MediaPlayerStopInterface
public class AudioControllerClass { //The Singletton Java Class
private MediaPlayerStopInterface currentActivity;
public void setCurrentActivity(MediaPlayerStopInterface mpsi){
currentActivity=mpsi;
}
}
4 - My activities classes in onResume() do a Singlettonclass.setStoppedPlayerInterface(this), so i always have a reference of the running activitie.
public class PortadaActivity extends Activity implements MediaPlayerStopInterface{
public void onResume() {
AudioControllerClass.getInstance(getApplicationContext()).setCurrentActivity(this); //In every resume the singletton class knows who was the last one in being active
}
}
5 - when timer execute, as i have the activitie class reference, i just call object_StoppedPlayerInterface.stoppedPlayer();
public class AudioControllerClass { //The Singletton Java Class
class TimerRadio extends TimerTask {
public void run() {
if(whatever==true){
currentActivity.onStopMediaPlayer();
}
}
}
}
Finally, i didn't code it, but the callback to onStopMediaplayer in activities must be done with a Handler, if you do not want a "Only UI thread can touch his views" exception :P
It works perfectly :). But i don't know if it is a really bad practice or is not so horrible xD
Anyway thanks Jameo. Yours sound much more elegant :P
I have tried almost all the solutions from SO but no success :(.
I have a simple myJavaClass.java with a couple of functions.
One of the functions in myJavaClass : startActivity() starts MyCustomActivity
public startActivity(Context context)
{
Intent intent = new Intent(context, MyCustomActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
This launches MyCustomActivity() as expected.
Now I have another function in myJavaClass.java to close/finish MyCustomActivity but it is not able to do so!
I have tried
Making MyCustomActivity SingleTop in manifest and creating the activity via an intent as above
Passing an activity instance to "this" in onCreate() of MyCustomActivity and calling MyCustomActivity.activity.finish() from myJava.class but that doesnt work as well
Please help me. I have been stuck here for hours now. I know the solution is very simple and conceptual but I am a newbie. Just building Java/Android concepts!
EDIT
MyCustomActivity
public Activity activity;
OnCreate()
{
...
this = activity;
}
MyJavaClass
public closeActivity(Context context)
{
Activity customActivity = MyCustomActivity.activity;
customActivity.finish();
}
I think that what you are trying to do is fundamentally bad. For a start, outside of the Activity code, there are no guarantees that the activity still exists - the memory manager may have cleaned it up, the user may have pressed Back etc. Think of Activities as independent entities - you can start them, and you can optionally get a result back when they finish what they're doing, but that's it.
Think about whether you really have to programmatically close the activity from outside it - I'd say this is an unusual design, but there are circumstances where it may be appropriate.
If so, what I think you want is a publish/subscribe system whereby MyCustomActivity can register a listener with MyJavaClass, and then receive a callback whereupon it can 'finish' itself.
public Activity activity implements FinishListener
{
public void onCreate(...)
{
//where does MyJavaClass come from? see in a minute
MyJavaClass myjava = getMyJavaclass();
myJava.addFinishListener( this );
}
public void onFinishCallback()
{
this.finish();
}
}
and
public class MyJavaClass
{
private List<FinishListener> finishListeners = ...;
public void addFinishListener( FinishListener fl )
{
this.finishListeners.add(fl);
}
public closeActivity(Context context)
{
for ( FinishListener fl : finishListeners )
{
fl.onFinishCallback();
}
}
}
and
public interface FinishListener
{
void onFinishCallback();
}
Now the only remaining issue is how to get MyJavaClass from the Activity. That's up to you - you may already know how, you may be able to put it in your Application implementation, it could be a singleton (bad), the listeners could be static (bad) or various other options.
Oh, and don't forget to remove the listener again in the Activity's onDestroy() method!
Just try this....
public closeActivity(Activity _activity)
{
_activity.finish();
}
you can't finish activity from other class until you have the reference of instance of Activity in that class, give the reference in that class and call finish() method to stop the activity.
activity.finish();
I am calling a subactivity from main activity. This subactivity should take few numbers from user (i'm using Edit text control to achieve this), save them to static variable in another class and terminate. I want main activity to wait for subactivity but both are just running simultaneously. Even doing sth like that doesn't help:
Thread t = new Thread(new Runnable(){
public void run(){
Log.v("==================", "run "+new Date());
startActivityForResult(new Intent(ctx,myCustomSubactivity.class),1);
} });
Log.v("==================", "calling run "+new Date());
t.start();
try {
t.join();
} catch (InterruptedException e) {Log.v("==================", "can't join");}
Log.v("==================", "back from activity "+new Date());
do you know how to force main activity to wait? Thread.wait() method is not supported in Android(program throws error).
May be I'm missing something but why don't just use startActivityForResult and onActivityResult mechanism? You could get result from you subactivity from intent it was resulted with.
Edit: BTW as far as I understand, if you will run Object.wait() from Activity code if will hold UI tread whitch can result in Application not responding error.
I agree with Nikolay this is definitely the android way to do this.
Start the subactivity with startActivityForResult in the sub activity use setResult to add an result code and an intent with all the numbers you need in the data bundle.
In your first activity overwrite onActivityResult and retrieve the numbers from the Intent.
If you use the static variable this seems easier in the first moment but it is very insecure and there are some cases this may not work. If your program is send to the background your activities will be saved but if the phone runs low on memory the system will close your program and after the user resumes it everything looks like the moment the user left it but the static variables will be recreated to their initialization value.
Try to get used to the way the android activity lifecycle works. Using this approach will result in fewer used memory and a much better user experience.
Check out the Notepad example, it covers exactly this situation. And as others have said, the Android way is to have your first activity start up your second activity (not sub-activity!) and asynchronously listen for a response (not pause or wait, no need for joining, etc.).
Well... you can do it like this (btw, there's not straight forward way):
Have a singleton class, let's call it Monitor:
public class Singleton
{
private Singleton() { }
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
public class ParentActivity extends Activity
{
private void startAndWait()
{
Intent i = new Intent();
// initialize i
startActivityForResult(i);
Singleton si = Singleton.getInstance();
synchronized(si)
{
si.wait();
}
//do remaining work
}
}
public class ChildActivity extends Activity
{
protected void onCreate(Bundle savedInstance)
{
//do all the work
Singleton si = Singleton.getInstance();
synchronized(si)
{
si.notify();
}
}
}
I'm not here to judge if it's a good pattern or not but if you really need an activity to wait for a sub-activity, you can try this approach:
define an object (lock) over which the two activities get synchronized; this can (should) also work as the object to exchange data between those two activities and thus should be defined as static
in parent activity, start an async task (as the UI main thread cannot be in waiting state)
in the async task, start your sub-activity
the async task waits on the lock till it gets notified
the sub-activity does whatever it needs and notifies the waiting thread when it finishes
I did a similar thing in my app and IMHO had a good reason for this (not to bother a user with login screen upon app start or resume, the app tries to re-use credentials stored in a secured place and only in case it fails, it shows this login screen. So yes, basically any activity in my app can get "paused" and waits till the user provides correct credentials in the login activity upon which the login screen finishes and the app continues exactly where it got paused (in the parent activity).
In the code it would be something like this:
ParentActivity:
public class ParentActivity extends Activity {
private static final String TAG = ParentActivity.class.getSimpleName();
public static class Lock {
private boolean condition;
public boolean conditionMet() {
return condition;
}
public void setCondition(boolean condition) {
this.condition = condition;
}
}
public static final Lock LOCK = new Lock();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parent_layout);
// do whatever logic you need and anytime you need to stat sub-activity
new ParentAsyncTask().execute(false);
}
private class ParentAsyncTask extends AsyncTask<Boolean, Void, Boolean> {
#Override
protected Boolean doInBackground(Boolean... params) {
// do what you need and if you decide to stop this activity and wait for the sub-activity, do this
Intent i = new Intent(ParentActivity.this, ChildActivity.class);
startActivity(i);
synchronized (LOCK) {
while (!LOCK.conditionMet()) {
try {
LOCK.wait();
} catch (InterruptedException e) {
Log.e(TAG, "Exception when waiting for condition", e);
return false;
}
}
}
return true;
}
}
}
ChildActivity:
public class ChildActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.child_layout);
// do whatever you need in child activity, but once you want to finish, do this and continue in parent activity
synchronized (ParentActivity.LOCK) {
ParentActivity.LOCK.setCondition(true);
ParentActivity.LOCK.notifyAll();
}
finish();
// if you need the stuff to run in background, use AsyncTask again, just please note that you need to
// start the async task using executeOnExecutor method as you need more executors (one is already occupied), like this:
// new ChildAsyncTask().executeOnExecutor(ChildAsyncTask.THREAD_POOL_EXECUTOR, false);
}
}