Every time I`m trying to finish an activity inside of a timer method, the activity comes back alive over and over again.
I running this activity:
public class PlayerNoAdmin extends ActionBarActivity {
Timer myTimer; boolean isAdmin;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_player_no_admin);
Intent oldIntent = getIntent();
if (oldIntent != null && oldIntent.hasExtra("THE_LIST")){
songs = oldIntent.getParcelableArrayListExtra("THE_LIST");
id = oldIntent.getIntExtra("ID",0);
listId = oldIntent.getIntExtra("LIST_ID",0);
isAdmin = oldIntent.getBooleanExtra("IS_ADMIN",false);
}
//update the list every k seconds
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
TimerMethod();
}
}, 0, k_time2Update);
}
private void TimerMethod() {
//This method is called directly by the timer
//and runs in the same thread as the timer.
//We call the method that will work with the UI
//through the runOnUiThread method.
this.runOnUiThread(Timer_Tick);
}
private Runnable Timer_Tick = new Runnable() {
public void run() {
//Here check for update in the list every 30 seconds and send the new location
String url = getRunUrl();
new TaskMusicPlay().execute(url);
}
};
private class TaskMusicPlay extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String jsonResult = null;
try {
String url = params[0];
TestMain client = new TestMain();
jsonResult = client.doGetRequest(url);
} catch (IOException e) {
e.printStackTrace();
}
return jsonResult;
}
#Override
protected void onPostExecute(String aVoid) {
super.onPostExecute(aVoid);
checkIfNew(aVoid);
}
private void checkIfNew(String result) {
try {
JSONObject object = new JSONObject(result);
String temp = object.getJSONObject("info").getString("isAdmin");
isAdmin = (temp.equals("true"));
if (isAdmin) {
Intent intent = new Intent(getApplication(),YouTubePlayer.class);
intent.putExtra("THE_LIST", songs);
intent.putExtra("ID", id);
intent.putExtra("LIST_ID",listId);
intent.putExtra("IS_ADMIN",isAdmin);
startActivity(intent);
finish();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
At the end, I succeeded to move to the YouTubePlayer activity, but every few seconds the app returns to the code of this activity (and then executes again the startActivity call and goes back to YouTubePlayer) and that's going on and on.
Your Timer is periodically calling the player to start over and over again.
You must make a cancel() call to the Timer if it is no longer needed so you prevent it from holding a reference for your activity and thus preventing from being removed from the backstack and GC.
http://developer.android.com/reference/java/util/Timer.html
And your Timer is not running on the same thread as it's code because the timer thread iis another Thread and the Code in the Timer is running on UI. You can check it out by adding some logs in the Timer's run method outside of the runOnUIThread() and inside of it.
Related
I have network operation inside a thread which in oncreate() based on network response I need to process the next step but the thread is running after the activity life cycle.
I called networkRequest() in oncreate() in activity
private void networkRequest() {
final String[] resp = new String[1];
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
resp[0] = AttemptingUploadCheckList.getJsonObj(url);
JSONObject response = new JSONObject(resp[0]);
if (response != null) {
version_code = response.getInt("version_code");
recommended_update = response.getBoolean("recommended_update");
forced_update = response.getBoolean("forced_update");
}
if (recommended_update) {
recomendUpadate();
} else if (forced_update)
onUpdateNeeded(url);
else {
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
thread.start();
}
Thread is not bound with the activity. It's not running with the main thread.
Android said if you want to perform any long running tasks like api call, data from database then you need to use the AsyncTask or the Service.
In your case, you can use the AsycnTask for the fetching data.
class MyAsync extends AsyncTask<Void, Void, Void>{
final String[] resp = new String[1];
JSONObject response;
#Override
protected void onPreExecute() {
super.onPreExecute();
// Show Progress Dialog
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// Hide Progress Dialog
if (response != null) {
version_code = response.getInt("version_code");
recommended_update = response.getBoolean("recommended_update");
forced_update = response.getBoolean("forced_update");
}
if (recommended_update) {
recomendUpadate();
} else if (forced_update)
onUpdateNeeded(url);
else {
Intent intent = new Intent(SplashActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}
#Override
protected Void doInBackground(Void... voids) {
try {
resp[0] = AttemptingUploadCheckList.getJsonObj(url);
response = new JSONObject(resp[0]);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
For executing the above AsynTask
private void networkRequest() {
new MyAsync().execute();
}
Thread does not care about Activity or any other Component's lifecycle Except the Process in which it is Running.
You need to check for state of component yourself.
I can provide some example code but i really do not understand what exactly you are trying to do .
Considering you are making a network request there. Java thread individually is hard to handle in such cases considering the fact that after response we need to move on to Main thread to update the UI. So i highly recommend you should use a Network API Library probably RetroFit .
You can check state of the Component like isFinishing() in Activity .
Hi people I am getting problem in getting my latest JSON value after every 10 seconds. I have developed this code and now I am stucked in this. When I run this code it shows the value after second and did not get updated the second time. I have implemented the handler but it is also not working here.
public class MainActivity extends AppCompatActivity {
TextView a,b,c,d,e,f,g,h;
String result = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
a=(TextView) findViewById(R.id.a);
b=(TextView) findViewById(R.id.b);
c=(TextView) findViewById(R.id.c);
DownloadTask task = new DownloadTask();
task.execute("https://api.thingspeak.com/channels/12345/feeds.json?results=1");
}
public class DownloadTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(final String result) {
super.onPostExecute(result);
new Handler().postDelayed(new Runnable() {
public void run() {
search(result);
}
}, 10000);
}
public void search(String result){
try {
JSONObject jsonObject = new JSONObject(result);
JSONArray weatherInfo = jsonObject.getJSONArray("feeds");
JSONObject legsobject = weatherInfo.getJSONObject(0);
a.setText(legsobject.getString("field1"));
b.setText(legsobject.getString("field2"));
c.setText(legsobject.getString("field3"));
}catch (JSONException e) {
e.printStackTrace();
}
}
}
}
I want to get my value refreshed after every 10 seconds and it is not doing it.
Can any one guide me that how can I make it possible.
Try this code ..
private final int INTERVAL_MILLI = 60000; // define your time..
Handler mHandler;
#Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacks(SyncData);
}
Runnable SyncData = new Runnable() {
#Override
public void run() {
// call your code here..
Log.e(TAG, "SyncData1: " + new java.sql.Date(System.currentTimeMillis()).toString());
final String Token = AppSetting.getStringSharedPref(mContext, Constants.USER_KEY_TOKEN, "");
if (!TextUtils.isEmpty(Token) && !CommonUtils.isServiceRunning(mContext)) {
Log.e(TAG, "SyncData2: " + new java.sql.Date(System.currentTimeMillis()).toString());
startService(new Intent(mContext, SyncService.class));
}
callSyncData();
}
};
public void callSyncData()
{
mHandler.postDelayed(SyncData, INTERVAL_MILLI);
}
and callSyncData() method called in activity onCreate method and run method.
To begin with, I don't like the idea of hammering the server with a request every 10s even nothing changes really. If you can move to a solution with notification from the server it will be better.
If you still need to do that you can use three common solutions to fire a repeating task with a period:
1- Use Timer & TimerTask
For this solution you need to declare your timer task to run:
final TimerTask repeatedTask = new TimerTask() {
#Override
public void run() {
//you stuff here
}
};
Then you need to schedule your task using a timer like below:
final Timer timer = new Timer();
timer.scheduleAtFixedRate(repeatedTask,0, 10 * 1000);
==> Don't forget to call timer.cancel(); when your are done (or activity pause, stop, ...)
2- Use ScheduledThreadPoolExecutor
This is basically a replacing for Timer task starting android 5.0. The setup is more easy and straightforward like below:
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
//you stuff here
}
}, 0, 10, TimeUnit.SECONDS);
==> don't forget to shutdown your executor when you are done by calling : executor.shutdown();
3- Use Handler
The tip here is to repost the runnable after downloading your json like mentionned in the previous answer.
You can use TimerTask and Timer. If you need to update UI components you should run it on UI thread.
final TimerTask yourRepeatedTask = new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//your code here
}
});
}
};
And the Timer which schedules your task in a given interval. In your case, it is 10s. Make sure to give the interval in milliseconds.
final Timer timer = new Timer();
timer.scheduleAtFixedRate(yourRepeatedTask ,0, 10 * 1000);
At last call timer.cancel() to stop the timer.
#Override
protected void onPause() {
if (timer != null) {
timer.cancel();
}
super.onPause();
}
I have a issue with using a timer on a listview.
In the list item I showed using sqlite values. There is a textview which showing time difference of last updated time of the data and current time. i have to show it in every one second. so the user can know how long he updated the record.
I tried this in several ways.
First way
I tried to add timer in adapter class. so for every item new timer is created. so application crashed because of many timers run simultaneously.
Second way
I tried using adapter.notifyDataSetChanged() way. Like as this.
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
if (adapterChatThread != null) {
adapter.notifyDataSetChanged();
}
timerHandler.postDelayed(this, 1000); // run every second
}
};
timerRunnable.run();
I move to another activity when click on list item and user can come back to this Activity.
so in Onresume I used
timerHandler.postDelayed(timerRunnable, 500);
and OnPause
timerHandler.removeCallbacks(timerRunnable);
Issue is data is not showing well. I mean in every second data difference is not one second. some time differnce is 2sec, 5 sec, .. etc.
means timer is not working as I expected.
Third way
I used a asynctask and call it in every second using a timer.
class ThreadTimer extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
return null;
}
#Override
protected void onPostExecute(Void result) {
if (adapter != null)
adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
}
I called this as in here
Handler timerHandler = new Handler();
Runnable timerRunnable = new Runnable() {
#Override
public void run() {
new ThreadTimer().execute();
timerHandler.postDelayed(this, 1000); // run every second
}
};
timerRunnable.run();
previous issue triggered. (data not showing well)
Fourth way
Using AsyncTask as this
class ThreadTimer extends AsyncTask<Void, Void, Void> {
void Sleep(int ms) {
try {
Thread.sleep(ms);
} catch (Exception e) {
}
}
#Override
protected Void doInBackground(Void... params) {
while (threadRun) {
Sleep(1000);
return null;
}
return null;
}
#Override
protected void onPostExecute(Void result) {
adapter.notifyDataSetChanged();
super.onPostExecute(result);
}
}
I called this class in OnResume.
In on pause I set threadRun= false;
issue is same.
please help me.
My requirement is update list item in every second.
Thank you.
edit
here is my adapter class textview update code.
Date lastUpdatedTime;
final ChatThreadDAO ctd = new ChatThreadDAO();
long timeForNextResponse = ctd.getLastRespondedTime(vct.get(position).getThread_id());
try {
if (vct.get(position).getThread_read_status() == 1 && timeForNextResponse > 0) {
final long respTime = timeForNextResponse;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
lastUpdatedTime = formatter.parse(vct.get(position).getLast_updated_time());
final long timeDiff = (new Date()).getTime() - lastUpdatedTime.getTime();
if (timeDiff <= respTime) {
timeForNextResponse = respTime - timeDiff;
ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), timeForNextResponse);
holder.tvChatTimer.setVisibility(View.VISIBLE);
holder.tvChatTimer.setText(timeForNextResponse / 1000 + "");
} else {
ctd.updateTimeRespondToLastMsg(vct.get(position).getThread_id(), 0);
}
} else {
holder.tvChatTimer.setVisibility(View.INVISIBLE);
}
} catch (ParseException e) {
e.printStackTrace();
}
here vct is
Vector vct;
I assign the values to vector in adapter class constructer.
Here is an example similar to your case.
private class connectionControl extends Thread {
boolean stop_ = false;
public void stop_() {
this.stop_ = true;
}
public void run() {
System.out.println("Thread started:" + getClass().getSimpleName());
while(!this.stop_) {
try {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Calendar c = Calendar.getInstance();
int rightNow = c.get(Calendar.SECOND) + c.get(Calendar.MINUTE)*60;
if(rightNow - lastUpdatedTime > 10) {
wirelessIcon.setImageResource(R.drawable.wirelessred);
}
else if(rightNow - lastUpdatedTime > 5) {
wirelessIcon.setImageResource(R.drawable.wirelessyellow);
}
else {
wirelessIcon.setImageResource(R.drawable.wirelessgreen);
}
}
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Thread stoped:" + getClass().getSimpleName());
}
}
You set your lastUpdatedTime the same way you created rightNow whenever you call notifyDataSetChanged() method of your adapter.
I've been working on looping AsyncTask on Android. I used an idea suggested by one of user and I came up with this:
public void loopAsyncTaskGetter(){
final Handler handler = new Handler();
final Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
new GetTasksAsync().execute(getIntent().getStringExtra(MainActivity.EXTRA_ID));
} catch (Exception e) {
}
}
});
}
};
timer.schedule(doAsynchronousTask, 500, 1000*30);
}
My AsyncTask extending class looks like that:
class GetTasksAsync extends AsyncTask<String, Void, Void>{
ProgressDialog dialog;
#Override
protected void onPreExecute(){
//dialog stuff
super.onPreExecute();
}
#Override
protected Void doInBackground(String... data) {
//this method below returns JSON String from my PHP file
String jsonData = Webserv.getTaskJson(data[0]);
try {
JSONArray jsonArray = new JSONArray(jsonData);
for(int i=0; i<jsonArray.length(); i++){
//some json parsing, doesn't matter
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void v){
dialog.dismiss();
myAdapter.notifyDataSetChanged();
super.onPostExecute(v);
}
I call loopAsyncTaskGetter() on my onCreate() method of Activity and I expect to have things done once for 30 seconds, and again. The strange thing for me is, that sometimes it works once for 30 seconds, and sometimes it gets done f.e. 3 times in 5 seconds, like much more often. Could anybody tell me why it works this way? Where did I make a mistake?
Kind regards!
You don't cancel your Timer when you're done with it. And because of that, you probably have multiple timers running in the background. Pass your Timer as a parameter to your asynctask and cancel it in onPostExecute.
In my app, I have a service implementing timer task through which i am getting user's location after every 10 seconds.
The thing I am stuck with is I would like to stop this service as well as timer after say 1 or 2 minutes.
I am not able to put behind the logic for it.
Please help me out.
public class TimeService extends Service {
// constant
public static final long NOTIFY_INTERVAL = 20 * 1000; // 10 seconds
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
int i=0;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// cancel if already existed
if(mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast
Toast.makeText(getApplicationContext(), getDateTime(),
Toast.LENGTH_SHORT).show();
new LongOperation().execute("");
}
});
}
private String getDateTime() {
// get date time in custom format
SimpleDateFormat sdf = new SimpleDateFormat("[yyyy/MM/dd - HH:mm:ss]");
return sdf.format(new Date());
}
}
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
System.out.println("bgnotification Long operation doinbackground called----> ");
return "";
}
#Override
protected void onPostExecute(String result) {
System.out.println("bgnotification Long operation post execute called----> ");
if(i<3){
GPSTracker mGPS = new GPSTracker(getApplicationContext());
onLocationChanged(mGPS);i++;
Toast.makeText(getApplicationContext(), "HEllo Post execute called",
}
#Override
protected void onPreExecute() {
System.out.println("bgnotification Long operation pre execute called----> ");
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
public void onLocationChanged(GPSTracker track) {
// Getting latitude
double latitude = track.getLatitude();
// Getting longitude
double longitude = track.getLongitude();
System.out.println( latitude);
System.out.println( longitude);
Geocoder geocoder = new Geocoder(this, Locale.getDefault());
try
{
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
Log.e("Addresses","-->"+addresses);
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
#Wishy to stop service and timer task at certain time you need to make an other timer task which going to execute one time and execution time duration will be whatever you specify. In run method u need to write mTimer.purge(); mTimer.cancel() and stopService(newIntent(class.this,yourservice.class));
An easier solution is making timer public static.
public class TimeService extends Service {
//...
private Timer mTimer = null;
//...
}
another Activity:
//...
if(TimeService.mTimer!=null) TimeService.mTimer.cancel();
//...
Override onDestroy() method in service class like thus:
#Override
public void onDestroy() {
super.onDestroy();
if (mTimer != null) {
mTimer.cancel();
}
}
Call stopService() there where you want to stop your service, like thus:
stopService(serviceIntent);
That's all.