当片段在凌空响应之前发生变化时,应用崩溃

时间:2018-10-10 14:35:25

标签: android android-volley

我有底部导航视图,该视图包含3个片段,分别名为Home,Notifications和Account。在“家庭”片段中,我提出了凌空发布请求,该请求使用用户的最后一个已知位置,并基于此请求从服务器获取响应。我想知道:

  1. 当我在截击响应之前在片段之间切换时,我的应用程序崩溃了,而当我在响应完成之后切换时,没有应用程序崩溃。

  2. 第一次启动活动时未显示来自服务器的响应,而是当我在片段之间切换并再次返回时显示。

它显示错误日志:

 java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
    at android.widget.Toast.<init>(Toast.java:138)
    at android.widget.Toast.makeText(Toast.java:385)
    at tiffino.app.com.Home$1.onResponse(Home.java:245)
    at tiffino.app.com.Home$1.onResponse(Home.java:240)
    at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60)
    at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30)
    at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6776)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)

Home.java

public class Home extends Fragment implements GoogleApiClient.OnConnectionFailedListener,
    GoogleApiClient.ConnectionCallbacks,
    com.google.android.gms.location.LocationListener {

    TextView fragText;
    GoogleApiClient mGoogleApiClient;
    LocationRequest mLocationRequest;
    Location mLocation;
    RequestQueue requestQueue;
    StringRequest stringRequest;
    public static final String TAG = "MyTag";
    private static final String URL = "https://google.com";

    public Home() { }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_home, container, false);

        fragText = view.findViewById(R.id.fragText);

        mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
            .addConnectionCallbacks(this)
            .addOnConnectionFailedListener(this)
            .addApi(LocationServices.API)
            .build();

        return view;
    }


    @Override
    public void onStart() {
        super.onStart();
        mGoogleApiClient.connect();
    }

    @Override
    public void onStop() {
        super.onStop();
        if(mGoogleApiClient.isConnected() && requestQueue != null){
            mGoogleApiClient.disconnect();
            requestQueue.cancelAll(TAG);
        }
    }

    @Override
    public void onConnected(@Nullable Bundle bundle) {
        mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
        if(mLocation != null) {
            String str1 = hereLocation(mLocation.getLatitude(),mLocation.getLongitude());
            fragText.setText(str1);
            sendLocation(str1);
        }
    }

    @Override
    public void onConnectionSuspended(int i) { }

    @Override
    public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { }

    private void sendLocation(final String str1) {
        requestQueue = Volley.newRequestQueue(getContext());
        stringRequest = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Toast.makeText(getActivity(),""+response,Toast.LENGTH_SHORT).show();
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) { }
        }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                HashMap<String,String> map = new HashMap<>();
                map.put("name",str1);
                return map;
            }   
        };
        stringRequest.setTag(TAG);
        requestQueue.add(stringRequest);
    }

    private String hereLocation(double lat, double lon) {
        String city = "";
        Geocoder geo = new Geocoder(getContext(), Locale.getDefault());
        List<Address> addresses;
        try {
            addresses = geo.getFromLocation(lat,lon,10);
            if(addresses.size()>0) {
                for (Address adr: addresses) {
                    if(adr.getLocality()!=null && adr.getLocality().length()>0) {
                        city = adr.getLocality();
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return city;
    }
}

请让我知道为什么应用崩溃了。

谢谢

3 个答案:

答案 0 :(得分:2)

问题可能出在onRespones中的getActivity()上。由于您现在位于另一个片段中,因此该片段现在未附加到getActivity。

您可以这样做:

if(isAdded()) { 
   Toast.makeText(getActivity(),""+response,Toast.LENGTH_SHORT).show();
}

答案 1 :(得分:1)

Activity实现回调侦听器是最正确的方法...因为与此类似,始终可以获取Context-无论哪个Fragment当前显示。

public class MainActivity extends FragmentActivity implements Response.Listener, Response.ErrorListener {

    ...
    @Override
    public void onResponse(String response) {
        if(response != null) {
            Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public void onErrorResponse(VolleyError error) {

    }
}

如此称呼(在Fragment内部):

new StringRequest(Request.Method.GET, url, getActivity());

如果需要,仍然可以将String传递回当前的Fragment

答案 2 :(得分:0)

尽管,您没有提供一段代码。但是总的来说,我可以告诉您,使用某些回调方法创建Web请求时,您应该注意很多事情。 例如,假设您具有以下代码:

RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        mTextView.setText(response);
    }
}, new Response.ErrorListener() {
    @Override
    public void onErrorResponse(VolleyError error) {
        mTextView.setText("That didn't work!");
    }
});
// Set the tag on the request.
stringRequest.setTag(TAG);

// Add the request to the RequestQueue.
queue.add(stringRequest);

这实际上取决于应用程序的逻辑,但是例如,一种选择是在用户离开当前片段时完全取消请求。因此,您可以在片段的onStop()中编写以下代码:

@Override
protected void onStop () {
    super.onStop();
    if (queue!= null) {
        queue.cancelAll(TAG);
    }
}

另一种选择是在尝试进行更改之前检查片段状态,因为调用回调方法时用户可能已经离开了片段:

StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            if (isResumed())
            {
                mTextView.setText(response);
            }
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            if (isResumed())
            {
                mTextView.setText("That didn't work!");
            }
        }
    });
相关问题