0

在我旋转屏幕并收到来自 AsyncTask 的回调以更新我对片段的视图之后,我在获取 Activity(Nullpointerexception) 时遇到了麻烦。如果我不改变方向,那么一切都很好(但不是一直,有时会出现这个错误)

我的主要活动:

public class MainActivity extends SherlockFragmentActivity  {


public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.pager_layout);

    fm = getSupportFragmentManager();
    fm.addOnBackStackChangedListener(this);

    session = new SessionManager(getApplicationContext());
    if (session.isAuthorizated()) {

        disableTabs();
        FragmentTransaction ft = fm.beginTransaction();

        if (session.termsAndConditions()) {
            ft.replace(android.R.id.content, new TermsAndConditionsFragment(), "terms-and-conditions").commit();
        } 
        }
    } else {
        enableTabs();

        mTabsAdapter = new TabsAdapter(this, mViewPager);
        mTabsAdapter.addTab(actionBar.newTab().setText("Log in"), LoginFragment.class, null);
        mTabsAdapter.addTab(actionBar.newTab().setText("Calculator"), CalculatorFragment.class, null);

    }
}

那是我的片段:

public class TermsAndConditionsFragment extends SherlockFragment implements OnClickListener, OnTouchListener, OnEditorActionListener, ValueSelectedListener, AsyncUpdateViewsListener {
private static final String TAG = "TermsAndConditionsFragment";

private TermsAndConditionsManager termsAndConditionsM;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    prepareData();
}

public void prepareData() {
    if (getSherlockActivity() == null)
        Log.d(TAG, "Activity is null");
    termsAndConditionsM = new TermsAndConditionsManager(getSherlockActivity().getApplicationContext());
    termsAndConditions = termsAndConditionsM.getTermsAndConditions();
    ...
    // some stuff
    ...
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    rootView = init(inflater, container);
    return rootView;
}

private View init(LayoutInflater inflater, ViewGroup container) {
    rootView = inflater.inflate(R.layout.fragment_terms_and_conditions, container, false);

    //bla bla bla

    return rootView;
}

public void updateTermsAndConditionsView() {
    //update views here
}

@Override
public void onClick(View v) {
    ft = fm.beginTransaction();
    switch (v.getId()) {
        case R.id.etHowMuch:
            d = NumberPaymentsPickerFragment.newInstance(getSherlockActivity(), Integer.valueOf(howMuch.replace("£", "")), 0);
            d.setValueSelectedListener(this);
            d.show(getFragmentManager(), Const.HOW_MUCH);
            break;
  }
}

@Override
public void onValueSelected() {
    Bundle args = new Bundle();

    ...

    ExecuteServerTaskBackground task = new ExecuteServerTaskBackground(getSherlockActivity());
    task.setAsyncUpdateViewsListener(this);
    task.action = ServerAPI.GET_TERMS_AND_CONDITIONS;
    task.args = args;
    task.execute();
}

@Override
public void onUpdateViews() {
    prepareData();
    updateTermsAndConditionsView();
}
}

我的带有回调的 AsyncTask:

public class ExecuteServerTaskBackground extends AsyncTask<Void, Void, Void> {

private static final String TAG = "ExecuteServerTaskBackground";

Activity mActivity;
Context mContext;
private AsyncUpdateViewsListener callback;

public ExecuteServerTaskBackground(Activity activity) {
    this.mActivity = activity;
    this.mContext = activity.getApplicationContext();
}

public void setAsyncUpdateViewsListener(AsyncUpdateViewsListener listener) {
    callback = listener;
}

@Override
protected Void doInBackground(Void... params) {

    ServerAPI server = new ServerAPI(mContext);
    if (!args.isEmpty())
        msg = server.serverRequest(action, args);
    else
        msg = server.serverRequest(action, null);
    return null;
}

@Override
protected void onPostExecute(Void result) {
    super.onPostExecute(result);
    callback.onUpdateViews();
}
}

为什么会这样?如果我改变方向,如何正确获得活动。

编辑: 据我了解,由于 asyctask 和 Activity 之间的引用错误,在方向更改和 asynctask 执行后会出现空指针。重新创建的活动t have this reference that不是为什么当我收到回调时我使用了不再存在的错误活动引用。但是如何保存当前的活动参考?

编辑: 我决定尝试在整个服务过程中实现我的任务,这就是我所做的。活动:

公共类 MainFragment 扩展 Fragment 实现 ServiceExecutorListener,OnClickListener {

private static final String TAG = MainFragment.class.getName();

Button btnSend, btnCheck;
TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialog pd = new ProgressDialog();

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    setRetainInstance(true);
    intent = new Intent(getActivity(), RESTService.class);
    getActivity().startService(intent);
    sConn = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            Log.d(TAG, "MainFragment onServiceConnected");
            service = ((RESTService.MyBinder) binder).getService();
            service.registerListener(MainFragment.this);
            if (service.taskIsDone())
                serviceStatus.setText(service.getResult());
            bound = true;
        }

        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "MainFragment onServiceDisconnected");
            bound = false;
        }

    };
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.main_fragment, container, false);
    serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
    btnSend = (Button) rootView.findViewById(R.id.btnSend);
    btnCheck = (Button) rootView.findViewById(R.id.btnCheck);

    btnSend.setOnClickListener(this);
    btnCheck.setOnClickListener(this);
    return rootView;
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btnSend:
            pd.show(getFragmentManager(), "ProgressDialog");
            service.run(7);
            service.run(2);
            service.run(4);
            break;
        case R.id.btnCheck:
            if (service != null)
                serviceStatus.setText(String.valueOf(service.taskIsDone()) + service.getTasksCount());
            break;
    }
}

@Override
public void onStart() {
    super.onStart();
    Log.d(TAG, "Bind service");
    getActivity().bindService(intent, sConn, 0);
}

@Override
public void onPause() {
    super.onDestroy();
    Log.d(TAG, "onDestroy: Unbind service");
    if (!bound)
        return;
    getActivity().unbindService(sConn);
    service.unregisterListener(this);
    bound = false;
}

@Override
public void onComplete(String result) {
    Log.d(TAG, "Task Completed");
    pd.dismiss();
    serviceStatus.setText(result);
}
}

对话:

public class ProgressDialog extends DialogFragment implements OnClickListener {

final String TAG = ProgressDialog.class.getName();

public Dialog onCreateDialog(Bundle savedInstanceState) {
    setRetainInstance(true);
    AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
            .setTitle("Title!")
            .setPositiveButton(R.string.yes, this)
            .setNegativeButton(R.string.no, this)
            .setNeutralButton(R.string.maybe, this)
            .setCancelable(false)
            .setMessage(R.string.message_text)
            .setOnKeyListener(new OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    return true;
                }
            });
    return adb.create();
}

public void onClick(DialogInterface dialog, int which) {
    int i = 0;
    switch (which) {
        case Dialog.BUTTON_POSITIVE:
            i = R.string.yes;
            break;
        case Dialog.BUTTON_NEGATIVE:
            i = R.string.no;
            break;
        case Dialog.BUTTON_NEUTRAL:
            i = R.string.maybe;
            break;
    }
    if (i > 0)
        Log.d(TAG, "Dialog 2: " + getResources().getString(i));
}

public void onDismiss(DialogInterface dialog) {
    Log.d(TAG, "Dialog 2: onDismiss");
    // Fix to avoid simple dialog dismiss in orientation change
    if ((getDialog() != null) && getRetainInstance())
        getDialog().setDismissMessage(null);

    super.onDestroyView();
}

public void onCancel(DialogInterface dialog) {
    super.onCancel(dialog);
    Log.d(TAG, "Dialog 2: onCancel");
}
}

服务:

public class RESTService extends Service {

final String TAG = RESTService.class.getName();

MyBinder binder = new MyBinder();
ArrayList<ServiceExecutorListener> listeners = new ArrayList<ServiceExecutorListener>();
Handler h = new Handler();
RequestManager mRequest;
ExecutorService es;
Object obj;
int time;
StringBuilder builder;
String result = null;

public void onCreate() {
    super.onCreate();
    Log.d(TAG, "RESTService onCreate");
    es = Executors.newFixedThreadPool(1);
    obj = new Object();
    builder = new StringBuilder();
}

public void run(int time) {
    RunRequest rr = new RunRequest(time);
    es.execute(rr);
}

class RunRequest implements Runnable {

    int time;

    public RunRequest(int time) {
        this.time = time;
        Log.d(TAG, "RunRequest create");
    }

    public void run() {
        Log.d(TAG, "RunRequest start, time = " + time);
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            Log.d(TAG, "RunRequest obj = " + obj.getClass());
        } catch (NullPointerException e) {
            Log.d(TAG, "RunRequest error, null pointer");
        }
        builder.append("result " + time + ", ");
        result = builder.toString();
        sendCallback();
    }
}

private void sendCallback() {
    h.post(new Runnable() {
        @Override
        public void run() {
            for (ServiceExecutorListener listener : listeners)
                listener.onComplete();
        }
    });
}

public boolean taskIsDone() {
    if (result != null)
        return true;
    return false;
}

public String getResult() {
    return result;
}

public void registerListener(ServiceExecutorListener listener) {
    listeners.add(listener);
}

public void unregisterListener(ServiceExecutorListener listener) {
    listeners.remove(listener);
}

public IBinder onBind(Intent intent) {
    Log.d(TAG, "RESTService onBind");
    return binder;
}

public boolean onUnbind(Intent intent) {
    Log.d(TAG, "RESTService onUnbind");
    return true;
}

public class MyBinder extends Binder {
    public RESTService getService() {
        return RESTService.this;
    }
}
}
4

1 回答 1

2

正如您在编辑中提到的那样,电流Activity在方向变化时被破坏并重新创建。

But how can I save current activity reference?

你不应该。以前Activity的不再有效。这不仅会导致NPEs 还会导致内存泄漏,因为 sAsyncTask可能会持有对 old 的引用,甚至Activity可能永远存在。

解决方案是使用Loaders

于 2013-03-28T15:12:28.557 回答