I'm practicing on async tasks. I want to use intent while the program is performing some calculation.
I can't use the intent in onClick, probably in onProgressUpdate.
public class MainActivity extends Activity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnStart=(Button) findViewById(R.id.btnStart);
Button btnAsync=(Button) findViewById(R.id.btnAsync);
btnStart.setOnClickListener(this);
btnAsync.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart:
doLongTaskOnMain(50001);
break;
case R.id.btnAsync:
LongTask task=new LongTask();
task.execute(50000);
break;
}
}
private void doLongTaskOnMain(int number){
TextView textOutput=(TextView) findViewById(R.id.textOutput);
textOutput.setText("Calculating sum of :"+number);
long sum=0;
for(int i=0;i<number; i++){
sum+= i;
textOutput.setText("Progress"+100f*i/number);
}
textOutput.setText("Sum: "+sum);
}
class LongTask extends AsyncTask<Integer, Float, Long>{ //<Params, Progress, Result>
#Override
protected void onPreExecute() {
TextView textOutput=(TextView) findViewById(R.id.textOutput);
textOutput.setText("Start");
}
#Override
protected Long doInBackground(Integer... params) {
int number= params[0];
long sum=0;
for(int i=0;i<number;i++){
sum+=i;
publishProgress(100f*i/number);
}
return sum;
}
#Override
protected void onProgressUpdate(Float... values) {
Float progress=values[0];
TextView textOutput=(TextView) findViewById(R.id.textOutput);
textOutput.setText("progress "+Math.round(progress)+"%");
Button btnNext=(Button) findViewById(R.id.btnNext);
}
#Override
protected void onPostExecute(Long result) {
TextView textOutput=(TextView) findViewById(R.id.textOutput);
textOutput.setText("sum: "+result);
}
}
}
The Second Activity:
public class SecondActivity extends Activity implements OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
Button btnBack= (Button) findViewById(R.id.btnBack);
btnBack.setOnClickListener(this);
}
#Override
public void onClick(View arg0) {
Intent intent=new Intent(this,MainActivity.class);
startActivity(intent);
}
}
How can I move to the second activity without stopping the calculation?
You can make your AsyncTask a standalone class, and have it an Activity member (better a weak reference though). Then, in your first activity's onCreate() you set that member to the first Activity, in a second Activity's onCreate() to the 2nd activity.
This way your onPostExecute will have the correct activity.
You can probably use an event bus instead such as Green Robot
Related
I'm facing a problem: I created two Activities.
One is the main Activity, which has a Button.
When I click this Button, the second Activity starts.
The second Activity uses an Asynctask in which a number is incremented from 1 to 10 and displays this number in a Textview
What I'm facing is that when I click the back Button while the Asynctask has not completed and then again go to the second Activity the Asynctask is not run from start immediately.
I know because in background when it completed the old task then it again starts a new task. Is there a way to fix this when destroying the Activity it also destroy the Asynctask?
Here is video sample for my problem.
Code for Main Activity:
public class MainActivity extends AppCompatActivity {
Button bt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this,SecondAcitivity.class);
startActivity(i);
}
});
}
}
Code of Second Activity:
public class SecondAcitivity extends AppCompatActivity {
TextView t1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
OurWork obj = new OurWork();
obj.execute();
}
class OurWork extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11) {
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
#Override
protected void onProgressUpdate(Integer... values) {
t1.setText(values[0] + "%");
}
#Override
protected void onPostExecute(String result) {
t1.setText(result);
}
}
}
you need to cancel the task on back pressed, and you need to monitor if the task is canceled while executing the doInbackground().
1- override onbackpressed:
#Override
public void onBackPressed() {
obj.cancel(true); // where obj is the asyncTask refernce object name
super.onBackPressed();
}
2- monitor isCanceled()
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11 && !isCancelled()) { // added !isCancelled()
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
on next iteration of the while loop, after cancel(true); is called,the loop will quit, and doInBackground() will return.
When you press back button , onBackPressed callback is called. so you can basically try this :
#Override
public void onBackPressed() {
if (asyncFetch.getStatus() == AsyncTask.Status.RUNNING) {
asyncFetch.cancel(true);
}
finish();
}
Try to use :
private OurWork task;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
task = new OurWork();
task.execute();
}
#Override
public void onBackPressed() {
task.cancel(true);
super.onBackPressed();
}
AsyncTask runs in background of the activity where it was hosted. If OnPause or OnDestroy is called, AsyncTask is destroyed, so to solve this issue, Override OnResume and execute AsyncTask again.
To cancel the asyncTask even when it is running when back is pressed, add this to onBackPressed:
public class SecondAcitivity extends AppCompatActivity {
TextView t1;
static OurWork obj;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_acitivity);
t1 = (TextView) findViewById(R.id.t1);
obj = new OurWork();
obj.execute();
}
class OurWork extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
int i = 0;
while (i < 11) {
try {
Thread.sleep(700);
publishProgress(i);
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Successfully Completed";
}
#Override
protected void onProgressUpdate(Integer... values) {
t1.setText(values[0] + "%");
}
#Override
protected void onPostExecute(String result) {
t1.setText(result);
}
}
//override onBackPressed and do this
#Override
public void onBackPressed() {
if (obj!=null && (obj.getStatus()== AsyncTask.Status.RUNNING ||
obj.getStatus()== AsyncTask.Status.PENDING ))
obj.cancel(true);
super.onBackPressed();
}
}
I'm developing an app that when user clicks on a Button it executes an Asynctask that this class calls a method at it's onPostExecute method that calls another Asynctask! It works when user clicks once, but at the second time it crashes and says Cannot execute task: the task has already been executed (a task can be executed only once)
.
public class Test extends Activity {
A a;
B b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
a = new A();
a.execute();
}
});
}
class A extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
// doing st
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
runB();
a.cancel(true);
}
}
public void runB() {
b = new B();
b.execute();
}
class B extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
// doing st
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//doing st
b.cancel(true);
}
}
Use AsyncTask.Status for checking status of AsyncTask before calling AsyncTask.execute() method on Button onClick:
#Override
public void onClick(View arg0) {
if(a ==null){
a = new A();
a.execute();
}
}
And in onPostExecute of B class assign null to a :
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//doing st
b.cancel(true);
a=null;
}
i have following problem:
I've made a simple android app that adds 1 to an integer every 1000 ms using a handler, and then display this integer.
The problem is that when i start another activity the same thing happens, which would be fine, if that was intended. The mentioned function is not called in the new activity and yet it seems to be. Please look over my code and show me where it went wrong..
MainActivity:
public class MainActivity extends ActionBarActivity {
protected TextView text;
protected int position;
private Handler handler = new Handler();
private int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
position=0;
SetButtonCLickListener();
counter();
}
protected void SetButtonCLickListener() {
Button btn = (Button) findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
SwitchActivity();
}
});
}
private void counter() {
handler.removeCallbacks(count);
handler.postDelayed(count, 1000);
}
private Runnable count = new Runnable() {
public void run() {
i++;
text.setText("Count: " + i);
handler.postDelayed(count, 1000);
}
};
protected void SwitchActivity() {
if (position == 1) {
finish();
} else {
Intent intent = new Intent(this, MainActivity2.class);
startActivity(intent);
}
}
}
SecondActivity
public class MainActivity2 extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_activity2);
text = (TextView) findViewById(R.id.text);
SetButtonCLickListener();
position=1;
}
}
MainActivity2 has an onCreate() method. In the onCreate() method, you call super.onCreate(), which triggers the MainActivity implementation of onCreate(). The MainActivity implementation of onCreate() is where you are starting your counter thing, via its call to the counter() method. Hence, when MainActivity2 starts up, its onCreate() calls MainActivity's onCreate(), which calls counter().
My guess is that MainActivity2 should inherit from Activity, not from MainActivity.
Here I have 3 activities: A, B, and C. From Activity A When I click a button it will goes to Activity B. When Activity B loads the countdown timer will start. Again, when I click a button in Activity B it will go to Activity C. Here I Need a Help.
When Activity C starts I need the countdown timer from Activity B to resume.
Again I switch over from Activity C to Activity B the countdown timer should be resumed from Activity C.
Activity A
public class MainActivity extends Activity {
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addListenerOnButton();
}
public void addListenerOnButton() {
final Context context = this;
button = (Button) findViewById(R.id.actone);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, Act_Two.class);
startActivity(intent);
}
});
}
}
Activity B
public class Act_Two extends Activity{
Button button;
public TextView textView1;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.act_two);
textView1=(TextView) findViewById(R.id.textView1);
MyCount counter = new MyCount(61000,1000);
counter.start();
addListenerOnButton();
}
public void addListenerOnButton() {
final Context context = this;
button = (Button) findViewById(R.id.acttwo);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, Act_Three.class);
startActivity(intent);
}
});
}
public class MyCount extends CountDownTimer{
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
//iFallApp app1 = new iFallApp();
#Override
public void onFinish() {
// TODO Auto-generated method stub
setContentView(R.layout.activity_main);
//textView1.setText("done");
}
#Override
public void onTick(long millisUntilFinished) {
// TODO Auto-generated method stub
textView1.setText(Long.toString(millisUntilFinished/1000));
}
}
}
While switching between the activities, try to pass the current count down time with the help of Bundle.
You should save a value of your CountDownTimer in Activty B and stop the CountDownTimer (using the cancel() method) in Activty B's onPause and start that CountDownTimer with saved value in onResume of Activty B. something like (assuming this is an Activity B code):
#Override
public void onPause() {
// turning off the timer
isWihesCountUpdateTimerNeeded = false;
if (wihesCountUpdateTimer!=null)
wihesCountUpdateTimer.cancel();
super.onPause();
}
#Override
public void onResume() {
super.onResume();
// resuming the timer
isWihesCountUpdateTimerNeeded = true;
totalWishesCount = SharedPrefsHelper.getTotalWishesCount(getActivity());
startWihesCountUpdateTimer();
}
// the timer increases some wishes count
private boolean isWihesCountUpdateTimerNeeded;
private CountDownTimer wihesCountUpdateTimer;
protected static final int wihesCountUpdateTimerDuration=5000;
protected int totalWishesCount;
private void startWihesCountUpdateTimer() {
wihesCountUpdateTimer = null;
if (!isWihesCountUpdateTimerNeeded)
return;
final int duration = wihesCountUpdateTimerDuration;
//Log.i(this, "startWihesCountUpdateTimer() duration: "+duration);
wihesCountUpdateTimer = new CountDownTimer(duration, 1000) {
#Override
public void onTick(long millisUntilFinished) {}
#Override
public void onFinish() {
totalWishesCount++;
SharedPrefsHelper.saveTotalWishesCount(getActivity(), totalWishesCount);
startWihesCountUpdateTimer();
}
}.start();
}
Okay so im having a hard time saving the state of my activity so that when the activity is destroyed it can restore where the user last left off. Here is my source code. If anyone could look at it and tell me how i would save and restore is please it will be greatly appreciated.
Here is my code...
public class DorothyTalk extends Activity{
Handler handler = new Handler();
int typeBar;
TextView text1;
EditText edit;
Button respond;
private String name;
private ProgressDialog progDialog;
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.dorothydialog);
text1 = (TextView)findViewById(com.fttech.da.R.id.dialog);
edit = (EditText)findViewById(com.fttech.da.R.id.repsond);
respond = (Button)findViewById(com.fttech.da.R.id.button01);
Talk();
}
protected Dialog onCreateDialog(int id) {
switch(id) {
case 0: // Spinner
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progDialog.setMessage("Loading...");
progDialog.setProgress(100);
return progDialog;
}
return progDialog;
}
public void Talk(){
text1.setText("Welcome what is your name?");
respond.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
name = edit.getText().toString();
new AsyncTask<Void, Integer, Void>(){
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
text1.setText("Nice to meet you "+name);
dismissDialog(typeBar);
}
#Override
protected void onPreExecute() {
typeBar = 0;
showDialog(typeBar);
}
}.execute((Void)null);
}
});
}
public void onBackPressed()
{
int i = Log.d("CDA", "onBackPressed Called");
Context localContext = getApplicationContext();
Intent localIntent = new Intent(localContext, mainMenu.class);
startActivityForResult(localIntent, 0);
return;
}
How can i save and restore when activity is destroyed?
You have to save your data before your activity is destroyed. You can test if it is going to be destroyed by using the isFinishing()
protected void onPause(){
if(isFinishing()){
saveData();
}
}
then you neeed to reload your data onCreate()
You can try overiding
public Object onRetainNonConfigurationInstance() {
//object returned here can always be recovered in getLaststNonConfigurationInstance()
return something;
}
and use getLastNonConfigurationInstance() to get the state back.