I have an activity thats already binded to the service.
When I start the activity, it binds to the service and gets a value from a variable inside the service. So I can display the value in my activity.
Now I want to read the value of the variable in the service permanently. Not only once while onCreate of my activity is called.
How can I do this?
Whats the right way for this?
There are several ways to accomplish that. One relatively easy way is to use a Handler that triggers itself periodically
public class MyActivity extends Activity {
private static final int UPDATE_RATE_IN_MS = 500;
private static final int MSG_UPDATE = 0;
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
doUpdate();
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE_IN_MS);
}
};
}
#Override
protected void onStart() {
super.onStart();
mHandler.sendEmptyMessageDelayed(MSG_UPDATE, UPDATE_RATE_IN_MS);
}
#Override
protected void onStop() {
super.onStop();
mHandler.removeMessages(MSG_UPDATE);
}
private void doUpdate() {
// do whatever you need here.
}
}
You would put the update of the value in doUpdate() in this example.
Related
I have a fragment that stems off the main activity. I am trying to have a textbox update with the users GPS location as they move around. I currently have it so every time you resume the fragment it updates, but I would like it to happen automatically every 10 seconds or so.
I am currently attempting to use runOnUiThread, which didn't cause my app to crash but didn't seem to do anything.
Within the fragment:
#Override
public void onViewCreated(#NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
TextView newText = getView().findViewById(R.id.wText);
newText.setText(getStringCoordinates);
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
newText.setText(getStringCoordinates);
}
});
}
Try using a handler, something like this should work
private Handler myHandler;
private static final int DELAY = 10000;
#Override
protected void onResume() {
super.onResume();
myHandler = new Handler(Looper.getMainLooper());
checkAgain();
}
private void checkAgain() {
myHandler.postDelayed(()-> checkGps(),DELAY);
}
private void checkGps() {
//do stuff here
checkAgain();
}
#Override
protected void onStop() {
super.onStop();
myHandler.removeCallbacksAndMessages(null);
myHandler = null;
}
basically it sends a message to the main thread every 10 seconds to check gps
the code may be wrong cause I'm writing it off the top of my head, but it should give you a good start
Maybe this is working
public class c_Thread_Update_Fragment extends Thread {
int i =0;
c_Thread_Update_Fragment(FragmentManager fm, ViewPager vp)
{
this.fragmentManager =fm;
this.mViewpager =vp;
}
#Override
public void run() {
while(true)
{
f.getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
yourfragmentclass.updateData(i);
}
});
i++;
sleep(1000);
}
}
public static void setFragment(Fragment f){
f =f;
}
}
Implement a public static void update (xxx){} in yourfragmentclass
Use setFragment(f) in your Fragment adapterclass and pass the current fragment.
I'm stuck in some problems with handlers. In particular, I need to stop and resume a callback either when I respectively turn my device lock and unlock, or when OnPause() and OnResume() are called. I put handler.Post(action) and handler.RemoveCallbacks(action) in OnPause() and in OnResume() but they don't work properly. Actually, when I exit and enter again in my application, It seems that handler.Post(action) is called twice because the update of TextView becomes faster than usual. Besides, the same thing happens when I lock or unlock the device. I dont' know how can I solve this issue.
This is my code:
public class MainActivity : Activity
{
int count = 1;
TextView text;
Handler handler;
myrunnable runnable;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
text = FindViewById<TextView>(Resource.Id.textView1);
handler = new Handler();
runnable = new myrunnable(text, handler);
}
protected override void OnResume()
{
handler.Post(runnable.Run);
base.OnResume();
}
protected override void OnPause()
{
handler.RemoveCallbacks(runnable.Run);
base.OnPause();
}
}
public class myrunnable : Java.Lang.Object, IRunnable
{
int i;
TextView text;
Handler handler;
public myrunnable() { }
public myrunnable(TextView text, Handler handler)
{
this.handler = handler;
this.text = text;
i = 0;
}
public IntPtr Handle
{
get
{
return (IntPtr) 0;
}
}
public void Dispose()
{
}
public void Run()
{
i++;
text.Text = i.ToString();
if (i < 100)
handler.PostDelayed(Run, 1000);
}
}
Thank You in advance.
Im having the same problem. The however, the problem is not the text view it's that onResume is called when the application starts and also when the suspended activity is resumed. Id recommend setting a boolean like canRun that if set false the handler will not post. And if it's true the handler can post and cancel as it pleases. I hope this helps and that im not way off.
RefreshHandler refreshHandler = new RefreshHandler();
class RefreshHandler extends Handler{
#Override
public void handleMessage(Message msg) {
Level1.this.updateUI();
}
public void sleep(long delayMillis){
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
public void updateUI(){
if(i<=imgid.length){
refreshHandler.sleep(100);
if(i<imgid.length){
imageView.setImageResource(imgid[i]);
imageView.setBackgroundColor(Color.WHITE);
} else if (i>=imgid.length) {
i = 0;
imageView.setImageResource(imgid[i]);
}
i++;
The loop works fine, the image slideshow keeps going.
When I click the back button and start a different activity the logcat keeps writing messages which tells me that the thread keeps running in the background.
How do I stop that?
I am new to programming so please don't be harsh to me, Thanks.
Basically, you need a way to know whether or not to call your RefreshHandler's sleep method (which is what is continuing the "loop".)
You can use a boolean member variable in your Activity and tie it to your Activity's onPause()/onResume() lifecycle callbacks to help you know whether or not to continue your slide show.
In addition, you should be careful not to leak your Level1 Activity by making your RefreshHandler static (if its an inner class) and holding onto a WeakReference to your Level1 Activity.
Have a look at this excellent article regarding the leaking Activity from a Handler problem by Alex Lockwood here:
http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
Try something like this:
public class Level1 extends Activity
{
public static class RefreshHandler extends Handler
{
private WeakReference<Level1> level1Ref;
public RefreshHandler(Level1 level1)
{
super();
level1Ref = new WeakReference<Level1>(level1);
}
#Override
public void handleMessage(Message msg)
{
Level1 level1 = level1Ref.get();
if (level1 != null)
{
level1.updateUI();
}
}
public void sleep(long delayMillis)
{
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
private boolean slideshowRunning = false;
private RefreshHandler refreshHandler = new RefreshHandler(this);
public void updateUI()
{
if (slideshowRunning)
{
// call refreshHandler.sleep
}
}
#Override
public void onResume()
{
super.onResume();
slideshowRunning = true;
}
#Override
public void onPause()
{
super.onPause();
slideshowRunning = false;
}
}
Activity.onPause() and onStop() are called in (at least) two situations:
The another Activity was launched on top of the current one.
The app was minimized.
Is there an easy way to tell the difference?
You could do it this way. Make all of your activities extend from a base activity. The base activity needs to keep a visibility counter that is incremented/decremented during onResume/onPause:
public abstract class MyBaseActivity extends ActionBarActivity {
private static int visibility = 0;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
}
#Override
protected void onResume() {
super.onResume();
visibility++;
handler.removeCallBacks(pauseAppRunnable);
}
#Override
protected void onPause() {
super.onPause();
visibility--;
handler.removeCallBacks(pauseAppRunnable);
// give a short delay here to account for the overhead of starting
// a new activity. Might have to tune this a bit (not tested).
handler.postDelayed(pauseAppRunnable, 100L);
}
#Override
protected void onDestroy() {
super.onDestroy();
// uncomment this if you want the app to NOT respond to invisibility
// if the user backed out of all open activities.
//handler.removeCallBacks(pauseAppRunnable);
}
private Runnable pauseAppRunnable = new Runnable() {
#Override
public void run() {
if (visibility == 0) {
// do something about it
}
}
};
}
I have custom AsyncTask (ListDownloadTask) that download data and updates UI. I want to make it forever while activity opened. So after AsyncTask did the work it must be scheduled. There are delays between attempts.
I tried to use timer but the problem is new ListDownloadTask().execute(); must be invoked from UI thread.
Now i have timer that generates message for Handler. That seems ugly to me. What is best practice?
#Override
public void onCreate(Bundle savedInstanceState) {
// ...
new ListDownloadTask().execute();
}
private static final long DOWNLOAD_UPDATES_DELAY = 5 * 1000;
private final Timer mUpdatesDownloaderTimer = new Timer(true);
Handler mDownloadTrigger = new Handler(new Handler.Callback() {
public boolean handleMessage(Message message) {
new ListDownloadTask().execute();
return true;
}
});
private void scheduleUpdatesDownload() {
mUpdatesDownloaderTimer.schedule(new TimerTask() {
#Override
public void run() {
mDownloadTrigger.sendEmptyMessage(0);
}
}, DOWNLOAD_UPDATES_DELAY);
}
private class ListDownloadTask extends AsyncTask<Long, String, Integer> {
#Override
protected void onPostExecute(Integer result) {
//...
scheduleUpdatesDownload();
}
Check out this example that is kinda similar to what you want to do. It might be better to use a Local Service also though.
Try Handler.sendEmptyMessageDelayed or Handler.sendEmptyMessageAtTime.
Create a service and bind to it in your activity.