I'm writing an Android App.
In my App I'm calling a map fragment right after an ACTION_IMAGE_CAPTURE intent is dispatched in the MainActivity.
The map fragment snippet is:
public class MapFragment extends Fragment implements OnMapReadyCallback {
.
.
.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
mView = inflater.inflate(R.layout.fragment_map, container, false);
return mView;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMapView = mView.findViewById(R.id.map);
if (mMapView != null) {
mMapView.onCreate(null);
mMapView.onResume();
mMapView.getMapAsync(this);
}
}
.
.
.
#Override
public void onMapReady(GoogleMap googleMap) {
MapsInitializer.initialize(getActivity());
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
}
If I don't dispatch the ACTION_IMAGE_CAPTURE intent the fragment works as planned, however, when dispatching the intent the context in MapsInitializer.initialize(getActivity()) is null
I think I need to better sync the the ACTION_IMAGE_CAPTURE intent completion and the onMapReady method but not sure how.
Any help will be appreciated.
Thanks,
Change to this,
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMapView = mView.findViewById(R.id.map);
//initialize before calling map onCreate
MapsInitializer.initialize(getActivity());
if (mMapView != null) {
//instead of passing null its a good practice to use savedInstanceState
mMapView.onCreate(savedInstanceState);
mMapView.onResume();
mMapView.getMapAsync(this);
}
}
Related
**Re-attached the relevant code
When I run the email app in FragmentB, the activity's 'onStop' is called.
At this time, FragmentA's method in 'onStop' does not work.
※ FragmentA and FragmentB have the same parent Activity
※ No error occurs when the app is terminated in FragmentB.
MainActivity.java
public class MainActivity extends FragmentActivity {
public Fragment fragmentA, fragmentB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (findViewById(R.id.fragment_container) != null) {
if (savedInstanceState != null) {
return;
}
fragmentA = new FragmentA();
fragmentB = new FragmentB();
fragmentA.setArguments(getIntent().getExtras());
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, fragmentA).commit();
}
}
#Override
protected void onStop() {
super.onStop();
((FragmentA) getSupportFragmentManager().findFragmentById(R.id.fragment_container)).saveData();
}
}
FragmentA.java
View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_timer, container, false);
if(isLoadData){ loadData(); }
return view;
}
public void saveData() {
SharedPreferences timerSharedPref = getActivity().getSharedPreferences("timer", Context.MODE_PRIVATE);
//...
SharedPreferences.Editor editor = timerSharedPref.edit();
String json = jsonArray.toString();
editor.putString("jsonString", json);
editor.apply();
}
FragmentB.java
public class FragmentB extends Fragment implements View.OnClickListener {
View view;
CardView cvContactUs;
MainActivity activity;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activity = (MainActivity) getActivity();
}
#Override
public void onDetach() {
super.onDetach();
activity = null;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_b, container, false);
cvContactUs = view.findViewById(R.id.cv_contact_us);
return view;
}
#Override
public void onStart() {
super.onStart();
cvContactUs.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int id = v.getId();
if (id == R.id.cv_contact_us) {
sendEmail(getActivity(), "Ask a question", new String[]{"help_center#gmail.com"});
}
}
public static void sendEmail(Context context, String title, String[] receivers){
Intent email = new Intent(Intent.ACTION_SEND);
email.putExtra(Intent.EXTRA_SUBJECT, title);
email.putExtra(Intent.EXTRA_EMAIL, receivers);
email.setType("message/rfc822");
context.startActivity(email);
}
}
You say you are getting a ClassCastException. The only class cast from the code you posted is
(FragmentA) getSupportFragmentManager().findFragmentById(...)
So check whether findFragmentById might return FragmentB or something else. Maybe you want to
either cast to the common parent activity
check whether the returned value is an instance of FragmentA before casting
You have two Fragments in the stack and a single ID and the findFragmentByID() method returns the last fragment added to the container. very well when the application ends with the FragmentA I believe that you don't have any error because in the onStop() method you are casting with the FragmentA, but if you end with the FragmentB in this case you are casting the FragmentB by the FragmentA which throws the ClassCastException exception. so I suggest you use the findFragmentByTag() method here is an example
When you add fragments:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
* rest of your code
*/
// when you add the Fragment A
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new FragmentA(), "A")
.commit();
// when you add the Fragment A
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new FragmentB(), "B")
.commit();
}
and when you call the onStop() methode:
#Override
protected void onStop() {
super.onStop();
// ((FragmentA) getSupportFragmentManager().findFragmentByTag("A")).save();
// ((FragmentB) getSupportFragmentManager().findFragmentByTag("B")).save();
Fragment f = getSupportFragmentManager().findFragmentByTag("A");
// you check if the fragment is add
if (f != null)
((FragmentA) f).save();
}
I am building an application in which I have a Google Maps Fragment. In my MainActivity onCreate() method, I display this Google Maps Fragment which works fine in all cases except with airplane mode. If I turn airplane mode off while the application is running, my app crushes. I tried to include some Logs to see which methods are called and apparently, the following methods are called in order:
onPause() in MapFragment
onPause() in MainActivity
onCreate() in MainActivity
onResume() in MainActivity
and finally the app crushes in onMapReady(GoogleMap googleMap) in the MapFragment when I call
MapsInitializer.initialize(getActivity());
What I do not understand is how and why these methods are called when airplane mode is turned off and how to prevent the application from crushing.
Here is the stack trace of the error
2020-12-03 05:32:44.070 700-700/com.example.mutapamaps E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.mutapamaps, PID: 700
java.lang.NullPointerException: Context is null
at com.google.android.gms.common.internal.Preconditions.checkNotNull(com.google.android.gms:play-services-basement##17.3.0:11)
at com.google.android.gms.maps.MapsInitializer.initialize(Unknown Source)
at com.example.mutapamaps.Fragments.MapFragment.onMapReady(MapFragment.java:218)
at com.google.android.gms.maps.zzac.zza(Unknown Source)
at com.google.android.gms.maps.internal.zzaq.dispatchTransaction(Unknown Source)
at com.google.android.gms.internal.maps.zzb.onTransact(Unknown Source)
at android.os.Binder.transact(Binder.java:504)
at dt.aZ(:com.google.android.gms.dynamite_mapsdynamite#204516046#20.45.16 (040306-0):2)
at com.google.maps.api.android.lib6.impl.bi.run(:com.google.android.gms.dynamite_mapsdynamite#204516046#20.45.16 (040306-0):1)
at android.os.Handler.handleCallback(Handler.java:836)
at android.os.Handler.dispatchMessage(Handler.java:103)
at android.os.Looper.loop(Looper.java:203)
at android.app.ActivityThread.main(ActivityThread.java:6251)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)
Here is my MainActivity
public class MainActivity extends AppCompatActivity{
public static FragmentManager fragmentManager;
public static final String LOG_TAG = "LOG_TAG";
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(LOG_TAG, "Main activity created");
super.onCreate(savedInstanceState);
// init airplane mode receiver
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
if(isAirplaneModeOn){
Log.i(LOG_TAG, "Airplane mode turned on");// handle Airplane Mode on
} else {
Log.i(LOG_TAG, "Airplane mode turned off");
}
}
};
this.registerReceiver(receiver, intentFilter);
setContentView(R.layout.activity_main);
fragmentManager = getSupportFragmentManager();
displayFragment(new MapFragment());
}
#Override
protected void onPause() {
super.onPause();
Log.i(LOG_TAG, "Main activity paused");
}
#Override
protected void onResume() {
super.onResume();
Log.i(LOG_TAG, "Main activity resumed");
}
public void displayFragment(Fragment fragmentActivity){
// start the transaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentActivity).
addToBackStack(fragmentActivity.getClass().getSimpleName()).commit();
}
}
Here is my MapFragment
public class MapsFragment extends Fragment implements
OnMapReadyCallback {
public MapsFragment() {
// Required empty public constructor
super();
}
#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(#NonNull View view, #Nullable Bundle savedInstanceState) {
FrameLayout map_frame = view.findViewById(R.id.map_frame);
// configure map
MapView mapFragment = view.findViewById(R.id.map_view);
mapFragment.onCreate(savedInstanceState);
mapFragment.onResume();
mapFragment.getMapAsync(this);
View mapView = mapFragment.getRootView();
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
Log.i(LOG_TAG, "MapFragment resumed");
}
#Override
public void onPause() {
super.onPause();
Log.i(LOG_TAG, "Map fragment paused");
}
#Override
public void onMapReady(GoogleMap googleMap) {
Log.i(LOG_TAG, "onMapReadyCalled");
MapsInitializer.initialize(getActivity());
}
}
May you please help me understand what is going on and debug this piece of code.
Thank you in advance.
Change the onViewCreated with this part of code. Hope it helps.
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
FrameLayout map_frame = view.findViewById(R.id.map_frame);
// configure map
MapView mapFragment = view.findViewById(R.id.map_view);
mapFragment.onCreate(savedInstanceState);
mapFragment.onResume();
mapFragment.getMapAsync(this);
View mapView = mapFragment.getRootView();
super.onViewCreated(mapView , savedInstanceState);
}
Replace Your MapsFragment with this.
public class MapsFragment extends Fragment implements
OnMapReadyCallback {
Context context;
public MapsFragment() {
// Required empty public constructor
super();
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
#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(#NonNull View view, #Nullable Bundle savedInstanceState) {
FrameLayout map_frame = view.findViewById(R.id.map_frame);
// configure map
MapView mapFragment = view.findViewById(R.id.map_view);
mapFragment.onCreate(savedInstanceState);
mapFragment.onResume();
mapFragment.getMapAsync(this);
View mapView = mapFragment.getRootView();
super.onViewCreated(view, savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
Log.i(LOG_TAG, "MapFragment resumed");
}
#Override
public void onPause() {
super.onPause();
Log.i(LOG_TAG, "Map fragment paused");
}
#Override
public void onMapReady(GoogleMap googleMap) {
Log.i(LOG_TAG, "onMapReadyCalled");
MapsInitializer.initialize(context);
}
}
I'm trying to get a Toast to appear in a tabbed fragment when an EditText is left empty.
Here is my MainActivity's onCreate:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(this, getSupportFragmentManager());
ViewPager viewPager = findViewById(R.id.view_pager);
viewPager.setAdapter(sectionsPagerAdapter);
TabLayout tabs = findViewById(R.id.tabs);
tabs.setupWithViewPager(viewPager);
}
}
My Tabbed Fragment works fine with this code:
public class SignupFragment extends Fragment {
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_signup, container, false);
}
}
But it doesn't work when creating the Toast like this:
public class SignupFragment extends Fragment {
EditText textFillCheck;
Button submitCheck;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
submitCheck = (Button) submitCheck.findViewById(R.id.signupBtn);
textFillCheck = (EditText) textFillCheck.findViewById(R.id.signupFirstName);
submitCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TextUtils.isEmpty(textFillCheck.getText().toString())) {
Intent intent = new Intent(getActivity(), SignupFragment.class);
startActivity(intent);
Toast.makeText(getActivity(), "Please fill in all fields", Toast.LENGTH_SHORT).show();
}
else{Toast.makeText(getActivity(), textFillCheck.getText().toString(), Toast.LENGTH_LONG).show();
}
}
});
return inflater.inflate(R.layout.fragment_signup, container, false);
}
}
You're not accessing the views of your Fragment's layout so the layout you're returning in onCreateView() doesn't have your logic attached to it. You should set up your Fragment to look something like this:
public class SignupFragment extends Fragment {
EditText textFillCheck;
Button submitCheck;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState){
// Store a reference to your Fragment's inflated layout
View root = inflater.inflate(R.layout.fragment_signup, container, false);
// Use the reference to access your Fragment's views
submitCheck = (Button) root.findViewById(R.id.signupBtn);
textFillCheck = (EditText) root.findViewById(R.id.signupFirstName);
submitCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(TextUtils.isEmpty(textFillCheck.getText().toString())) {
Toast.makeText(getActivity(), "Please fill in all fields", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getActivity(), textFillCheck.getText().toString(), Toast.LENGTH_LONG).show();
}
}
});
// Return the inflated layout
return root;
}
}
I am amazed why your code is not having any error like VIEW DOES NOT EXIST or NULL POINTER EXCEPTION because
First, you change the activity before showing the Toast secondly you are inflating the layout after the initialization of views and not getting the context properly, Right way of doing what you are trying to achieve is using OnViewCreated() like this
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
submitCheck = (Button) view.findViewById(R.id.signupBtn);
textFillCheck = (EditText) view.findViewById(R.id.signupFirstName);
submitCheck.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (TextUtils.isEmpty(textFillCheck.getText().toString())) {
Toast.makeText(getActivity(), "Please fill in all fields",
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getActivity(), SignupFragment.class);
startActivity(intent);
}
else{
Toast.makeText(getActivity(), textFillCheck.getText().toString(),
Toast.LENGTH_LONG).show();
}
}
});
}
When I try to call an intent in a fragment, I get "Cannot resolve method getIntent()".
Here is my code
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.activity_browse_product,null);
if(getIntent().getBooleanExtra("Exit me", false)){
finish();
return; // add this to prevent from doing unnecessary stuffs
}
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarBrowse);
setSupportActionBar(toolbar);
spnCategory = (Spinner)findViewById(R.id.spinnerCategory);
spnCategory.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener(){
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
}
public void onNothingSelected(AdapterView<?> adapterView) {
return;
}
});
You use
getActivity().getIntent()
instead of
getIntent()
Bundle bundle=getArgument();
if you have passed bundle in intent.
I have made a MapFragment which basically is GoogleMaps. This Fragment is called in an activity, through the fragmentManager and fragment transaction. I would like to tweak my Map now to add some markers and dynamic zoom aswell. I am a bit struggling with this at the moment. Maybe some of you can take a look and help out.
MapsActivity.java
public class MapsActivity extends Activity {
Context context;
Button showMap;
Button showMyLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
context = this;
showMap = (Button)findViewById(R.id.showMap);
showMap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
MapFragment mf = new MapFragment();
MapFragment.googleMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble("2.900000"), Double.parseDouble("1.55555")))
.title("oh yeah"));
ft.add(R.id.maps_layout, mf);
ft.commit();
}
});
showMyLocation = (Button)findViewById(R.id.showMyLocation);
showMyLocation.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
MapFragment.java
public class MapFragment extends Fragment {
public static GoogleMap googleMap;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.map_fragment_layout, container, false);
return v;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
googleMap = ((com.google.android.gms.maps.MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();
}
}
After updating to the code above it gives me this error in the stacktrace :
java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.android.gms.maps.model.Marker com.google.android.gms.maps.GoogleMap.addMarker(com.google.android.gms.maps.model.MarkerOptions)' on a null object reference
at com.example.dell.exampleapplication.MapsActivity$1.onClick(MapsActivity.java:42)
at android.view.View.performClick(View.java:5156)
at android.view.View$PerformClick.run(View.java:20755)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5834)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)
This may provide extra information for help.
Thanks for you help.
ok here is how i use it:
public class Mapfrag2 extends Fragment{
public static GoogleMap map;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.map_fragment_layout, container, false);}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
map = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();
if (savedInstanceState == null) {
map.setMyLocationEnabled(true);
CameraUpdate center = CameraUpdateFactory.newLatLng(new LatLng(30.76793169992044, 1.98180484771729));//moving the map to defined position
CameraUpdate zoom = CameraUpdateFactory.zoomTo(5);
map.moveCamera(center);
markerPoints = new ArrayList<LatLng>();
map.animateCamera(zoom);
map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker marker) {
//doing something when pressing marker's bubble
}
});
}
}
}
in your activity just call
MapFrag2.map
example
adding markers from activity
Mapfrag2.map.addMarker(new MarkerOptions().position(
new LatLng(Double.parseDouble(lat), Double.parseDouble(lon)))
.title(title).snippet(snippet));
clearing the map
Mapfrag2.map.clear();
Edit 2
try to change this part of code
public void onClick(View v) {
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
MapFragment mf = new MapFragment();
MapFragment.googleMap.addMarker(new MarkerOptions().position(new LatLng(Double.parseDouble("2.900000"), Double.parseDouble("1.55555")))
.title("oh yeah"));//move this to the end
ft.add(R.id.maps_layout, mf);
ft.commit();
//here you add your marker
}
I found a solution very easy. I just followed the steps in this wiki page (http://www.techotopia.com/index.php/Working_with_the_Google_Maps_Android_API_in_Android_Studio). It basically explains everything to you.
Simple tip: make your MapActivity extend FragmentActivity !