Okhttp3 在请求加载之前关闭 activity 使应用程序崩溃

Okhttp3 making app crash on closing the activity before the request loads

一切正常。但是我正在加载问题片段并立即单击返回并退出应用程序而不让请求完成。它使应用程序崩溃。我试着环顾四周,但找不到可以帮助我防止崩溃的修复程序。我附上 logcatQuestions class 以供参考。

logcat

12-11 15:37:44.898 16772-16835/com.aftertutor.app E/AndroidRuntime: FATAL EXCEPTION: OkHttp Dispatcher
                                                                    Process: com.aftertutor.app, PID: 16772
                                                                    java.lang.NullPointerException
                                                                        at com.aftertutor.app.Question.onResponse(Question.java:112)
                                                                        at okhttp3.RealCall$AsyncCall.execute(RealCall.java:153)
                                                                        at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
                                                                        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                                                                        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                                                                        at java.lang.Thread.run(Thread.java:841)

问题Class

package com.aftertutor.app;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.aftertutor.app.model.API;
import com.dpizarro.autolabel.library.AutoLabelUI;
import com.dpizarro.autolabel.library.AutoLabelUISettings;
import com.github.thunder413.datetimeutils.DateTimeStyle;
import com.github.thunder413.datetimeutils.DateTimeUtils;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.Date;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


public class Question extends Fragment {

    public String id;
    public TextView title;
    public TextView desc;
    public TextView date;
    public TextView edit;
    public TextView report;
    public TextView username;
    public AutoLabelUI tags;
    public CardView cardView;
    public ProgressBar progressBar;
    public TextView votes;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_question, null);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        // Equivalent to on Create
        super.onViewCreated(view, savedInstanceState);

        getActivity().setTitle("Loading...");

        title = view.findViewById(R.id.ques_title);
        desc = view.findViewById(R.id.ques_desc);
        date = view.findViewById(R.id.ques_time);
        edit = view.findViewById(R.id.ques_edit);
        report = view.findViewById(R.id.ques_report);
        username = view.findViewById(R.id.ques_username);
        tags = view.findViewById(R.id.ques_labels);
        cardView = view.findViewById(R.id.ques_card);
        progressBar = view.findViewById(R.id.ques_progress);
        votes = view.findViewById(R.id.ques_votes);

        Bundle arg = getArguments();
        if (arg != null && arg.containsKey("id")) {
            id = arg.getString("id");
        }

        loadQuestion(id);

    }

    public void loadQuestion(String qid) {
        final API api = new API();
        OkHttpClient client = new OkHttpClient();

        RequestBody body = new FormBody.Builder()
                .add("qid", qid)
                .build();

        Request request = api.call("get_question", body, getContext(), getActivity());

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                call.cancel();
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        MaterialDialog dialog = api.prepareDialog(getContext(), "An Error Occoured", "An Error Occoured. Please make sure you are connected to the internet and try again. If the issue still persists please contact support.");
                        dialog.show();
                    }
                });
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                final String responseText = response.body().string();
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        try {

                            JSONObject jsonObject = new JSONObject(responseText);

                            if (jsonObject.get("status").equals("ok"))
                            {
                                JSONObject payload = jsonObject.getJSONObject("payload");
                                JSONObject questionItem = payload.getJSONObject("question");

                                title.setText(questionItem.get("title").toString());
                                getActivity().setTitle(questionItem.get("title").toString());
                                desc.setText(questionItem.get("description").toString());
                                date.setText(DateTimeUtils.getTimeAgo(getContext(), new Date(questionItem.getInt("postedOn") * 1000L), DateTimeStyle.AGO_FULL_STRING));
                                votes.setText(questionItem.getInt("votes") + "");
                                username.setText("@" + questionItem.get("postedBy").toString());
                                String[] taggs = api.toStringArray(questionItem.getJSONArray("tags"));

                                edit.setOnClickListener(new View.OnClickListener() {
                                    @Override
                                    public void onClick(View v) {
                                        // Edit Page here
                                    }
                                });

                                report.setOnClickListener(new View.OnClickListener() {
                                    @Override
                                    public void onClick(View v) {
                                        MaterialDialog dialog = new MaterialDialog.Builder(getContext())
                                                .title("Report this question because...")
                                                .items(R.array.report_array)
                                                .itemsCallbackSingleChoice(0, new MaterialDialog.ListCallbackSingleChoice() {
                                                    @Override
                                                    public boolean onSelection(MaterialDialog dialog, View itemView, int which, CharSequence text) {
                                                        Toast.makeText(getContext(), "YOU SELECTED: " + which, Toast.LENGTH_SHORT).show();
                                                        return false;
                                                    }
                                                })
                                                .content("Reporting will let us know that something isn't wrong with this post. We will take action asap.")
                                                .positiveText("Report")
                                                .onPositive(new MaterialDialog.SingleButtonCallback() {
                                                    @Override
                                                    public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                                                        Toast.makeText(getContext(), "Reported", Toast.LENGTH_SHORT).show();
                                                    }
                                                })
                                                .negativeText("Cancel")
                                                .build();
                                        dialog.show();
                                    }
                                });

                                AutoLabelUISettings autoLabelUISettings = new AutoLabelUISettings.Builder()
                                        .withMaxLabels(5)
                                        .withShowCross(false)
                                        .withLabelsClickables(false)
                                        .withBackgroundResource(R.drawable.rounded_corner)
                                        .withTextSize(R.dimen.custom_label_font_size)
                                        .withLabelPadding(R.dimen.custom_label_font_padding)
                                        .build();
                                tags.setSettings(autoLabelUISettings);
                                tags.clear();

                                for (String tag: taggs) {
                                    tags.addLabel(tag);
                                }
                                progressBar.setVisibility(View.GONE);
                                cardView.setVisibility(View.VISIBLE);

                            }
                            else if (jsonObject.get("status").equals("error"))
                            {
                                MaterialDialog dialog = api.prepareDialog(getContext(), jsonObject.getJSONObject("dialog").get("title").toString(), jsonObject.getJSONObject("dialog").get("message").toString());
                                dialog.show();
                            }
                            else
                            {
                                MaterialDialog dialog = api.prepareDialog(getContext(), "An Error Occurred", "An Error Occurred. Please make sure you are connected to the internet and try again. If the issue still persists please contact support.");
                                dialog.show();
                            }

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                });

            }
        });

    }

}

您必须在 onPause() 中取消通话,因此请将您的通话作为以下字段:

private Call call;

然后将您的 loadQuestion() 方法更改为:

call = client.newCall(request);
call.enqueue(new Callback() {

并取消请求:

@Override
public void onPause() {
    super.onPause();
    if (call != null){
        call.cancel();
    }
}

由于您确定如果 Fragment 暂停,请求的响应会使应用程序崩溃 (Exception),那么您也可以在 class 中声明一个 boolean喜欢:

private boolean active= true;

然后在你的 onResume:

@Override
public void onResume() {
  super.onResume();
  active= true;

}

然后在你的 onPause

@Override
public void onPause() {
  super.onPause();
  active= false;

}

然后在你的 Fragment 的调用中 onResponse 添加一个 if 语句:

@Override
public void onResponse(Call call, Response response) throws IOException {
    if(active){
     //Call your extra code here!
   }
}