Issue
To begin with; Yes, I've searched for an answer to this everywhere, but no one have had the same problem that i have. This question might seem to be the same as another question on here, but it's most definitely not :)
Basically what i want to create is a "First-start" activity that consists of 4 fragments with different layouts. This I've managed to do myself. I also have an AsyncTask that will help one of the fragments with a call to a remote server to check if a user exists in a database. This also works. BUT, as soon as I rotate the phone and orientation changes the FragmentActivity is recreated (obviously =)). If i do this when I've fired the AsyncTask, it either crashes or in some cases finishes it's user check.
So my question is: How do I preserve the state of the AsyncTask if orientation changes? I've seen some basic solutions using callbacks and to place the AsyncTask as an inner-class. They don't work in my case due to the layout of my pager adapter and the fact that the same Fragments class is used for all four fragments that's created.
Any help is much appreciated. Examples or solutions are even more appreciated! =)
See below for the (ugly) code that makes all of this come to life.
FirstRunActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.iqqn.***.R;
import com.viewpagerindicator.IconPageIndicator;
import com.viewpagerindicator.PageIndicator;
public class FirstRunActivity extends SherlockFragmentActivity {
private FragmentAdapter mAdapter;
private ViewPager mPager;
private PageIndicator mIndicator;
private boolean userExit = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.first_run);
mAdapter = new FragmentAdapter(getSupportFragmentManager());
mPager = (ViewPager)findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mIndicator = (IconPageIndicator)findViewById(R.id.indicator);
mIndicator.setViewPager(mPager);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getSupportMenuInflater();
inflater.inflate(R.menu.first_run, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_exit:
userExit = true;
this.finish();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
};
@Override
public void finish() {
// Prepare data intent
Intent data = new Intent();
if(userExit) {
data.putExtra("exit", true);
setResult(RESULT_CANCELED, data);
} else {
data.putExtra("signedIn", true);
data.putExtra("registered", true);
data.putExtra("acceptedEULA", true);
// Activity finished ok, return the data
setResult(RESULT_OK, data);
}
super.finish();
}
}
FragmentAdapter.java
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.iqqn.***.R;
import com.viewpagerindicator.IconPagerAdapter;
class FragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
protected static final int[] CONTENT = new int[] { R.layout.***_welcome_1, R.layout.***_welcome_2, R.layout.***_welcome_3, R.layout.***_welcome_4};
protected static final String[] CONTENTTITLE = new String[] { "Welcome","Account","Intro","Let's start!" };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
R.drawable.perm_group_location
};
private int mCount = CONTENT.length;
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return Fragments.newInstance(CONTENT[position % CONTENT.length],position);
}
@Override
public int getCount() {
return mCount;
}
@Override
public CharSequence getPageTitle(int position) {
return FragmentAdapter.CONTENTTITLE[position % CONTENT.length];
}
@Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
Fragments.java
public final class Fragments extends SherlockFragment {
private static final String KEY_CONTENT = "Fragments:Content";
private int position = -1;
private RegisterAsyncTaskHelper registerTask = null;
public static Fragments newInstance(int content, int position) {
Fragments fragment = new Fragments();
fragment.mContent = content;
fragment.position = position;
return fragment;
}
private int mContent = -1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getInt(KEY_CONTENT);
}
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onDestroy() {
if (registerTask != null) {
registerTask.cancel(false);
}
super.onDestroy();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(mContent, container, false);
switch(position) {
case 0:
break;
case 1:
final Button btnRegister;
final Button btnLinkToLogin;
btnRegister = (Button) view.findViewById(R.id.btnRegister);
btnLinkToLogin = (Button) view.findViewById(R.id.btnLinkToLoginScreen);
// Register Button Click event
btnRegister.setOnClickListener(new View.OnClickListener() {
public void onClick(View localview) {
// Execute register task
registerTask = new RegisterAsyncTaskHelper(getActivity(), view);
if(registerTask != null)
registerTask.execute();
}
});
// Link to Login Screen
btnLinkToLogin.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
// TODO Login
}
});
break;
case 2:
break;
case 3:
break;
default:
break;
}
return view;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_CONTENT, mContent);
}
}
RegisterAsyncTaskHelper.java
import org.json.JSONException;
import org.json.JSONObject;
import android.os.AsyncTask;
import android.support.v4.app.FragmentActivity;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.iqqn.***.R;
import com.iqqn.***.utils.DatabaseHandler;
import com.iqqn.***.utils.UserFunctions;
public class RegisterAsyncTaskHelper extends AsyncTask<Void, Integer, Void> {
// JSON Response node names
private static final String KEY_SUCCESS = "success";
private static final String KEY_ERROR = "error";
private static final String KEY_ERROR_MSG = "error_msg";
private static final String KEY_UID = "uid";
private static final String KEY_NAME = "name";
private static final String KEY_EMAIL = "email";
private static final String KEY_CREATED_AT = "created_at";
private View view = null;
private FragmentActivity activity = null;
private ProgressBar mProgress;
public RegisterAsyncTaskHelper(FragmentActivity activity, View view) {
this.view = view;
this.activity = activity;
this.mProgress = (ProgressBar) view.findViewById(R.id.registerProgress);
}
@Override
protected void onPreExecute() {
mProgress.setVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(Void... params) {
final EditText inputFullName;
final EditText inputEmail;
final EditText inputPassword;
final TextView registerErrorMsg;
// Importing all assets like buttons, text fields
inputFullName = (EditText) view.findViewById(R.id.registerName);
inputEmail = (EditText) view.findViewById(R.id.registerEmail);
inputPassword = (EditText) view.findViewById(R.id.registerPassword);
registerErrorMsg = (TextView) view.findViewById(R.id.register_error);
String name = inputFullName.getText().toString();
String email = inputEmail.getText().toString();
String password = inputPassword.getText().toString();
UserFunctions userFunction = new UserFunctions();
JSONObject json = userFunction.registerUser(name, email, password);
// check for login response
try {
if (json.getString(KEY_SUCCESS) != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
registerErrorMsg.setText("");
}
});
String res = json.getString(KEY_SUCCESS);
if(Integer.parseInt(res) == 1){
// user successfully registred
// Store user details in SQLite Database
DatabaseHandler db = new DatabaseHandler(activity.getApplicationContext());
JSONObject json_user = json.getJSONObject("user");
// Clear all previous data in database
userFunction.logoutUser(activity.getApplicationContext());
db.addUser(json_user.getString(KEY_NAME), json_user.getString(KEY_EMAIL), json.getString(KEY_UID), json_user.getString(KEY_CREATED_AT));
/*
// Launch Dashboard Screen
Intent dashboard = new Intent(ctx, DashboardActivity.class);
// Close all views before launching Dashboard
dashboard.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(dashboard);
// Close Registration Screen
finish();
*/
}else{
// Error in registration
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
registerErrorMsg.setText("Error occured in registration");
}
});
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(final Integer... values) {
}
@Override
protected void onPostExecute(final Void result) {
mProgress.setVisibility(View.GONE);
}
}
Just to clarify. This code is in no way supposed to look good as of now. But it will after i get this working.
// Alexander
Solution
How do I preserve the state of the AsyncTask if orientation changes?
Have the AsyncTask
be managed by a retained fragment (i.e., a dynamic fragment that calls setRetainInstance(true)
on itself). That fragment will survive the configuration change.
They don't work in my case due to the layout of my pager adapter and the fact that the same Fragments class is used for all four fragments that's created.
Then add a fifth fragment for the AsyncTask
. It does not have to participate in the UI:
if (getSupportFragmentManager().findFragmentByTag(MODEL)==null) {
model=new ModelFragment();
getSupportFragmentManager().beginTransaction().add(model, MODEL)
.commit();
}
Here, ModelFragment
is the Fragment
responsible for the AsyncTask
(and any portion of the data model needed by the activity not held in memory anywhere else). We only create the fragment if it does not already exist under its tag (MODEL
).
Answered By - CommonsWare
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.