Hello I´m making a map app that is inside a drawer activity in Android Studio, everything was going well untill I started to play with fragments since I'm pretty new in android I don't really know whats going on or what is the cause of the issue.
I replaced the main layout with the map layout making it my "home" layout. Then I added a fragment where I can change the language of the app called "Configuration" and I call that fragment when the "Configuration" button is pressed at the drawer menu.
I've noticed that even though the Configuration fragment replaces the map layout some location methods from the map fragment are still active in the background, I know this because a Toast message is displayed everytime the app checks for permission or changes location I did this as a visual aid so I know its working.
There are 2 scenarios where my app crashes for the same error at the same line of code and it happens to be one of the toasts I put there as aid. It is weird for me because all the other toast are working fine since the message is being displayed but when it gets to that specific toast at the onLocationChanged method the next error its displayed:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.widget.Toast.<init>(Toast.java:114)
at android.widget.Toast.makeText(Toast.java:277)
at android.widget.Toast.makeText(Toast.java:267)
at com.tesseract.psiclops.zerov2.mapFragment.onLocationChanged(mapFragment.java:172)
at com.google.android.gms.internal.location.zzay.notifyListener(Unknown Source:4)
at com.google.android.gms.common.api.internal.ListenerHolder.notifyListenerInternal(Unknown Source:8)
at com.google.android.gms.common.api.internal.ListenerHolder$zza.handleMessage(Unknown Source:16)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
So the 2 things that trigger the error are:
1.- When I press the back button and there is no fragment in the backstack (I suppose) so it hides (closes? minimizes?) the app then I open it again...it crashes.
2.- When I go into my configuration fragment and change language. Note: The method I use to change language restarts the activity so the change in language is shown.
I figured that since I'm closing the app both pressing the back button or calling my languaje method it makes sense that getcontext() becomes null after this but why are the other toasts showing the message and only crashing at that specific line? or specific method? and how can I prevent this??
NOTE: When I comment out the toast everything works fine, no crashing or anything :S, I really need to understand whats going on so I can prevent any issues later.
MapFragment:
public class mapFragment extends Fragment implements OnMapReadyCallback, LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private GoogleMap mMap;
private GoogleApiClient mApiClient;
private Context mContext;
private OnFragmentInteractionListener mListener;
public mapFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_map, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment)getChildFragmentManager()
.findFragmentById(R.id.map1);
mapFragment.getMapAsync(this);
}
private void SetSancrisM(final GoogleMap mMap) {
// Add a marker in Sancris and move the camera
// LatLng sancris = new LatLng(16.736380, -92.638795);
LatLngBounds SanCris = new LatLngBounds(new LatLng(16.720215, -92.684189), new LatLng(16.749950, -92.596649));
//mMap.addMarker(new MarkerOptions().position(sancris).title("Marker in Sancris"));
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SanCris.getCenter(), 16));
//mMap.setLatLngBoundsForCameraTarget(SanCris);
}
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
try {
// Customise the styling of the base map using a JSON object defined
// in a raw resource file.
boolean success = googleMap.setMapStyle(
MapStyleOptions.loadRawResourceStyle(getContext(), R.raw.style_json));
if (!success) {
Toast.makeText(mContext, "Chido3", Toast.LENGTH_SHORT).show();
}
} catch (Resources.NotFoundException e) {
Toast.makeText(mContext, "No cargó el styla", Toast.LENGTH_SHORT).show();
}
//Calls the function that moves the cam to Sancris
SetSancrisM(mMap);
//Location permission conditions
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(mContext, "Failed to get location permission", Toast.LENGTH_SHORT).show();
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 200);
return;
} else {
if (!mMap.isMyLocationEnabled()) {
mMap.setMyLocationEnabled(true);
Toast.makeText(mContext, "Chido", Toast.LENGTH_SHORT).show();
}
}
mApiClient = new GoogleApiClient.Builder(getContext())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mApiClient.connect();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 200: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(mContext, "Failed to get permission 2", Toast.LENGTH_SHORT).show();
} else {
mMap.setMyLocationEnabled(true);
Toast.makeText(mContext, "Chido2", Toast.LENGTH_SHORT).show();
}
}
}
}
}
@Override
public void onLocationChanged(Location location) {
if(location==null){
Toast.makeText(mContext, "No Location 4", Toast.LENGTH_SHORT).show();
}else{
LatLng ll= new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate update= CameraUpdateFactory.newLatLngZoom(ll,mMap.getCameraPosition().zoom);
mMap.animateCamera(update);
Toast.makeText(mContext, "Chido4", Toast.LENGTH_SHORT).show(); //This one right here is the one not working
}
}
LocationRequest mLocReq;
@Override
public void onConnected(@Nullable Bundle bundle) {
mLocReq = LocationRequest.create();
mLocReq.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocReq.setInterval(1000);
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(getActivity(), new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 200);
return;
}
LocationServices.FusedLocationApi.requestLocationUpdates(mApiClient, mLocReq, this);
Toast.makeText(mContext, "Chido5", Toast.LENGTH_SHORT).show();
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
//Este código tiene que ver con la comunicación entre fragmentos y actividades, osea déjalo para después
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
mContext=context;
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
The toast that's not working its inside the onLocationChanged method
@Override
public void onLocationChanged(Location location) {
if(location==null){
Toast.makeText(getContext(), "No Location 4", Toast.LENGTH_SHORT).show();
}else{
LatLng ll= new LatLng(location.getLatitude(), location.getLongitude());
CameraUpdate update= CameraUpdateFactory.newLatLngZoom(ll,mMap.getCameraPosition().zoom);
mMap.animateCamera(update);
Toast.makeText(getContext(), "Good4", Toast.LENGTH_SHORT).show(); //This one right here is the one not working
}
}
All other toasts inside the mapfragment methods are working fine.
If you need more code please ask me here and I'll add it for you. Thank you very much in advance!!