Avoiding threads restarting when changing activity - java

Right now, when I change the activity, my thread seams to go to sleep or something. And when I come back to the main activity, there are two threads running, doing the same things. I'm not sure if this is the case, but it seems like it's something equal.
...
public class MainActivity extends Activity {
public static double cowCount = 195;
public static double income = 0.100;
static boolean twiceCow = false, Threadrunning = false;
...
public void inc() {
new Thread(new income()).start();
}
class income implements Runnable {
#Override
public void run() {
for (int i = 0; i < 20;) {
final int value = i;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
cowCount = cowCount + income;
refresh();
}
});
}
}
}
This is how my thread looks like.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
checkThread();
}
private void checkThread() {
if (Threadrunning == false)
inc();
Threadrunning = true;
}
public void inc() {
new Thread(new income()).start();
}
...
public void refresh () {
TextView myTextView = (TextView)findViewById(R.id.myText);
myTextView.setText("You Have " + String.valueOf((nf.format(cowCount)) + " Cows!"));
}
I don't really understand what I've done wrong.

Please review this post: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Consider your activity re-start as the same thing as a config change.
This pattern, i.e. using a retained Fragment as a container for your thread, and proxying UI updates via callbacks to your activity, is a pattern that will work much better for you.
In your case you'd need only a single TaskCallback for your UI refresh(), e.g. onRefreshCowCount(int cows);

Related

Keep UI responsive while fetch data from internet alternative of Handler postDelayed

I have a ArrayList that I fetch from internet. Now I am performing the list retrieval using Handler postdelayed. Like below in the onCreate of the activity.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
lis_dat.remove(lis_dat.size() - 1);
if (gri_not_lis) {
rv_3r_ada.notifyItemRemoved(lis_dat.size());
} else {
rv_3r_2c_ada.notifyItemRemoved(lis_dat.size());
}
List<String> lis_of_dat;
int cou = 0, pos = lis_dat.size();
String gen_sta, gen_end, gen_mon;
if (yea) {
String[] mon_sym = new DateFormatSymbols().getMonths();
lis_of_dat = Arrays.asList(mon_sym);
} else {
int how_man;
if (lis_is_new) {
how_man = 500;
} else {
how_man = 15;
}
if (day_in_bet(sta, end) <= how_man) {
gen_sta = sta;
gen_end = end;
} else {
gen_sta = sta;
Calendar cal = Calendar.getInstance();
cal.setTime(db_han.con_dat(sta));
cal.add(Calendar.DATE, how_man);
gen_end = USE_DAT.format(cal.getTime());
}
lis_of_dat = gen_dat_in_bet(gen_sta, gen_end);
}
for (String dat : lis_of_dat) {
if (yea) {
Date date = get_mon_dat(dat, YEA.format(db_han.con_dat(sta)));
gen_sta = get_mon_fir_or_las_dat(date, true);
gen_end = get_mon_fir_or_las_dat(date, false);
gen_mon = dat;
} else {
gen_sta = dat;
gen_end = null;
gen_mon = mon;
}
add_to_lis(gen_sta, gen_end, gen_mon, pos, gri_not_lis);
pos++;
}
pos_f[0] = pos;
cou_f[0] = cou;
is_loa = false;
}
}, 1000);
Now my question is this 1000 milliseconds here may vary in different devices. On whom the UI will stay frozen. So what's the alternative of this. Instead of waiting for 1 sec how can I wait till the UI loading is complete and then I do the retrieval?
I could use AsyncTask but then the task will stay running till the task is complete even if I go to another activity. but i don't need the task running after onPause is called. So how do I do it?
You can use AsyncTask which running in separate thread, your keeps UI responsive . You can cancel it in onPause of Activity by calling **asyncTaskRunner.cancel(true) **
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
private String resp;
ProgressDialog progressDialog;
#Override
protected String doInBackground(String... params) {
return resp;
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}
You can save instance of handler and then remove all call backs in
onPause of the activity.
private Handler handler = new Handler();
handler.postDelayed(() -> {
// do you task here
},1000);
#Override
public void onPause() {
super.onPause();
handler.removeCallbacksAndMessages(null); // this is important
}
And if you want something which do not freeze UI without any delay,
there you go
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Executors.newSingleThreadExecutor().submit(() -> {
// Do you task here without any delay it will not freeze the UI
});
}
You can also try this,
class MyThread implements Runnable{
#Override
public void run() {
// Your Task Here, put your all calculations Here
}
}
and then in onCrate()
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new MyThread());
and then in onPause() or onDestory()
executor.shutdownNow();// this will stop the thread instantly

Display values in ArrayList one by one in textView

I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);

Android System.Err for setVisibility(View.GONE)?

I've noticed a bug in a basic survey app I'm making to better learn android.
Occasionally I get a W/System.errīš• at MainActivity.surveyAvailable(MainActivity.java:40) that points to this line of code:
button.setVisibility(View.GONE);
I've used setVisibility many times before and never had any issues.
Here's the function, this gets called when the user first enters the app, and after they finish taking a survey to check the server and see if there is another survey available for the user:
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
Button button = (Button)findViewById(R.id.takeSurveyButton);
if (surveyIsAvailable) {
button.setVisibility(View.VISIBLE);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
button.setVisibility(View.GONE);
}
}
When a survey isn't available, the appropriate lines are logged - App survey is available? false and 'We hit here'. But then the button sometimes doesn't get set to View.GONE and I see the System.Err line. But sometimes it works fine and the button's visibility does change. Any idea how to fix that? Or how to get more information on what the System.Err actually means?
EDIT:
I found that by setting Button surveyButton; in my activity and then referencing the button as this.surveyButton seems to get the functionality to work more along the lines of what we'd expect (e.g. when we call button.setVisibility(View.GONE) the view is actually consistently GONE). But it still throws the System.Err line which has me hesitant that things are working correctly.
Edited Activity:
public class MainActivity extends ActionBarActivity implements SurveyListener {
Button surveyButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.surveyButton = (Button)findViewById(R.id.takeSurveyButton);
}
public void surveyAvailable(boolean surveyIsAvailable) {
Log.d("MainActivity", "App survey is available? " + surveyIsAvailable );
if (surveyIsAvailable) {
this.surveyButton.setVisibility(View.VISIBLE);
this.surveyButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
App.getInstance().showSurvey();
}
});
} else {
Log.d("MainActivity", "We hit here");
this.surveyButton.setVisibility(View.GONE);
}
}
}
The activity implements this class:
public abstract interface SurveyListener
{
public abstract void surveyAvailable(boolean surveyAvailable);
}
Main App class that checks for surveys and calls 'surveyAvailable()`:
public class App
{
private static App _instance;
private SurveyListener _eventsHandler;
private String _apiKey = "";
private String _appuserId = "";
private String _surveyUrl = "";
private Activity _parentContext;
private Boolean _surveyAvailable;
public static App initWithApiKeyAndListener(String apiKey, SurveyListener surveyEventsHandler) {
if (_instance == null)
{
_instance = new App();
_instance._parentContext = (Activity) surveyEventsHandler;
_instance.setSurveyListener(surveyEventsHandler);
_instance.setApiKey(apiKey);
String appuserId = PreferenceManager.getDefaultSharedPreferences((Activity) _instance._eventsHandler).getString(tag, "no_appuser");
if (appuserId == "no_appuser") {
_instance._surveyAvailable = true;
_instance.alertAvailability(true);
} else {
_instance.checkForCampaigns();
}
}
return _instance;
}
private void alertAvailability(boolean surveyAvailable) {
App.getInstance()._eventsHandler.surveyAvailable(surveyAvailable);
}
private void checkForCampaigns() {
new CampaignCheck().execute();
}
public static App getInstance()
{
if (_instance == null)
{
_instance = new App();
}
return _instance;
}
public void donePushed()
{
App.getInstance().checkForCampaigns();
}
private class CampaignCheck extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
Boolean surveysAvailable = false;
try {
surveysAvailable = new AppuserConnection().checkCampaigns();
App.getInstance()._surveyAvailable = surveysAvailable;
App.getInstance().alertAvailability(_surveyAvailable);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
}
}
}
You shouldn't modify the UI elements from a different thread. You are doing this by calling App.getInstance().alertAvailability(_surveyAvailable); on a background thread. Move this to the AsyncTask's onPostExecute.

Android - Sharing surfaceview between Activities or prevent drawing tasks to lock the main thread when switching activity

I am developing an app which uses a common header in all its activities.
The header contains a sort of a custom progress bar which indicates task completion. The "progress bar" is implemented by subclassing a SurfaceView and the drawing operations are managed by an inner ExecutorService.
The tasks which tell the "progress bar" to run a certain animation are issued by a Singleton custom AsyncTaskManager, which holds a reference to the custom SurfaceView and the current activity.
Some of the AsyncTasks the singleton manager controls are executed upon custom Activities onCreate method, hence sometimes the AsyncTaskManager notifies the progress bar to animate before the activity is actually displayed.
It can also happens that the user might choose to switch activity before the progressbar's drawing Runnable task is finished.
To better explain, this is what happens when I switch to some activities:
oldActivity tells the ExecutorService to cancel it's Future task that draws on the SurfaceView canvas.
newActivity's onCreate is triggered and issues the AsyncTaskManager
singleton to start a new AsyncTask.
The AsyncTask in its onPreExecute tells the progress bar to start drawing on its canvas.
The ExecutorService manages the drawing Runnable, which in turn
locks the SurfaceHolder
When the AsyncTask completes, in its onPostExecute method,
tells the surfaceview drawing Runnable to draw a different thing
according on the result.
The problem I am having is that SOMETIMES (not always - seems randomly but maybe it has to do with tasks threadpools), upon starting the new activity, the application skips frames xx where xx is apparently random (sometimes it skips ~30 frames, other times ~ 300, other times the app gets an ANR).
I have been trying to solve this for some days now, but to no avail.
I think the problem could be one of the following or a combination of both:
The drawing thread does not cancel/ends in a timely manner thus causing the SurfaceHolder to stay locked and thus preventing the Activity to take control of the View as it goes onPause/onResume and hence leading to the main thread skipping frames. The animation is by no means heavy in terms of computations (a couple of dots moving around) but it needs to last at least 300ms to properly notify the user.
The singleton AsyncTaskManager holds the reference to the "leaving activity"'s SurfaceView preventing the former to be destroyed until the surfaceholder is released and causing the frame-skipping.
I am more prone to believe the second issue is what is making Coreographer's angry and so this leads to the following question:
How can I share the SAME (as in the same instance) surfaceView (or any view, really) between all the activities or alternatively to allow the current instance of SurfaceView to be destroyed and recreated without waiting fot the threads to join/interrupt?
As it is now, the SurfaceView is being destroyed/recreated when switching between activities and I would have nothing against it if its drawing thread would stop as the new activity begins its lifecycle.
This is the custom AsyncTaskManager that holds a reference to the SurfaceView
public class AsyncTaskManager {
private RefreshLoaderView mLoader;
//reference to the customactivity holding the surfaceview
private CustomBaseActivity mActivity;
private final ConcurrentSkipListSet<RequestedTask> mRequestedTasks;
private volatile static AsyncTaskManager instance;
private AsyncTaskManager() {
mRequestedTasks = new ConcurrentSkipListSet<RequestedTask>(new RequestedTaskComparator());
}
public void setCurrentActivity(CustomBaseActivity activity) {
mActivity = activity;
if (mLoader != null) {
mLoader.onDestroy();
}
mLoader = (RefreshLoaderView) mActivity.getViewById(R.id.mainLoader);
}
This is what happens when an AsyncTask (RequestedTask in the above code snippet)
is executed
#Override
protected void onPreExecute() {
if (mLoader != null) {
mLoader.notifyTaskStarted();
}
}
#Override
protected Integer doInBackground(Void... params) {
//do the heavy lifting here...
}
#Override
protected void onPostExecute(Integer result) {
switch (result) {
case RESULT_SUCCESS:
if (mLoader != null) {
mLoader.notifyTaskSuccess();
}
break;
//TELLS THE SURFACE VIEW TO PLAY DIFFERENT ANIMATIONS ACCORDING TO RESULT ...
This is the CustomBaseActivity that holds the SurfaceView from which all others activities inherit.
public abstract class CustomBaseActivity extends FragmentActivity {
private volatile RefreshLoaderView mLoader;
//...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_base);
mLoaderContainer = (FrameLayout) findViewById(R.id.mainLoaderContainer);
mLoader = (RefreshLoaderView) findViewById(R.id.mainLoader);
//other uninteresting stuff goin on ...
And the code for the SurfaceView as well:
public class RefreshLoaderView extends SurfaceView implements SurfaceHolder.Callback {
private LoaderThread mLoaderThread;
private volatile SurfaceHolder mHolder;
private static final int ANIMATION_TIME = 600;
private final ExecutorService mExecutor;
private Future mExecutingTask;
public RefreshLoaderView(Context context) {
super(context);
...
init();
}
private void init() {
mLoaderThread = new LoaderThread();
...
}
#Override
public void surfaceChanged(SurfaceHolder holder, int arg1, int arg2, int arg3) {
...
mHolder = this.getHolder();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
//uninteresting stuff here
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
stopThread();
}
private void stopThread() {
mLoaderThread.setRunning(false);
if (mExecutingTask != null) {
mExecutingTask.cancel(true);
}
}
private void startThread() {
if (mLoaderThread == null) {
mLoaderThread = new LoaderThread();
}
mLoaderThread.setRunning(true);
mExecutingTask = mExecutor.submit(mLoaderThread);
}
public void notifyTaskStarted() {
stopThread();
startThread();
mLoaderThread.setAction(LoaderThread.ANIMATION_TASK_STARTED);
}
public void notifyTaskFailed() {
mLoaderThread.setAction(LoaderThread.ANIMATION_TASK_FAILED);
}
public void notifyTaskSuccess() {
mLoaderThread.setAction(LoaderThread.ANIMATION_TASK_SUCCESS);
}
private class LoaderThread implements Runnable {
private volatile boolean mRunning = false;
private int mAction;
private long mStartTime;
private int mMode;
public final static int ANIMATION_TASK_STARTED = 0;
public final static int ANIMATION_TASK_FAILED = 1;
public final static int ANIMATION_TASK_SUCCESS = 2;
private final static int MODE_COMPLETING = 0;
private final static int MODE_ENDING = 1;
public LoaderThread() {
mMode = 0;
}
public synchronized boolean isRunning() {
return mRunning;
}
public synchronized void setRunning(boolean running) {
mRunning = running;
if (running) {
mStartTime = System.currentTimeMillis();
}
}
public void setAction(int action) {
mAction = action;
}
#Override
public void run() {
if (!mRunning) {
return;
}
while (mRunning) {
Canvas c = null;
try {
c = mHolder.lockCanvas();
synchronized (mHolder) {
//switcho quello che devo animare
if (c != null) {
switch (mAction) {
case ANIMATION_TASK_STARTED:
animationTaskStarted(c);
break;
case ANIMATION_TASK_FAILED:
animationTaskFailed(c, mMode);
break;
case ANIMATION_TASK_SUCCESS:
animationTaskSuccess(c, mMode);
break;
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (c != null) {
mHolder.unlockCanvasAndPost(c);
}
}
}
}
private void animationTaskStarted(Canvas canvas) {
//do an animation here
}
private void animationCloseLoaderCycle(Canvas canvas) {
//do stuff here ...
} else {
mStartTime = System.currentTimeMillis();
mMode = MODE_ENDING;
}
}
private void queryThreadClose() {
mProgress = 0;
mMode = MODE_COMPLETING;
mRunning = false;
}
private void animationTaskFailed(Canvas canvas, int mode) {
switch (mode) {
case MODE_COMPLETING:
animationCloseLoaderCycle(canvas);
break;
case MODE_ENDING:
if (System.currentTimeMillis() - mStartTime < ANIMATION_TIME) {
//notify user task is failed
} else {
queryThreadClose();
}
break;
}
}
private void animationTaskSuccess(Canvas canvas, int mode) {
switch (mode) {
case MODE_COMPLETING:
animationCloseLoaderCycle(canvas);
break;
case MODE_ENDING:
if (System.currentTimeMillis() - mStartTime < ANIMATION_TIME) {
//notify user task is failed
} else {
queryThreadClose();
}
break;
}
}
}
public void onPause() {
stopThread();
}
public void onStop() {
stopThread();
}
public void onDestroy() {
stopThread();
}
}
Using DDMS when Coreographer warns me I'm skipping frame shows that there are usually around 30 threads (daemon and normal) running, where an asynctask, the main thread and the drawing task are waiting for something.
(Also, how can I check what are they waiting for?)
Thanks in advance for your help.
Edit: these are the main thread calls when it hangs, according to DDMS Threads view:
at hava.lang.Object.wait(Native Method)
at java.lang.Thread.parkFor(Thread.java:1205)
at sun.misc.Unsafe.park(Unsafe.java:325)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:813)
...
I solved this in the end. There was a mistake in the synchronized block:
while (mRunning) {
Canvas c = null;
try {
//mistake was here
c = mHolder.lockCanvas();
synchronized (mHolder) {
if (c != null) {
//do stuff
}
}
}
I was getting the canvas outside the synchronized block, thus causing a deadlock when the activity needed to be destroyed/recreated.
moving c = mHolder.lockCanvas(); inside the synchronized block solved this.
in the end the working code is as follows:
synchronized (mHolder) {
c = mHolder.lockCanvas();
if (c != null) {
switch (mAction) {
//do stuff
}
}
}
Thanks anyway!

Is is possible to make a method execute only once?

I have a for loop and structure like this:
for(....)
....
....
if(isTrue)
... do something..
.. method to be executed once (doTrick) is declared outside for loop.
....endif
endfor
public void doTrick()
...
...
..end
Is it possible for a method in for loop to be executed only once?
Sure!..
if(!alreadyExecuted) {
doTrick();
alreadyExecuted = true;
}
Your can use AtomicBoolean to make sure the task is only called the first time:
import java.util.concurrent.atomic.AtomicBoolean;
public class Once {
private final AtomicBoolean done = new AtomicBoolean();
public void run(Runnable task) {
if (done.get()) return;
if (done.compareAndSet(false, true)) {
task.run();
}
}
}
Usage:
Once once = new Once();
once.run(new Runnable() {
#Override
public void run() {
foo();
}
});
// or java 8
once.run(() -> foo());
if you use kotlin, you can do this:
val execOnce by lazy {
print("hello, world")
}
In Java 8, you can effectively do this using automatic memoization as described here: Do it in Java 8: Automatic memoization
I'll admit that memoization could be considered overkill for a "run once" scenario, but it is a rather clean alternative to some described in previous answers.
For instance:
public void doSomething() { ... }
Map<Boolean, Boolean> cache = new ConcurrentHashMap<>();
public void doSomethingOnce() {
cache.computeIfAbsent(true, x -> {
doSomething();
return true;
});
}
You can avoid the if() by using this trick:
private Runnable once;
private final static Runnable NOP = new Runnable () {
public void run () {
// Do nothing
}
}
public void method () {
once = new Runnable () {
public void run () {
doTrick();
once = NOP;
}
}
for (...) {
...
once.run();
...
}
}
Another overkill solution:
Depending on what you want to do, it might be possible to use a static initialization block.
public class YourKlass{
public void yourMethod(){
DoTrick trick;
for( int i = 0; condition; i++){
// ... (1)
trick = new DoTrick(); // or any kind of accessing DoTrick
// ... (2)
}
}
}
public class DoTrick{
static{
// Whatever should be executed only once
}
}
Simple solution:
Or, instead you just want to execute the first part outside of the loop:
int i = 0;
if( condition ){
// ... (1)
// do trick
// ... (2)
}
for(i = 1; condition; i++){
// ... (1)
// ... (2)
}
perhaps the break keyword is what you need? After running you method call break; I am sorry its not 100% clear what you mean from your question.
Have a look here from the sun docs
my sample from my app:
boolean alreadyExecuted = false;
then :
private void startMyService() {
if(!alreadyExecuted) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something after 4 seconds
context.startService(new Intent(context, myService.class));
alreadyExecuted = true;
}
}, 4000);
}
I want to do something slight more complex. In a multi-threaded environment ensure that the methods is run only one (which is solved by Hover Ruan's answer above), but also block any thread so none return until the method is done.
My solution is to use a Semaphore to do the blocking.
public class Once implements Runnable {
private static Semaphore signal = new Semaphore(1,true);
private static boolean done=false;
#Override
public void run() {
if(done)
return;
signal.acquireUninterruptibly();
if(done) {
signal.release();
return;
}
doTrick(); // actually run the task
done=true;
signal.release();
return;
}
static int result; // Result of running the task
static int count; // number of times its been called
/**
* The task we only want to run once
*/
public void doTrick() {
++count;
Random rnd = new Random();
for(int i=0;i<10000;++i) {
result += rnd.nextInt(100);
}
try {
Thread.sleep(1000); // just to ensure all thread start
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i=0;i<5;++i) { // multiple instances
final Once task = new Once();
for(int j=0;j<5;++j) { // multiple calls of same instance
executor.submit(() -> {
task.run();
System.out.println("Result "+Once.result+" count "+Once.count);
} );
}
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The program should pause, waiting until the first thread has finished, then all other threads should finish printing the result stored from the first run.
or by using Shared Preferences:
sharedpref = PreferenceManager.getDefaultSharedPreferences(this);
isFirstRun = sharedpref.getBoolean("FIRSTRUN", true);
if (isFirstRun)
{
// Do your unique code magic here
SharedPreferences.Editor editor = wmbPreference.edit();
editor.putBoolean("FIRSTRUN", false);
editor.commit();
}else{
//this will repeat everytime
}
Here is an example way. Just use "new Getlineonce();"
class Getlineonce {
static int[] linesRun = new int[0];
public Getlineonce() {
boolean lineRan = false;
int line = Thread.currentThread().getStackTrace()[2].getLineNumber();
for(int i = 0; i < linesRun.length; i++) {
if(line == linesRun[i]) {
lineRan = true; //Dont print
}
}
if(!lineRan) {
add(line);
System.out.println(line + " ran!");
}
}
public void add(int line) {
int newSize = linesRun.length+1;
int[] linesRunBuff = new int[newSize];
for(int i = 0; i < newSize-1; i++) {
linesRunBuff[i] = linesRun[i];
}
linesRunBuff[newSize-1] = line;
linesRun = linesRunBuff;
}
}
For me, the perfect solution was...
public class MainActivity extends BaseActivity {
private static boolean splash = false;
if (!splash){
runSplash();
}
private void runSplash(){
MainActivity.splash = true;
}
}
Defined my variable as private static and use the access via class.variable in my function :)
Try this. First, this will be called only once when the app is being installed for the first time on the user's device. Use SharedPreferences this will help us to remember that this method has already been called so it will not re-call it again when the app is killed or even if the device was turned off. (But keep in mind that when the user un-stall and then re-install the app the method will be called again)
public class MainActivity extends AppCompatActivity {
private static boolean alreadyExecuted = false; // Use private static boolean
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); // Use SharedPreferences
if (!prefs.getBoolean("onlyonce", false)) {
startMyService(); // Method to be called only once as long as the app wont be un-stalled but there is
// no problem if the app will be killed or the device being turned off.
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("onlyonce", true);
editor.commit();
}
}
private void startMyService() {
if (!alreadyExecuted) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(MainActivity.this, SecondActivity2.class);
startActivity(intent);
alreadyExecuted = true;
}
}, 4000);
}
}
}
import java.util.ArrayList;
class RemoveDuplicate {
public static void main(String[] args) {
ArrayList<String> originalList = new ArrayList<String>();
originalList.add("foo");
originalList.add("bar");
originalList.add("bat");
originalList.add("baz");
originalList.add("bar");
originalList.add("bar");
String str="bar";
ArrayList<String> duplicateList = new ArrayList<String>();
// adding duplicates to duplicateList
for(String currentString : originalList) {
if(currentString.startsWith(str)) {
duplicateList.add(currentString);
}
}
// removing duplicates in duplicatesList
for(String removeString : duplicateList) {
originalList.remove(removeString);
}
// finally adding duplicateElement
originalList.add(str);
for(String currEntry : originalList) {
System.out.println(currEntry);
}
}
}

Categories