I am using a Google Maps fragment with a MapView that starts by getting user location and setting a marker with it. But i noticed a lag when user scrolls the map, it's like a frame drop.
I searched for some reasons, but i guess it depends on my code. Something seems wrong, but i don't know what yet.
Here's the code:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setFragment(new MapFragment());
}
protected void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
MapFragment.java
GoogleMap mGoogleMap;
MapView mMapView;
View mView;
LocationManager mLocationManager;
Location mUserLocation;
private final String TAG_PARSING_STYLE_FAILURE = "ERROR PARSING JSON";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationManager = (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
}
#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, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mMapView = (MapView) mView.findViewById(R.id.testMapView);
if( mMapView != null){
mMapView.onCreate(null);
mMapView.onResume();
mMapView.getMapAsync(this);
}
}
#Override
public void onMapReady(GoogleMap googleMap) {
MapsInitializer.initialize(getContext());
mGoogleMap = googleMap;
mGoogleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
mUserLocation = getUserLocation();
LatLng latLng = new LatLng(mUserLocation.getLatitude(), mUserLocation.getLongitude());
MarkerOptions marker = new MarkerOptions();
marker.position(latLng);
marker.title("My Location");
mGoogleMap.addMarker(marker);
CameraPosition cameraPosition = CameraPosition.builder().target(latLng).zoom(17).build();
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
public Location getUserLocation(){
Location loc = null;
try {
loc = mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
} catch (SecurityException ex) {
Log.e("ERROR - LOCATION", ex.toString());
}
return loc;
}
Is there a better approach when using MapFragments?
Related
My shake detector is not working in fragment. But worked in activity. what is the reason for this, what should i do.How can ı solve.
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
unbinder = ButterKnife.bind(this, view);
presenter.takeView(this);
Log.d(TAG, "onViewCreated: " + this);
presenter.initListener();
initUI();
SensorManager sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
ShakeDetector sd = new ShakeDetector(this);
sd.start(sensorManager);
}
My shake detectror code;
#Override
public void hearShake() {
int position= listDataAdapter.getPosition();
listDataAdapter.removeItem(position);
UserItemPojo item = listDataAdapter.removeItem(position);
if (item != null)
sub_main_presenter.doLike(item);
presenter.isEmpty();
if (userList.isEmpty())
homePresenter.stopPlayer();
Toast.makeText(getContext(),"shakeDetector is working", Toast.LENGTH_LONG).show();
}
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);
}
}
I will ultimately need to send information from InteractionFragment to DisplayFragment. To my understanding, this needs to go through the container activity first, so I'm trying to send from InteractionFragment to MainActivity.
public class MainActivity extends AppCompatActivity {
Fragment fragmentInteraction, fragmentHistory, fragmentDisplay;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FragmentManager fm = getSupportFragmentManager();
fragmentInteraction = fm.findFragmentById(R.id.upper_container);
if (fragmentInteraction == null) {
fragmentInteraction = new InteractionFragment();
fm.beginTransaction()
.add(R.id.upper_container, fragmentInteraction)
.commit();
}
fragmentDisplay = fm.findFragmentById(R.id.lower_container);
if (fragmentDisplay == null) {
fragmentDisplay = new DisplayFragment();
fm.beginTransaction()
.add(R.id.lower_container, fragmentDisplay)
.commit();
}
public void onStart() {
super.onStart();
Intent intent = getIntent();
String intentContents = intent.getStringExtra("editTextString");
}
}
public class InteractionFragment extends Fragment implements View.OnClickListener {
Button buttonScramble, buttonHistory;
EditText mEditText;
Activity context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Inflate the layout for this fragment
context = getActivity();
View v = inflater.inflate(R.layout.fragment_interaction, parent, false);
return v;
}
public void onStart() {
super.onStart();
buttonScramble = (Button) getActivity().findViewById(R.id.buttonScramble);
buttonScramble.setOnClickListener(this);
buttonHistory = (Button) getActivity().findViewById(R.id.buttonHistory);
buttonHistory.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.buttonScramble:
//set x to number of letters in word
break;
case R.id.buttonHistory:
//call other fragment
break;
default:
break;
}
//use this to send user input to display fragment
//display fragment will use this info to shuffle letters
mEditText = (EditText) getActivity().findViewById(R.id.edit_text_display);
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("editTextString", mEditText.getText().toString());
startActivity(intent);
}
intentContents returns null and no other solutions I've found for similar problems are working for me. Any suggestions would be greatly appreciated! Thanks!
Did you try using OnFragmentInteractionListener?
This answer: How to implement OnFragmentInteractionListener might help.
I'm making a simple app that adds a location to the list fragment in main page, and as I add more addresses to the list, whenever configuration changes, those addresses are carried over, which is expected.
However as you will see below, the empty list text shows up for some reason, and seems like when I add another new address hereafter, it will add to the very first place of the list.
Below is my main activity :
public class MainActivity extends AppCompatActivity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
private GoogleApiClient mGoogleApiClient;
private Location mLastLocation, mCurrentLocation;
private double currentLatitude, currentLongitude;
private String lastUpdateTime, addressMessage = null;
private AddressResultReceiver resultReceiver;
private MainList listFragment = new MainList();
//private boolean mRequestStatus = true;
private MaterialDialog dialog;
public boolean mAddressRequested = false;
private FragmentManager mFragmentManager;
private final String FRAGMENT_TAG = "main_list_tag";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
mFragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
fragmentTransaction.add(R.id.list_frame, listFragment);
fragmentTransaction.commit();
dialog = new MaterialDialog(this)
.setTitle("Select an address")
.setPositiveButton("SELECT", new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
listFragment.list.add(addressMessage);
listFragment.mAdapter.notifyDataSetChanged();
}
})
.setNegativeButton("CANCEL", new View.OnClickListener() {
#Override
public void onClick(View v) {
dialog.dismiss();
}
});
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
setSupportActionBar(toolbar);
FloatingActionButton floatingActionButton = (FloatingActionButton) findViewById(R.id.fab_button);
//LayoutInflater inflater = LayoutInflater.from(getApplicationContext());
floatingActionButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (checkAirPlaneMode(getApplicationContext())) {
Toast.makeText(getApplicationContext(), "Air Plane Mode is ON, Please turn off to get location", Toast.LENGTH_LONG).show();
}
else if (!checkNetwork()) {
Toast.makeText(getApplicationContext(),"Unable to reach network, please check network settings",Toast.LENGTH_LONG).show();
}
else if (!checkLocationSettings(getApplicationContext())) {
showLocationSettings();
}
else {
startAddressLookUp();
mAddressRequested = true;
dialog.setMessage(addressMessage);
dialog.show();
}
}
});
}
#Override
public void onStart() {
super.onStart();
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addOnConnectionFailedListener(this)
.addConnectionCallbacks(this)
.build();
}
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
super.onPause();
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
}
#Override
public void onResume() {
super.onResume();
if(mGoogleApiClient.isConnected()) {
LocationRequest locationRequest = createLocationRequest();
startLocationUpdates(locationRequest);
}
}
And list fragment class:
public class MainList extends ListFragment implements AdapterView.OnItemClickListener {
private int stateInt;
private final String FRAGMENT_KEY = "saved_fragment";
ArrayList<String> list = new ArrayList<>();
ArrayAdapter<String> mAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.list_fragment, container, false);
/*ListView view = (ListView) v.findViewById(android.R.id.list);
view.setEmptyView(v.findViewById(android.R.id.empty));
return view;*/
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, list);
setListAdapter(mAdapter);
//mAdapter.notifyDataSetChanged();
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(parent.getContext(), "Item Pressed!", Toast.LENGTH_LONG).show();
}
}
How can avoid this? Am I missing the save application state or something else? Any help would be appreciated! Thanks in advance!
Thanks,
Paul
The onCreate method is called for every orientation change. And in the method you are adding the fragment again. That is why you get this behavior.
Check this for the correct way to do this.
Handling Configuration Changes with Fragments
FragmentManager fm = getFragmentManager();
mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);
// If the Fragment is non-null, then it is currently being
// retained across a configuration change.
if (mTaskFragment == null) {
mTaskFragment = new TaskFragment();
fm.beginTransaction().add(mTaskFragment, TAG_TASK_FRAGMENT).commit();
}
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 !