Android ViewPager,Fragments和AsyncTask。如何在方向更改时保留AsyncTask的状态?

时间:2012-11-20 22:21:07

标签: android android-asynctask android-fragments android-viewpager android-lifecycle

首先;是的,我到处寻找答案,但没有人遇到过同样的问题。这个问题似乎与此处的另一个问题相同,但绝对不是:)

基本上我想创建的是一个“First-start”活动,它包含4个不同布局的片段。我已经设法自己做了。我还有一个AsyncTask,它可以通过调用远程服务器来帮助其中一个片段检查用户是否存在于数据库中。这也有效。但是,只要我旋转手机和方向改变,就会重新创建FragmentActivity(显然=))。如果我在解雇AsyncTask时执行此操作,它会崩溃或在某些情况下完成用户检查。

所以我的问题是:如果方向发生变化,如何保留AsyncTask的状态? 我已经看到了一些使用回调的基本解决方案,并将AsyncTask作为内部类。由于我的寻呼机适配器的布局以及相同的Fragments类用于创建的所有四个片段,它们在我的情况下不起作用。

非常感谢任何帮助。更感谢示例或解决方案! =)

请参阅下面的(丑陋)代码,让所有这些变为现实。

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

只是澄清一下。到目前为止,这段代码绝不应该看起来很好。但是在我开始工作之后它会发生。

//亚历山大

4 个答案:

答案 0 :(得分:2)

  

如果方向发生变化,如何保留AsyncTask的状态?

AsyncTask由保留的片段(即自身调用setRetainInstance(true)的动态片段)管理。该片段将在配置更改后继续存在。

  

由于我的寻呼机适配器的布局以及相同的Fragments类用于创建的所有四个片段,它们在我的情况下不起作用。

然后为AsyncTask添加第五个片段。它不必参与UI:

if (getSupportFragmentManager().findFragmentByTag(MODEL)==null) {
  model=new ModelFragment();
  getSupportFragmentManager().beginTransaction().add(model, MODEL)
                             .commit();
}

此处,ModelFragment是负责Fragment的{​​{1}}(以及其他任何地方未在内存中保存的活动所需的数据模型的任何部分)。我们只在片段(AsyncTask)下不存在片段时才创建片段。

答案 1 :(得分:1)

使用AsyncTaskLoader保存任务的状态和结果。

答案 2 :(得分:0)

我在这种情况下所做的是使用BroadcastReceiver。我建议您使用AsyncTask来运行后台操作并调用FragmentActivity,然后在{{1}中接收该广播,而不是将Threadcontext.sendBroadcast(...)紧密耦合。 }}

答案 3 :(得分:0)

在目标片段中使用意向服务加LocalBroadcastManager