I have about resuming multiple threads within the same Activity: I've three different threads in my app, that I call AThread, BThread and CThread.
If my app is closed and reopened, I need to reopen all preview Threads. How could I do that? I thought on returning a list of threads. Is that a good option? Something like:
#Override
public Object onRetainNonConfigurationInstance() {
return new ArrayList<Thread>(AThread, BThread, CThread);
}
And than, at the function onCreate, call a "for each" that verifies all Threads. Something like
#Override
public void onCreate(Bundle savedInstanceState) {
(...)
super.onCreate(savedInstanceState);
ArrayList<Thread> allThreads = (ArrayList<Thread>) getLastNonConfigurationInstance();
AThread = allThreads.get(0);
BThread = allThreads.get(1);
CThread = allThreads.get(2);
if (AThread != null && AThread.isAlive()) {
// TODO SOMETHING
}
if (BThread != null && BThread.isAlive()) {
// TODO SOMETHING
}
if (CThread != null && CThread.isAlive()) {
// TODO SOMETHING
}
}
Is that correct? Any better Idea?
Cheers =)
Use a Fragment to host your Threads (or more preferably an AsyncTask) and call setRetainInstance(true) in the Fragment's onCreate method. The Fragment will be retained across configuration changes and the Fragment (and its Threads) won't be destroyed along with the Activity. I believe this is preferred over using onRetainNonConfigurationInstance.
Related
I want to know which method constantly calls when fragment is running? Is it onResume(). I have a condition (if statement), i want that the fragment constantly checks the condition and if it is true do the following task that i want to do.
For example:
if (heartdata >= 100 || bloodata >= 120 || tempdata >= 100)
{
sendMessage();
}
Where should i put this IF statement so that the android fragment/app constantly checks the condition and call the sendMessage();
i put the code in onCreate() it didn't worked i also put that in onCreateView() but didn't worked please tell me where to put this code..
The solution is to use a TimerTask and schedule it at regular intervals using Timer because Fragment Life cycle methods won't be called repeatedly while fragment is stable and running. Paste below code in onViewCreated method of your fragment
Example
Timer timer = new Timer(); //Global declaration
public void onViewCreated(..){
...
timer.schedule(new TimerTask() {
#Override
public void run() {
if (heartdata >= 100 || bloodata >= 120 || tempdata >= 100)
{
sendMessage();
}
}
},60 * 1000); // Which will run for every 60 seconds
...
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
}
You can view the Fragment life-cycle here. Basically there is no method that "constantly checks". For example the method onResume() is called only when a the fragment is resumed.
If you want to constantly check if a condition is satisfied, i'd suggest creating a background thread and running the code you stated above inside that thread. Once the condition is met, send your message.
Create a boolean named isRunning
In onResume set isRunning to true and in onPause set it to false.
Or use onStart and inStop thatever you want.
And then your while statement:
while(isRunning) and do whatever you want there...
However I am not really sure if this is good for performance
P.S.: Use while or maybe for if you want to do aciton repeatedly.. not if... if is kind of check
I think for this purpose you should use a new Thread in which you continuously checking that condition and when that condition is reached give callback to fragment.
Try this code, it will check every 1SEC
public class MyFrag extends Fragment {
Runnable runnable = new Runnable() {
#Override
public void run() {
if(getActivity()!=null) {
mHandler.postDelayed(runnable, 1000);
}else{
mHandler.removeCallbacks(runnable);
return;
}
//Your check code will here
}
};
Handler mHandler = new Handler();
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mHandler.postDelayed(runnable,1000);
}
}
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I have an AsyncTaskLoader to do some work on the first startup. The loader is initialized in the OnCreate method of my Activity.
if(!startedLoader) {
getLoaderManager().initLoader(INITIALIZE_DB_LOADER_ID, null, this);
startedLoader = true;
}
startedLoader is a boolean that is kept in onSaveInstanceState and retrieved again in onCreate.
This avoids my loader to restart. But now it does not deliver the results through the callbacks because my listener, which is my activity itself, was destroyed.
Here's the code that starts my Loader:
#Override
public Loader<Boolean> onCreateLoader(int id, Bundle args) {
return new InitalizeDatabaseLoader(this);
}
How can I avoid my AsyncTaskLoader to restart on an orientation change but still deliver the results?
You have to extend the deliverResult() method and keep the result in memory until the activity reconnects to the loader.
You can find here a pretty good example: http://developer.android.com/reference/android/content/AsyncTaskLoader.html
The essential part is:
/**
* Called when there is new data to deliver to the client. The
* super class will take care of delivering it; the implementation
* here just adds a little more logic.
*/
#Override public void deliverResult(List<AppEntry> apps) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (apps != null) {
onReleaseResources(apps);
}
}
List<AppEntry> oldApps = mApps;
mApps = apps;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(apps);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldApps != null) {
onReleaseResources(oldApps);
}
}
Also, you will want to extend the onStartLoading() method, in order to deliver the cached result right away:
/**
* Handles a request to start the Loader.
*/
#Override protected void onStartLoading() {
if (mApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mApps);
}
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || mApps == null || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
I have this problem every time I use loader. If I start my AsyncTaskLoader and then rotate screen (doesn't matter one or several times) onLoaderFinished() is not called. loadInBackground() finishes its work but onLoaderFinished() is not called. It looks like callbacks are missed but in activity onCreate() I have:
LoaderManager lm = getSupportLoaderManager();
if (lm.getLoader(LOADER_FLIGHTS) != null) {
lm.initLoader(LOADER_FLIGHTS, null, mFlightsLoaderCallbacks);
}
Doesn't matter callbacks are implemented by activity or field. In my case I use field:
LoaderCallbacks<SearchResult> mFlightsLoaderCallbacks = new LoaderCallbacks<SearchResult>() {
Sometimes it works pretty good but in some devices I have got this trouble again.
I searched in Android bugs tracker but found nothing useful.
Is this my mistake and how can I correct it?
EDIT:
private Handler mHandler = new Handler();
#Override
public void onLoadFinished(Loader<SearchResult> loader, SearchResult res) {
mHandler.post(new Runnable() {
#Override
public void run() {
dismissProgress(R.string.dlg_wait_flights);
}
});
mResult = res;
Helper.Log.d(TAG, "Loader.onLoadFinished.");
Don't wrap your initLoader call in an if statement. In fact, I'm not even sure how initLoader is ever called if you are expecting the loader to not be null before you even call initLoader.
I have used AsyncTasks with my application, in order to lazy download and update the UI.
For now my AsyncTasks updates the UI real simply:
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
gender.setText(values[0]);
}
My problem is how to check if the activity which the gender TextView rendered from, is still available?
If not, I will get an error and my application will shut down.
You can cancel your asynctask in the activity's onDestroy
#Override
protected void onDestroy() {
asynctask.cancel(true);
super.onDestroy();
}
and when performing changes you check whether your asynctask has been cancelled(activity destroyed) or not
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if(!isCancelled()) {
gender.setText(values[0]);
}
}
I had a similar problem - essentially I was getting a NPE in an async task after the user had destroyed the fragment. After researching the problem on Stack Overflow, I adopted the following solution:
volatile boolean running;
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
running=true;
...
}
public void onDestroy() {
super.onDestroy();
running=false;
...
}
Then, I check "if running" periodically in my async code. I have stress tested this and I am now unable to "break" my activity. This works perfectly and has the advantage of being simpler than some of the solutions I have seen on SO.
Try
if (!isFinishing()) {
gender.setText(values[0]);
}
Check whether activity is running or not
if (!isFinishing()) {
// Do whatever you want to do
}
I will insist that you that if you Activity is not running why don't you cancel the AsyncTask?
That would be a better and feasible solution. If you Application is running say you move from one Activity to another then it won't give error AFAIK.
But, I would insist to cancel the AsyncTask then you'r Activity is not running, you can check AsyncTask is running or not,
if(task != null && task.equals(AsyncTask.Status.RUNNING))
task.cancel(true);
Even though, I have never faced this scenario; I will try to answer your question.
In your case you will need to validate the Context passed to AsyncTask.
You can perform validation
if(null!=mContext) //Activity still exist!!
{
gender.setText(values[0]);
}
else //Activity is destroyed
{
//Take appropriate action!!
}
The advantage will be, if the activity is destroyed by the time you reach this statement, your Context will automatically become null and you can handle the scenario.
As this part of one training on Android Developers suggests, keep a WeakReference on the UI element that needs to be updated after task is done and check if the reference is null before using it. This helps not only in checking if the UI is still around, but also does not prevent UI elements from being garbage collected.
Shouldn't
if (gender) {
gender.setText(values[0]);
}
be enough?
I need my Android app to periodically fetch data from a server using AJAX calls, and update the UI accordingly (just a bunch of TextViews that need to be updated with setText()). Note that this involves 2 tasks:
Making an AJAX call, and updating the UI once I receive a response - I use a simple AsyncTask for this.
Doing the above repeatedly, at regular intervals.
I haven't figured out an elegant way to achieve Point 2 above. Currently, I am simply executing the task itself from OnPostExecute(). I read on this thread at SO that I need not worry about garbage collection as far as the AsyncTask objects are concerned.
But I'm still unsure as to how I set up a timer that will fire my AsyncTask after it expires. Any pointers will be appreciated. Here is my code:
public class MyActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new AjaxRequestTask().execute(MY_REST_API_URL);
}
private void updateReadings(String newReadings) {
//Update the UI
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX Request
}
#Override
protected void onPostExecute(String result) {
updateReadings(result);
/*Is there a more elegant way to achieve this than create a new AsyncTask object every 10 seconds? Also, How can I update the UI if I create a timer here? */
new AjaxRequestTask().execute(MY_REST_API_URL);
}
}
}
Thanks in advance
EDIT:
I tried posting an answer but couldn't do it since I don't have the reputation to answer within 8 hours.
Well, so I found a solution. I'm not convinced however.
protected void onPostExecute(String result) {
updateReadings(result);
// super.onPostExecute(result);
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
new AjaxRequestTask().execute(MY_REST_API_URL);
}
},
TIMER_ONE_TIME_EXECUTION_DELAY
);
}
Are there any flip sides that I should be aware of when I use this? In particular, I am seeing lots of GCs happening in the LogCat. Also, I am wondering how an AsyncTask can be candidate for GC unless the onPostExecute() completes?
How can I "stop" the updates? One way I thought of was to make the very first AsyncTask instance as a member variable of the Activity. That way, I can invoke cancel(true) on it and hope that this will "stop" the tasks.
SOLUTION:
In case anyone is looking for something similar - none of the solutions I mentioned here work satisfactorily. They all suffer from OutOfMemory issues. I did not debug into the details of the OOM, but I suspect it could either be because of the recursion, or because of having HTTP-related objects as member variables in the AsyncTask rather than as members of the Activity (basically because of NOT reusing HTTP and other objects).
I discarded this approach for a different one - making my Ajax Calls endlessly in the doInBackground() of my AsyncTask; and updating the UI in onProgressUpdate(). That way I also avoid the overhead of maintaining too many threads or Handlers for updating the UI (remember UI can be updated in onProgressUpdate() ).
This approach also eliminates the need for Timers and TimerTasks, favoring the use of Thread.sleep() instead. This thread on SO has more details and a code snippet too.
Call postDelayed() on any View to schedule a hunk of code to be run on the main application thread after a certain delay. Do this in onPostExecute() of the AsyncTask to create and execute another AsyncTask.
You could use AlarmManager, as others have cited, but I would agree with you that it feels a bit like overkill for timing that occurs purely within an activity.
That being said, if the AJAX calls should be occurring regardless of whether the activity exists, definitely consider switching to AlarmManager and an IntentService.
I think the android way to do this is using AlarmManager. Or you can user a basic java Timer as well. I'd recommend AlarmManager.
Set it up to send some intent with a custom Action, and register a broadcastreceiver for it.
If the ajax calls are only executed in the activity you can just use a timer in the activity which starts the tasks.
Otherwise use a service which uses the AlarmManager and which connects to the gui via a broadcast.
The recommended way to do a repeated task, is via AlarmManager, as alluded to by Scythe. Basically it involves setting up a broadcast listener, and having AlarmManager fire off an intent to that listener at whatever interval you choose. You then would have your broadcast listener call out to the activity to run the AsyncTask. If you need a very tight timer (less than 5s calls I'd say), then you're better off using a Timer within a Service, and using AIDL to call back to the activity.
Instead of talking directly from the broadcast intent, you could also setup an IntentService which you can poke, and use AIDL to update the activity.
This is how I achieved it finally. Note that the AsyncTask cancel(true) method is useless in my scenario because of the recursion. I used what #CommonsWare suggested - used a flag to indicate whether any more tasks should be executed.
public class MyActivity extends Activity {
/*Flag which indicates whether the execution should be halted or not.*/
private boolean mCancelFlag = false;
private AjaxRequestTask mAjaxTask;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(mAjaxTask == null){
mAjaxTask = new AjaxRequestTask();
}
mAjaxTask.execute(MY_REST_API_URL);
}
#Override
protected void onResume() {
super.onResume();
mCancelFlag = false; /*when we resume, we want the tasks to restart. Unset cancel flag*/
/* If the main task is Finished, create a new task and execute it.*/
if(mAjaxTask == null || mAjaxTask.getStatus().equals(AsyncTask.Status.FINISHED)){
new AjaxRequestTask().execute(TLS_REST_API_URL);
}
}
#Override
protected void onPause() {
mCancelFlag = true; /*We want the execution to stop on pause. Set the cancel flag to true*/
super.onPause();
}
#Override
protected void onDestroy() {
mCancelFlag = true;/*We want the execution to stop on destroy. Set the cancel flag to true*/
super.onDestroy();
}
private void updateReadings(String result) {
//Update the UI using the new readings.
}
class AjaxRequestTask extends AsyncTask<String, Integer, String> {
private AjaxRequestTask mChainAjaxRequest;
private Timer mTimer;
private TimerTask mTimerTask;
#Override
protected String doInBackground(String... restApiUrl) {
//Do AJAX call and get the response
return ajaxResponse;
}
#Override
protected void onPostExecute(String result) {
Log.d(TAG, "Updating readings");
updateReadings(result);
// super.onPostExecute(result);
if(mTimer == null){
mTimer = new Timer();
}
if(!mCancelFlag){/*Check if the task has been cancelled prior to creating a new TimerTask*/
if(mTimerTask == null){
mTimerTask = new TimerTask() {
#Override
public void run() {
if(!mCancelFlag){/*One additional level of checking*/
if(mChainAjaxRequest == null){
mChainAjaxRequest = new AjaxRequestTask();
}
mChainAjaxRequest.execute(MY_REST_API_URL);
}
}
};
}
mTimer.schedule(mTimerTask,TIMER_ONE_TIME_EXECUTION_DELAY);
}
}
}
}