我有底部导航视图,该视图包含3个片段,分别名为Home,Notifications和Account。在“家庭”片段中,我提出了凌空发布请求,该请求使用用户的最后一个已知位置,并基于此请求从服务器获取响应。我想知道:
当我在截击响应之前在片段之间切换时,我的应用程序崩溃了,而当我在响应完成之后切换时,没有应用程序崩溃。
第一次启动活动时未显示来自服务器的响应,而是当我在片段之间切换并再次返回时显示。
它显示错误日志:
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;
}
}
请让我知道为什么应用崩溃了。
谢谢
答案 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!");
}
}
});