In the open source library:android-async-http , Has a method cancelRequests(context, boolean):
public void cancelRequests(final Context context, final boolean mayInterruptIfRunning) {
if (context == null) {
Log.e(LOG_TAG, "Passed null Context to cancelRequests");
return;
}
Runnable r = new Runnable() {
#Override
public void run() {
List<RequestHandle> requestList = requestMap.get(context);
if (requestList != null) {
for (RequestHandle requestHandle : requestList) {
requestHandle.cancel(mayInterruptIfRunning);
}
requestMap.remove(context);
}
}
};
if (Looper.myLooper() == Looper.getMainLooper()) {
new Thread(r).start();
} else {
r.run();
}
}
The cancelRequests function will be called as following.
class TestActivity extends Activity {
#Override
protected void onDestroy() {
cancelRequests(this, true);
super.onDestroy();
}
}
This is a memory leak? How to solve?
An Async Task will not be canceled or destroyed at the moment the
activity is dismissed
Dont call stop Async like
cancelRequests(this, true);
Let system decide it. You only pause and stop it by the check value, or stop permantly. It's real algorithm
Related
I Have an EventBus() that runs and looping until it goes to my other Fragment when my app starts. when I idle the app for at least 30++ minutes, I'm getting this stacktrace:
10-11 10:23:46.315 3790-4797/com.jti.mikee.jti_pos W/libc: pthread_create failed: couldn't allocate 1040384-byte stack: Out of memory
10-11 10:23:46.315 3790-4797/com.jti.mikee.jti_pos E/dalvikvm: pthread_create (stack size 16384 bytes) failed: Try again
I also use ScheduleExecutorService() on onCreateView()
scheduledExecutorService = Executors.newScheduledThreadPool(4);
This is the declaration of my EventBus()
public static final Runnable mRunnable = new Runnable() {
#Override
public void run() {
EventBus.getDefault().post(new EB_TapCard());
}
};
and on my onResume() this is the code
#Override
public void onResume() {
Log.e("current_module",current_module);
super.onResume();
try {
EventBus.getDefault().register(this);
rfscanner = scheduledExecutorService.scheduleAtFixedRate(mRunnable, 0, 2, TimeUnit.SECONDS);
} catch (Throwable e) {
e.printStackTrace();
}
}
and lastly, this is my onPause() method
#Override
public void onPause() {
try {
getContext().unregisterReceiver(broadcastReceiver);
} catch (Throwable e) {
e.printStackTrace();
}
rfscanner.cancel(true);
EventBus.getDefault().unregister(this);
super.onPause();
}
I'm wondering that when I idle my device, The runnable is still running. How can I pause/resume it? much appreciated.
EDIT
As of now, I have tried to add a function Callback(). It's working well but after I tap the card, The Card Reader is not reading the second card. how can I make it loop without making the memory full??
class CallBackThread extends Thread {
#Override
public void run() {
try {
RFCardInterface.waitForCardPresent(RFCardInterface.CONTACTLESS_CARD_MODE_AUTO, 1, -1);
if (RFCardInterface.isCallBackCalled &&
RFCardInterface.notifyEvent.eventID == RFCardInterface.CONTACTLESS_CARD_EVENT_FOUND_CARD) {
IDCatcher = StringUtility.ByteArrayToString(RFCardInterface.notifyEvent.eventData,
RFCardInterface.notifyEvent.eventData.length);
IDCatcher = IDCatcher.substring(9, 21).replace(" ", "");
Log.e("IDCatcher", IDCatcher);
EventBus.getDefault().post(new EBTest2());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Try something along these lines:
private Handler mHandler; // the handler to this activity
private Runnable mCallback; // the callback to 2s loop
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mHandler = new Handler();
mCallback = new Runnable() {
#Override
public void run() {
EventBus.getDefault().post(new EB_TapCard());
// schedule next run here
scheduleNextRun();
}
};
}
#Override
public void onResume() {
scheduleNextRun();
}
#Override
public void onPause() {
cleanUpRun();
}
#Override
public void onDestroy() {
// needed in case the system will force-kill your process
cleanUpRun();
}
private void cleanUpRun() {
if (mHandler != null) {
mHandler.removeCallbacks(mCallback);
}
}
private void scheduleNextRun() {
// clean up beforehand
cleanUpRun();
if (mHandler != null) {
mHandler.postDelayed(mCallback, 2000L);
}
}
idea is that every time you enter the page, you post-delayed your runnable, and you remove it when you go out; once you run it, and it gets the callback executed, you schedule the next run, and so on.
I am working on application, where in am getting a tasks from server and then user evaluate through Mobile Application(just like a quiz Application).
During Evaluation of Tasks, if the user presses home button then app goes to background. And when user back to application from recent background applications, then Application started from Splash screen.
I am confused that what price of code should I add, so that when user back to Application, then previous state must be shown to the user??
copy this class further i will tell you what to do
public class Foreground implements Application.ActivityLifecycleCallbacks {
public static final long CHECK_DELAY = 50;
public static final String TAG = Foreground.class.getName();
public interface Listener {
public void onBecameForeground();
public void onBecameBackground();
}
private static Foreground instance;
private boolean foreground = false, paused = true;
private Handler handler = new Handler();
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
private Runnable check;
/**
* Its not strictly necessary to use this method - _usually_ invoking
* get with a Context gives us a path to retrieve the Application and
* initialise, but sometimes (e.g. in test harness) the ApplicationContext
* is != the Application, and the docs make no guarantees.
*
* #param application
* #return an initialised Foreground instance
*/
public static Foreground init(Application application){
if (instance == null) {
instance = new Foreground();
application.registerActivityLifecycleCallbacks(instance);
}
return instance;
}
public static Foreground get(Application application){
if (instance == null) {
init(application);
}
return instance;
}
public static Foreground get(Context ctx){
if (instance == null) {
Context appCtx = ctx.getApplicationContext();
if (appCtx instanceof Application) {
init((Application)appCtx);
}
throw new IllegalStateException(
"Foreground is not initialised and " +
"cannot obtain the Application object");
}
return instance;
}
public static Foreground get(){
if (instance == null) {
throw new IllegalStateException(
"Foreground is not initialised - invoke " +
"at least once with parameterised init/get");
}
return instance;
}
public boolean isForeground(){
return foreground;
}
public boolean isBackground(){
return !foreground;
}
public void addListener(Listener listener){
listeners.add(listener);
}
public void removeListener(Listener listener){
listeners.remove(listener);
}
#Override
public void onActivityResumed(Activity activity) {
paused = false;
boolean wasBackground = !foreground;
foreground = true;
if (check != null)
handler.removeCallbacks(check);
if (wasBackground){
Log.i(TAG, "went foreground");
for (Listener l : listeners) {
try {
l.onBecameForeground();
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}
#Override
public void onActivityPaused(Activity activity) {
paused = true;
if (check != null)
handler.removeCallbacks(check);
handler.postDelayed(check = new Runnable(){
#Override
public void run() {
if (foreground && paused) {
foreground = false;
Log.i(TAG, "went background");
for (Listener l : listeners) {
try {
l.onBecameBackground();
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}
}, CHECK_DELAY);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {}
#Override
public void onActivityStarted(Activity activity) {}
#Override
public void onActivityStopped(Activity activity) {}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
#Override
public void onActivityDestroyed(Activity activity) {}
}
add this in onCreate of year Application Class
Foreground foreground = Foreground.init(this);
final Foreground.Listener myListener = new Foreground.Listener()
{
public void onBecameForeground()
{
Log.d("TAG", "FOREGROUND");
}
public void onBecameBackground()
{
//registerActivityLifecycleCallbacks(new MyLifecycleHandler());
Intent i = new Intent("android.intent.action.MAIN").putExtra("some_msg", "I will be sent!");
sendBroadcast(i);
}
};
foreground.addListener(myListener);
add this code in onCreate of your Base Activity ok ?
IntentFilter intentFilter = new IntentFilter(
"android.intent.action.MAIN");
mReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
//extract our message from intent
String msg_for_me = intent.getStringExtra("some_msg");
//log our message value
Log.i("InchooTutorial", msg_for_me);
finish();
}
};
//registering our receiver
this.registerReceiver(mReceiver, intentFilter);
not this this is your override onDestroy method copy outside the oncreate
#Override
protected void onDestroy()
{
super.onDestroy();
unregisterReceiver(mReceiver);
}
Overide the methods onStop(), onPause(), onResume() in your main activity.
I'm trying to implement a callback method to be called whenever a Thread is is done It's work.
I'm using the interface approach and not the Handler approach.
I have a main UI Thread which is the onCreate(Bundle) method and a Thread i call from within the onCreate(Bundle) method.
(Only relevant code posted).
MainActivity.java:
public class MainActivity extends AppCompatActivity implements GetDataFromTheWebThreadCallback
{
public static GetDataFromTheWebThread getDataFromTheWebThread;
private GetDataFromTheWebEventNotifier eventNotifier;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.eventNotifier = new GetDataFromTheWebEventNotifier(MainActivity.this);
// The thread that will search the web for data
this.getDataFromTheWebThread = new GetDataFromTheWebThread();
getDataFromTheWebThread.start();
}
#Override
public void finishParsing() // The callback method that never called
{
Toast.makeText(MainActivity.this,"Callback Method Called",Toast.LENGTH_LONG).show();
Log.d("Callback:", "Callback Method Called");
}
}
GetDataFromTheWebEventNotifier.java:
public class GetDataFromTheWebEventNotifier
{
private GetDataFromTheWebThreadCallback callbackInterface;
public GetDataFromTheWebEventNotifier(GetDataFromTheWebThreadCallback callbackInterface)
{
this.callbackInterface = callbackInterface;
}
public void onEvent()
{
this.callbackInterface.finishParsing();
}
}
GetDataFromTheWebThreadCallback.java:
public interface GetDataFromTheWebThreadCallback
{
void finishParsing(); // The method i wish to invoke when certain event will happen
}
GetDataFromTheWebThread.java:
public class GetDataFromTheWebThread extends Thread
{
public static boolean isFinished = false; // False - the thread is still running. True - the thread is dead
#Override
public void run()
{
GetDataFromTheWebThread.isFinished = false;
try
{
// Some internet computations...
Thread.sleep(100);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
GetDataFromTheWebThread.isFinished = true;
}
}
So what's wrong with my callback?
As for your ThreadClass, have a constructor with the callback :
public class GetDataFromTheWebThread extends Thread {
public static boolean isFinished = false; // False - the thread is still running. True - the thread is dead
private GetDataFromTheWebThreadCallback mCallback;
public GetDataFromTheWebThread(GetDataFromTheWebThreadCallback c) {
mCallback = c;
}
#Override
public void run() {
GetDataFromTheWebThread.isFinished = false;
try {
// Some internet computations...
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
GetDataFromTheWebThread.isFinished = true;
if (mCallback !- null) {
mCallback.finishParsing();
}
}
}
As for your Activity, simply pass the callback when creating your Thread :
this.getDataFromTheWebThread = new GetDataFromTheWebThread(this);
As well as :
#Override
public void finishParsing() {
// You know that this function is called from a background Thread.
// Therefore from here, run what you have to do on the UI Thread
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,"Callback Method Called",Toast.LENGTH_LONG).show();
Log.d("Callback:", "Callback Method Called");
}});
}
You never call onEvent(). Is your notifier supposed to be watching the isFinished variable or something?
Actually you didn't call onEvent(). And check AsyncTask.
I'm trying to write an app that will launch, or show a notification or a popup when another specific app goes to the background.
For example:
User launches app A
User uses app A
User puts app A in the background, either by pressing the home button or back button or launching another app
My app detects that and launches itself or shows a popup or whatever
Is there a way to do this and if there is, without killing the battery?
In your app A put the below code in a class:
public class Foreground implements Application.ActivityLifecycleCallbacks {
public static final long CHECK_DELAY = 500;
public static final String TAG = Foreground.class.getName();
public interface Listener {
public void onBecameForeground();
public void onBecameBackground();
}
private static Foreground instance;
private boolean foreground = false, paused = true;
private Handler handler = new Handler();
private List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
private Runnable check;
/**
* Its not strictly necessary to use this method - _usually_ invoking
* get with a Context gives us a path to retrieve the Application and
* initialise, but sometimes (e.g. in test harness) the ApplicationContext
* is != the Application, and the docs make no guarantees.
*
* #param application
* #return an initialised Foreground instance
*/
public static Foreground init(Application application) {
if (instance == null) {
instance = new Foreground();
application.registerActivityLifecycleCallbacks(instance);
}
return instance;
}
public static Foreground get(Application application) {
if (instance == null) {
init(application);
}
return instance;
}
public static Foreground get(Context ctx) {
if (instance == null) {
Context appCtx = ctx.getApplicationContext();
if (appCtx instanceof Application) {
init((Application) appCtx);
}
throw new IllegalStateException(
"Foreground is not initialised and " +
"cannot obtain the Application object");
}
return instance;
}
public static Foreground get() {
if (instance == null) {
throw new IllegalStateException(
"Foreground is not initialised - invoke " +
"at least once with parameterised init/get");
}
return instance;
}
public boolean isForeground() {
return foreground;
}
public boolean isBackground() {
return !foreground;
}
public void addListener(Listener listener) {
listeners.add(listener);
}
public void removeListener(Listener listener) {
listeners.remove(listener);
}
#Override
public void onActivityResumed(Activity activity) {
paused = false;
boolean wasBackground = !foreground;
foreground = true;
if (check != null)
handler.removeCallbacks(check);
if (wasBackground) {
Log.i(TAG, "went foreground");
for (Listener l : listeners) {
try {
l.onBecameForeground();
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}
#Override
public void onActivityPaused(Activity activity) {
paused = true;
if (check != null)
handler.removeCallbacks(check);
handler.postDelayed(check = new Runnable() {
#Override
public void run() {
if (foreground && paused) {
foreground = false;
Log.i(TAG, "went background");
for (Listener l : listeners) {
try {
l.onBecameBackground();
Intent intent = getPackageManager().getLaunchIntentForPackage("com.package.name");
if (intent != null) {
// We found the activity now start the activity
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
} else {
// Bring user to the market or let them choose an app?
intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("market://details?id=" + "com.package.name"));
startActivity(intent);
}
} catch (Exception exc) {
Log.e(TAG, "Listener threw exception!", exc);
}
}
} else {
Log.i(TAG, "still foreground");
}
}
}, CHECK_DELAY);
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
}
#Override
public void onActivityStarted(Activity activity) {
}
#Override
public void onActivityStopped(Activity activity) {
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
}
}
Now in onCreate method of Application.class put the code:
#Override
public void onCreate() {
super.onCreate();
Foreground.init(this);
}
You have to set your app's package name in onActivityPaused() method.
Thanks
Do the code in onPause
#Override
protected void onPause() {
Toast.makeText(getApplicationContext(),"Background",Toast.LENGTH_LONG).show();
super.onPause();
}
So if the app goes in background, you will get toast.
Hope it helps..All the best
Try using Services. Read more on http://developer.android.com/guide/components/services.html
I have a handler that I am using as follows:
handler.postDelayed(Play, 1000);
when my application onPause() is called before this is done, I need to pause it and tell it not to perform the "postDelayed" until I resume.
is this possible, or is there an alternative way?
My problem is that when onPause() is called I pause the audio (SoundManager), but if this handler.postDelayed is called after that, the audio will not be paused and will continue to play with my application in the background.
#Override
public void onPause()
{
Soundmanager.autoPause()
}
but then the postDelayed after 1000ms starts the audio playing again.
You need to subclass Handler and implement pause/resume methods as follows (then just call handler.pause() when you want to pause message handling, and call handler.resume() when you want to restart it):
class MyHandler extends Handler {
Stack<Message> s = new Stack<Message>();
boolean is_paused = false;
public synchronized void pause() {
is_paused = true;
}
public synchronized void resume() {
is_paused = false;
while (!s.empty()) {
sendMessageAtFrontOfQueue(s.pop());
}
}
#Override
public void handleMessage(Message msg) {
if (is_paused) {
s.push(Message.obtain(msg));
return;
}else{
super.handleMessage(msg);
// otherwise handle message as normal
// ...
}
}
//...
}
Have you tried with:
#Override
public void onPause()
{
handler.removeCallbacks(Play);
Soundmanager.autoPause()
}
Ger
Modifying the answer given by CpcCrunch. There handleMessage not worked for me, so instead of it using dispatchMessage. Note: Below code is written in Kotlin:
class CustomHandler: Handler() {
var s = Stack<Message>()
var is_paused = false
#Synchronized
fun pause() {
is_paused = true
}
#Synchronized
fun resume() {
is_paused = false
while (!s.empty()) {
sendMessageAtFrontOfQueue(s.pop())
}
}
override fun dispatchMessage(msg: Message?) {
if (is_paused) {
s.push(Message.obtain(msg))
return
} else {
super.dispatchMessage(msg)
}
}
}
public class YourActivity extends AppCompatActivity {
private static boolean handlerflag=false;
private Handler handler;
private Runnable runnable;
private int myind=0,index=0,count=0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activtiy);
//oncreate exe only
handlerflag=true;
handler = new Handler();
startyourtime(0);
}
private void startyourtime(int a) {
myind=0;
for (index=a; index<10 ;index++) {
myind++;
runnable=new Runnable() {
count++;
#Override
public void run() {
//your code here
}
};handler.postDelayed(runnable, Constants.TIME_LIMIT * myind);
}
#Override
protected void onPause() {
super.onPause();
handlerflag=false;
handler.removeCallbacksAndMessages(null);
}
#Override
protected void onResume() {
super.onResume();
if(!handlerflag)
{
startyourtime(count);
}
}
}
I came up with an alternative to CpnCrunch when wanting to pause/resume Runnables in a queue. To have methods that has been called whilst still connecting and is offline, once online, resume the queue and all runnables are executed.
Instead of using Handler, use ExecutorService:
public class ExecutorQueueService extends ThreadPoolExecutor {
private Stack<Runnable> runnables = new Stack<>();
private boolean paused = false;
public ExecutorQueueService() {
super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
public synchronized void pause() {
paused = true;
}
public synchronized void resume() {
paused = false;
while (!runnables.empty()) {
execute(runnables.pop());
}
}
public synchronized boolean isPaused() {
return paused;
}
#Override
public void execute(Runnable runnable) {
if (paused) {
runnables.push(runnable);
} else {
super.execute(runnable);
}
}
}
Using it is similar to Handler, but instead of post(runnable), use execute(runnable)