How to restore when activity is destroyed or paused? - android

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.

Related

How to show splash screen when using SQLiteAssetHelper library?

I use this library SQLiteAssetHelper for my precreated database. At first run, my app shows white screen only. I guess the library is copying my database(about 10 sec) to the appropriate location. And the splash screen only shown after the white screen. I want to show splash screen also while copying. How do I do that?
Here is my SplashActivity btw.
public class SplashActivity extends AppCompatActivity {
public static final String MyPREFERENCES = "MyPrefs" ;
public static final String COPIED = "copied";
SharedPreferences prefs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
prefs = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
if (prefs.getBoolean(COPIED, true)) {
new DatabaseCopier().execute(this);
prefs.edit().putBoolean(COPIED, false).commit();
} else {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
splashEnd();
}
}, 500);
}
}
private void splashEnd() {
Intent openListActivity = new Intent(this, MainListActivity.class);
startActivity(openListActivity);
}
#Override
protected void onPause() {
super.onPause();
finish();
}
private class DatabaseCopier extends AsyncTask<Context, Void, Void> {
#Override
protected Void doInBackground(Context... params) {
Log.i("suddenly here", "suddenly here 0");
BookDatabaseHelper.getInstance(params[0]); //I thought it start copy from here but not
DatabaseHelper.getInstance(params[0]);
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
splashEnd();
}
}
}

AsyncTask is not run from start when the Activity is created

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();
}
}

When using nested AsycTask in activity will handler reference remain after onDestroy

I have sample code which very simply does some heavy work and sends a message to a handler to update the UIThread. My concern is with the handler reference i am passing to the constructor. If my activity gets destroyed while the asncTask is still running will the handler reference not be null ?
public class SomeActivity extends Activity
{
private static final int UPDATE_BUTTON_TEXT = 1;
private static final SomeActivity me = null;
private static Handler handler = new Handler() {
public void handleMessage(Message msg) {
if (me == null) return;
switch (msg.what) {
case UPDATE_BUTTON_TEXT:
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
}
};
private View.OnClickListener onClickListener = new View.OnClickListener() {
public void onClick(View view) {
new SomeLongRunningTask().execute();
}
};
private static class SomeLongRunningTask extends AsyncTask<Void, Void, Boolean> {
private Handler handler;
public SomeLongRunningTask(Handler handler) {
this.handler = handler;
}
#Override
protected Boolean doInBackground(Void... voids) {
try {
Thread.sleep(30000); // replace with some background logic
} catch (InterruptedException e) {}
return true;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
//can the handler be null here if activity is destroyed ????
Message msg = handler.obtainMessage(UPDATE_BUTTON_TEXT);
msg.obj = "success"
handler.sendMessage(msg);
}
}
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button someButton = (Button) findViewById(R.id.someButton);
someButton.setOnClickListener(onClickListener);
}
#Override
protected void onStart() {
super.onStart();
me = this;
}
#Override
protected void onStop() {
me = null;
super.onStop();
}
}
Yes, the reference of the handler is going to be retained in memory until it has a reference count > 0.
I think you should use AsyncTask().onProgressUpdate for updating progress on UI, which does what you're trying to do.
EDIT
If you're updating ui in onPostExecute then you don't need to use onProgressUpdate(my apologies).
Just use an interface as a callback function like below:
private interface Callback {
void updateUI(String value);
}
private static class SomeLongRunningTask extends AsyncTask<Void, String, Boolean> {
private Callback mCallback;
public SomeLongRunningTask(Callback callback) {
mCallback = callback;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
mCallback.updateUI("success");
}
}
// somewhere else...
Callback callback = new Callback() {
#Override
public void updateUI(String value) {
Button btn = (Button) me.findViewById(R.id.someButton);
btn.setText((String) msg.obj);
}
};
new SomeLongRunningTask(callback).execute();
Also it doesn't seem right to have a handler instance as a static variable. It will last until the class is unloaded.
As a rule, whenever I write an AsyncTask subclass, I use a pattern like this:
private WeakReference<Callback> mCallbackRef;
public MyAsyncTask(Callback callback) {
mCallbackRef = new WeakReference<>(callback);
}
#Override
protected void onPostExecute(Boolean aBoolean) {
if (mCallbackRef != null) {
Callback callback = mCallbackRef.get();
if (callback != null) {
callback.updateUI("success");
}
}
}

Pointing to wrong UI from posted Runnable after screen orintation changes

This is my little test program. My problem is that from run() method I access to fields of wrong (old) Activity, which was destroyed after screen orientation changed. What's the way to handle this situation?
And, by the way, I must have my activity been recreated, because in real application I have different layouts for portrait and landscape modes!
public class MainActivity extends Activity {
private EditText edit;
private Button button;
private ProgressDialog progressDialog;
private boolean isLoginInProgress = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edit = (EditText) findViewById(R.id.edit_timer);
button = (Button) findViewById(R.id.btn_start);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
if (edit.getText().toString().length() == 0) throw new Exception();
long dTime = Long.parseLong(edit.getText().toString());
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
MainActivity.this.isLoginInProgress = false;
progressDialog.dismiss();
}
}, dTime);
progressDialog.show();
isLoginInProgress = true;
} catch (Exception e) {
Toast.makeText(MainActivity.this, "bad time value", Toast.LENGTH_SHORT).show();
}
}
});
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("loading");
if (savedInstanceState != null) { // activity is restarted
isLoginInProgress = savedInstanceState.getBoolean("fl_login");
edit.setText(savedInstanceState.getString("edit"));
}
if (isLoginInProgress) { // Show dialog again
progressDialog.show();
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putBoolean("fl_login", isLoginInProgress);
outState.putString("edit", edit.getText().toString());
}
#Override
public void onDestroy(){
super.onDestroy();
progressDialog.dismiss();
}
}
You Can Use Database(SQLITE) for Storing Your Values..

Android splash screen and server communication

I am developing an application in android, where i need to display a splash screen and at the same time there will be server communication. The problem here is when i launch the app, first application is communicating with the server and then it is displaying the splash screen. I want to both server communication and splash screen at the same time.
The following is my code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
try {
Thread thread = new Thread(this);
thread.start();
thread.join();
//Attractions
CommonMethods.getSystemOutput("Response Json Array String Attractions:::"+jArrayMobileAttractions);
attractionsDate = JsonParsing.getLatestDate(jArrayMobileAttractions);
attractionsDate = getDate(attractionsDate);
CommonMethods.getSystemOutput("Attractions Date:::::"+attractionsDate);
//Categories
CommonMethods.getSystemOutput("Response Json Array String Categories:::"+jArrayCategories);
categoryDate = JsonParsing.getLatestDate(jArrayCategories);
categoryDate = getDate(categoryDate);
CommonMethods.getSystemOutput("Category date:::"+categoryDate);
//Contacts
CommonMethods.getSystemOutput("Response Json Array String Contacts:::"+jArrayContacts);
contactsDate = JsonParsing.getLatestDate(jArrayContacts);
contactsDate = getDate(contactsDate);
CommonMethods.getSystemOutput("Contacts Date:::"+contactsDate);
} catch (Exception e) {
CommonMethods.getSystemOutput("Exception in Splash screen thread:::"+e);
}
}
public void run() {
// if (attractionsDate == null) {
jArrayMobileAttractions = RequestHandler.getJSONfromURL(Constants.MOBILE_ATTRACTIONS_URL);
jArrayCategories = RequestHandler.getJSONfromURL(Constants.CATEGORY_URL);
jArrayContacts = RequestHandler.getJSONfromURL(Constants.CONTACTS_URL);
// } else {
// jArrayMobileAttractions = RequestHandler.getJSONfromURL(Constants.MOBILE_ATTRACTIONS_URL+"?lastupdateddate="+attractionsDate);
// }
}
You can use the AsynchTask Manager in which it has a method
private class DownloadWebPageTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
// Do Server Interaction Here
return response;
}
#Override
protected void onPreExecute(String result) {
//Show your Splash Screen
}
#Override
protected void onPostExecute(String result) {
//Gone the Splash Screen view
}
}
For this purpose it will be better start from "SplashActivity" - in onCreate() start new Thread for communication with server, and when all communication finished - call startActivityForResult(mainActivityIntent). For correct behavior back button finish splash activity on finish main activity. Approximate code:
public class SplashActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setup view for activity
new Thread(new Runnable() {
public void run() {
// do here some long operation
startActivityForResult(new Intent(SplashActivity.this, MainActivity.class), 0);
}
}).start();
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
finish();
}
}
I had the same thing to do and I did it this way and it works just fine. I had to show the splashscreen and download some file from the server, unzip it, move files insto proper directories and then start the apps main screen. Here is the code, I used AsyncTask.
So, you have three AsyncTask classes, one for each task and in the onPostExecute() I call the next AsyncTask. I can't say if this is the best way but it works for me.
I removed unneccessary code but for clarity I left a call to a dialog where I ask a user ih he wants to proceed with downloading as it may take a while. Also I check if FIRST_RUN is true just so I know if I should download the package since for my app I need to do it only the first time, so if it is true I do the spashscreen activities and if it is false I proceed to MAINAPP activity.
Hope it helps.
public class SplashScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen);
SharedPreferences settings = getSharedPreferences(PREFS_NAME,0);
boolean firstRun = settings.getBoolean("FIRST_RUN", true);
if (firstRun) {
showDialog(INITIAL_DLG);
} else {
startActivity(new Intent(appContext, MAINAPP.class));
}
}
/***
* First entry after YES on Dialog!
*/
protected void initialize() {
messageTV.setVisibility(TextView.VISIBLE);
progressBar.setVisibility(ProgressBar.VISIBLE);
downloadThread = new DownloadFiles();
downloadThread.execute();
}
protected void rollback() {
}
#Override
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder;
switch (id) {
case INITIAL_DLG:
builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.app_setup)
.setCancelable(false)
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
initialize();
}
})
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDlg = builder.create();
return alertDlg;
default:
return null;
}
}
protected class DownloadFiles extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//file download
} catch (Exception e) {
result = false;
}
return true;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
unzipThread = new DecompressZipFile();
unzipThread.execute();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
messageTV.setText("Step 1/4:Downloading data...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
}
protected class DecompressZipFile extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//unzip files
return true;
} catch(Exception e) {
return false;
}
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
if (values[0]<0) progressBar.setMax(values[0]*-1);
else progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
moveDBThread = new MoveDBFile();
moveDBThread.execute();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
messageTV.setText("Step 2/4:Decompressing data...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
}
protected class MoveDBFile extends AsyncTask<String, Integer, Boolean> {
#Override
protected Boolean doInBackground(String... params) {
try {
//moving files
return true;
} catch (Exception e) {
globalE = e;
finish();
return false;
}
}
#Override
protected void onPreExecute() {
messageTV.setText("Step 3/4:Shufflin'...");
progressBar.setProgress(0);
progressBar.setMax(100);
super.onPreExecute();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
progressBar.setProgress(values[0]);
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result) {
getSharedPreferences(PREFS_NAME,0).edit().putBoolean("FIRST_RUN", false).commit();
startActivity(new Intent(appContext, MAINAPP.class));
} else {
rollback();
}
}
}
}

Categories

Resources