Search code examples
androidandroid-asynctaskparse-platformnetworkonmainthread

Android AsyncTask getting NetworkOnMainThreadException when called a second time


I'm getting some data off Parse.com in my app When it first starts up, it checks the cache if available and displays it, then the user can pull-to-refresh to get the latest data When the first refresh action is called, everything works great, but when I try to refresh a second time I get the NetworkOnMainThreadException force close

This is the calling method (I'm using Android support's swipe-to-refresh view)

@Override
public void onRefresh() {
    // this part is merely a check, crashes both with or without this
    if(!runningTask.getClass().equals(AsyncTask.Status.FINISHED))
        runningTask.cancel(true);

    runningTask = new DownloadEvents(true).execute();
}

This is the async task

private class DownloadEvents extends AsyncTask<Void, Void,  ArrayList<Event>> {
    boolean forceDownload;

    String errorString = "";
    public DownloadEvents(boolean forceDownload) {
        this.forceDownload = forceDownload;
        Parse.initialize(getActivity(), #API KEY CENSORED#);
    }

    // Do the long-running work in here
    protected ArrayList<Event> doInBackground(Void... params) {
        List<ParseObject> events = null;
        PreferencesHelper ph = new PreferencesHelper(getActivity());

        ParseQuery<ParseObject> eventsQuery = new ParseQuery<ParseObject>("events");
        try {
            eventsQuery.setCachePolicy(ParseQuery.CachePolicy.CACHE_ONLY);
            events = eventsQuery.find();
        } catch (ParseException e1) {
            e1.printStackTrace();
        }
        if(forceDownload || System.currentTimeMillis() - ph.getLastEventsDownloadTime() > 43200000 || events == null)
        {
            swipeLayout.setRefreshing(true);
            try {
                eventsQuery.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
                events = eventsQuery.find();
                ph.setLastEventsDownloadTime();
            } catch (ParseException e) {
                e.printStackTrace();
            } 
        }

        // creating classes and sorting goes here

        return eventsList;
    }

    @Override
    protected void onPreExecute() { 
        super.onPreExecute(); 
    }

    @Override
    protected void onPostExecute(ArrayList<Event> events) {
        if(events.size() > 0)
        {
            EventsAdapter adapter = new EventsAdapter(getActivity(), R.layout.events_card, events);
            adapter.notifyDataSetChanged();
            getListView().setAdapter(adapter);
        }
        if(errorString != "")
            Toast.makeText(getActivity(), errorString, Toast.LENGTH_SHORT).show();

        swipeLayout.setRefreshing(false);
    }
}

Even if I force the download as the app start, it's always the second pulldown that crashes it, not the second time it downloads something

Please don't suggest turning off the NetworkOnMainThread strict rule, that's not a solution

Edit: here's the logcat

FATAL EXCEPTION: main
Process: com.mdk.test, PID: 24048
android.os.NetworkOnMainThreadException
at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1145)
at com.android.org.conscrypt.OpenSSLSocketImpl.shutdownAndFreeSslNative(OpenSSLSocketImpl.java:1102)
at com.android.org.conscrypt.OpenSSLSocketImpl.close(OpenSSLSocketImpl.java:1097)
at org.apache.http.impl.SocketHttpClientConnection.close(SocketHttpClientConnection.java:205)
at org.apache.http.impl.conn.DefaultClientConnection.close(DefaultClientConnection.java:161)
at org.apache.http.impl.conn.tsccm.AbstractConnPool.closeConnection(AbstractConnPool.java:320)
at org.apache.http.impl.conn.tsccm.ConnPoolByRoute.shutdown(ConnPoolByRoute.java:678)
at org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager.shutdown(ThreadSafeClientConnManager.java:256)
at com.parse.ParseRequest.initialize(ParseRequest.java:118)
at com.parse.Parse.initialize(Parse.java:109)
at com.mdk.test.EventsFragment$DownloadEvents.<init>(EventsFragment.java:136)
at com.mdk.test.EventsFragment.onRefresh(EventsFragment.java:223)
at android.support.v4.widget.SwipeRefreshLayout.startRefresh(SwipeRefreshLayout.java:441)
at android.support.v4.widget.SwipeRefreshLayout.onTouchEvent(SwipeRefreshLayout.java:399)
at android.view.View.dispatchTouchEvent(View.java:8073)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2253)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1987)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2259)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2001)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2198)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1649)
at android.app.Activity.dispatchTouchEvent(Activity.java:2717)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2159)
at android.view.View.dispatchPointerEvent(View.java:8263)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4013)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3892)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3507)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3473)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3583)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3481)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3640)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3507)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3473)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3481)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3454)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5682)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5656)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5627)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5761)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.view.InputEv

Solution

  • Parse.initialize() is in the async task constructor that gets executed in the main thread and it invokes a network operation.

    Move the call to doInBackground().