I am implementing an inactivity timer based on this answer: https://stackoverflow.com/a/12481918/6298161
I need the timer to work across multiple activities, so as the comments suggest from the original post I have change the Handler and Runnable to be static.
How do I now redirect to a new activity in the runnable where I have put the comment? Any help is greatly appreciated
public class InactivityTimerActivity extends AppCompatActivity {
public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_inactivity_timer);
}
private static Handler disconnectHandler = new Handler() {
public void handleMessage(Message msg) {
}
};
private static Runnable disconnectCallback = new Runnable() {
#Override
public void run() {
// I want to redirect here
}
};
public void resetDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
}
public void stopDisconnectTimer() {
disconnectHandler.removeCallbacks(disconnectCallback);
}
#Override
public void onUserInteraction() {
resetDisconnectTimer();
}
#Override
public void onResume() {
super.onResume();
resetDisconnectTimer();
}
#Override
public void onStop() {
super.onStop();
stopDisconnectTimer();
}
}
I think you shouldn't make it static. Just keep that protected, and then when start new activity, putting an integer variable inside the intent (the remaining time or the time that the timer has run). Then when on create new activity, you get that value out and set your timer base on that value.
Related
I want to make a simple button which will start to loop a function every period of time which I can set. But not only it will start the loop, but also stop the loop if I click the button again. Is there anyway I can achieve this with a single button?
Here's how I'd do it
public class MainActivity extends AppCompatActivity {
private Button btn;
private View.OnClickListener runOnClickListener;
private View.OnClickListener stopOnClickListener;
void init() {
Handler handler = new Handler();
int duration = 5000;
Runnable runnable = new Runnable() {
#Override
public void run() {
foo();
handler.postDelayed(this, duration);
}
};
runOnClickListener = view -> {
runnable.run();
btn.setOnClickListener(stopOnClickListener);
};
stopOnClickListener = view -> {
handler.removeCallbacks(runnable);
btn.setOnClickListener(runOnClickListener);
};
btn.setOnClickListener(runOnClickListener);
}
void foo() {
Log.i("foo", "foo");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = findViewById(R.id.btn);
init();
}
}
Yeah, give you a simple example.
First, create two constant values and one instance variable:
//indicate whether or not the loop is running
private boolean isRunning = false;
//used for handler to send empty msg
private final static int MSG_LOOP = 1;
private final static long LOOP_INTERVAL = 5000;
Then create a Handler instance to handle the loop logic:
Handler handler = new Handler() {
#Override
public void handleMessage(#NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case MSG_LOOP:
doStuff();
break;
}
}
};
private void doStuff() {
//after what you want to do is done, send another MSG_LOOP msg with delay
handler.sendEmptyMessageDelayed(MSG_LOOP, LOOP_INTERVAL);
}
And finally:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isRunning) {
//cancel if any in the message queue
handler.removeMessages(MSG_LOOP);
} else {
//if you do not want to start the loop immediately, then use: "sendEmptyMessageDelayed"
handler.sendEmptyMessage(MSG_LOOP);
}
}
});
I'm looking on a way to run this task repeatedly with the listener. Right now, this is working but I'm looking on a way to make it repeatedly every 10 seconds.
Activity
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
VolleyRequest.makeRequest(this, URL, listenerResponse, listenerError);
}
private static final String URL = "https://naqil.ma/random.php";
private Response.Listener<JSONObject> listenerResponse = new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Toast.makeText(SecondActivity.this, "Resonse " + response.toString(), Toast.LENGTH_LONG).show();
}
};
private Response.ErrorListener listenerError = new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(SecondActivity.this, "Error " + error, Toast.LENGTH_LONG).show();
}
};
}
Class making request
public class VolleyRequest {
public static void makeRequest(Context context, String url,
Response.Listener<JSONObject> listenerResponse, Response.ErrorListener listenerError) {
JsonObjectRequest requestWeather = new JsonObjectRequest(Request.Method.GET, url, null, listenerResponse,
listenerError);
Volley.newRequestQueue(context).add(requestWeather);
}
}
````
(Adapted from this answer: https://stackoverflow.com/a/10156550/2711811 )
Basically use a handler to reschedule request every 10 seconds. Handler is attached to main looper by virtue of creating it in onStart.
First, remove the VolleyRequest.makeRequest from onCreate.
Add members to SecondActivity:
private Handler myHandler;
private Runnable myRunnable;
In onStart of SecondActivity :
protected void onStart() {
super.onStart();
// Start issuing VolleyRequests repeating every 10 seconds.
myHandler = new Handler();
myHandler.post(new Runnable() {
#Override
public void run() {
SecondActivity.this.myRunnable = this;
VolleyRequest.makeRequest(
SecondActivity.this,
URL,
SecondActivity.this.listenerResponse,
SecondActivity.this.listenerError);
SecondActivity.this.myHandler.postDelayed(this, 10000);
}
};
}
And stop the repeated requests when the activity is stopped: in onStop of SecondActivity:
protected void onStop() {
super.onStop();
// check that it actually ran at least once - can't be null.
if (myRunnable != null) {
myHandler.removeCallbacks(myRunnable);
}
}
I am running a recursive handler which runs some code. I am posting the handler using a HandlerThread. I want to run the next recursive call only after the completion of the previous call.
Is it possible to do so? If not what are the alternatives.
HandlerThread ht = new HandlerThread();
ht.start();
Handler h = new Handler(ht.getLooper());
h.post(new Runnable() {
#override
public void run(){
//Some code
h.postDelay(this,1000);
}
});
Your code should work, but if you want a complete example how to run something recursively using HandlerThread, here it is:
public class Main2Activity extends AppCompatActivity {
private MyWorkerThread mWorkerThread;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
mWorkerThread = new MyWorkerThread("myWorkerThread");
final Runnable task = new Runnable() {
#Override
public void run() {
Log.d("TAG", "Done.");
mWorkerThread.postTask(this);
}
};
mWorkerThread.start();
mWorkerThread.prepareHandler();
mWorkerThread.postTask(task);
}
#Override
protected void onDestroy() {
mWorkerThread.quit();
super.onDestroy();
}
}
class MyWorkerThread extends HandlerThread {
private Handler mWorkerHandler;
public MyWorkerThread(String name) {
super(name);
}
public void postTask(Runnable task){
mWorkerHandler.postDelayed(task, 1000); // set timeout which needed
}
public void prepareHandler(){
mWorkerHandler = new Handler(getLooper());
}
}
Don't forget to call handlerThread.quit() in onDestroy
I want to make a callback function in the ShipInfoManager to inform the MainActivity to do some action.
If I put onEvent() into Runnable, it runs.
However If I put it like this, it shows an error.
Is there any way to fire the callback after loading data?
Or, is there any way to do the callback like Android's API's LocatioManger's requestLocationUpdates, giving a callback when the data/variables is changed?
Thank you for any replies!
MyCallback Interface:
interface MyCallback {
void callbackCall();
}
ShipInfoManager class:
public class ShipInfoManager {
Context mContext;
public ShipInfoManager(Context _mContext) {
this.mContext = _mContext;
reloadData();
startTimer();
}
MyCallback callback;
void onEvent() {
callback.callbackCall();
}
private void startTimer() {
/* RUN EVERY MIN */
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#SuppressWarnings("unchecked")
public void run() {
try {
reloadData();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
// TEMP SUSPEND FROM PREVENTING RELOAD //
timer.schedule(doAsynchronousTask, 0, 5000);
}
/* JSON handling and extraction */
private void reloadData() {
//Do sth to reload the data
//After reload, I want to fire the callback
onEvent();
}
}
It looks like you haven't any listeners to your callback and you're not checking for this.
You should replace your ShipInfoManager with this:
public class ShipInfoManager {
public interface MyCallback {
void callbackCall();
}
public void setCustomEventListener(MyCallback eventListener) {
callback = eventListener;
}
Context mContext;
public ShipInfoManager(Context _mContext) {
this.mContext = _mContext;
reloadData();
startTimer();
}
MyCallback callback;
void onEvent() {
// Check if we have listeners
if (callback != null)
callback.callbackCall();
}
private void startTimer() {
/* RUN EVERY MIN */
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#SuppressWarnings("unchecked")
public void run() {
try {
reloadData();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
// TEMP SUSPEND FROM PREVENTING RELOAD //
timer.schedule(doAsynchronousTask, 0, 5000);
}
/* JSON handling and extraction */
private void reloadData() {
//Do sth to reload the data
//After reload, I want to fire the callback
onEvent();
}
}
Inside your Activity or Fragment you should have something like:
public class MainActivity extends ActionBarActivity implements ShipInfoManager.MyCallback {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ShipInfoManager s = new ShipInfoManager(this);
s.setCustomEventListener(this);
}
#Override
public void callbackCall() {
}
}
I changed my MainActivity like this. It works now.
Thank you for your suggestion and reply!!!!!
public class MainActivity extends ActionBarActivity {
ShipInfoManager mShipInfo;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mShipInfo = new ShipInfoManager(this);
Log.i("Show Ship List Size", String.valueOf(mShipInfo.get_shipsList().size()));
Log.i("Show Ship - 6", String.valueOf(mShipInfo.getShip(6).getShip_name()));
mShipInfo.callback = new ShipInfoManager.MyCallback() {
#Override
public void callbackCall() {
Log.i("Call Back", "it is called");
}
};
}
I have created a Timer through Stopwatch class and implement it successfully in activity.
But i want to continue the timer after closing the application, so i used Service and put the method inside this. Something like below:
MyService.java:
Stopwatch stopwatch = Stopwatch.createStarted();
String workingTime1 = "";
void startThreadUpdateTimer() {
final DecimalFormat format = new DecimalFormat("00");
Timer T = new Timer();
T.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
workingTime1 = "Your effort is "
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.HOURS)))
+ ":"
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.MINUTES)))
+ ":"
+ format.format(Double.valueOf(stopwatch
.elapsed(TimeUnit.SECONDS)))
+ " till now for the day";
SwipePage.efforttimer.setText(workingTime1);
}
});
}
}, 1000, 1000);
}
void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
efforttimer is the TextView in which I want to show my effort time. I think binding service or broadcastreceiver will help here. Implement many ways but not succeed yet.
All helps and suggestions are mostly appreciable.
Thanks
LocalBroadcastManager will be the simplest solution in your case.
In your MyService you'll need this code:
public class MyService extends Service {
public static final String ACTION_UPDATE = "MyServiceACTION_UPDATE";
...
private void updateEmitterMethod() {
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_UPDATE));
}
}
While in your Activity you'll have:
private BroadcastReceiver mMyServiceUpdateReciever;
...
#Override
public void onResume() {
super.onResume();
mMyServiceUpdateReciever = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
onUpdateMethod();
}
};
LocalBroadcastManager.getInstance(this).registerReceiver(mMyServiceUpdateReciever, new IntentFilter(MyService.ACTION_UPDATE));
}
#Override
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMyServiceUpdateReciever);
}