Android:通过服务执行http请求

时间:2013-03-28 14:12:02

标签: android android-activity

在我有旋转屏幕并收到来自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之后出现了正确的nullpointer。重新创建的活动没有t have this reference that为什么当我收到回调时,我使用的错误活动参考不再存在。但是如何保存当前的活动参考?

修改 我决定尝试在整个服务中实现我的任务,这就是我所做的。 活性:

public class MainFragment extends 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;
    }
}
}

1 个答案:

答案 0 :(得分:2)

正如您在编辑中提到的那样,当前的Activity会被销毁并在方向更改时重新创建。

But how can I save current activity reference?

你不应该。之前的Activity不再有效。这不仅会导致NPE,还会导致内存泄漏,因为AsyncTask可能会保留对旧Activity的引用,可能永远存在。

解决方案是使用Loaders