SupportMapFragmentManagers getMapAsync() does not trigger onMapReady(GoogleMap map) - google-maps-android-api-2

I have a
public abstract class MyMapFragment implements OnMapReadyCallback
{
//
public GoogleMap googleMap;
SupportMapFragment mapFragment;
#IdRes
public abstract int getSupportMapFragId();
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// http://stackoverflow.com/a/36592000/5102206
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
// Do something for lollipop and above versions
mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(getSupportMapFragId());
} else {
// do something for phones running an SDK before lollipop
mapFragment = (SupportMapFragment) getFragmentManager().findFragmentById(getSupportMapFragId());
}
mapFragment.getMapAsync(this);
}
//..
#Override
public void onMapReady(GoogleMap map) {
this.googleMap = map;
}
}
According to my breakpoints onViewCreated() is called, but onMapReady() is not called (breakpoint on this.googleMap = map not triggered)
On Android 5, 6 and 7 it works fine so far and I can see the Map..
On Android 4.X (API 16 - API 19) devices my app starts up, but then it seem to freeze there... I see a white blank screen.
On Android 4.X OS devices:
1. With getFragmentManager(), the mapFragment object is null after the else condition.
2. With getChildFragmentMenager() the mapfragment seem to be valid and non-null, but onMapReady not triggered.
What am I missing here?

Note: You cannot inflate a layout into a fragment when that layout includes a . Nested fragments are only supported when added to a fragment dynamically
If you want to inflate a map in a fragment you can either do it in xml or do it in java code like this:
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
FragmentManager fm = getChildFragmentManager();
SupportMapFragment mapFragment = (SupportMapFragment) fm.findFragmentByTag("mapFragment");
if (mapFragment == null) {
mapFragment = new SupportMapFragment();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.mapFragmentContainer, mapFragment, "mapFragment");
ft.commit();
fm.executePendingTransactions();
}
mapFragment.getMapAsync(callback);
}
And also the simple container
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
</LinearLayout>
Also, you don't need to implement the onMapReadyCallback in the class definition. Instead of callback you create a new OnMapReadyCallback() right there:
MapView.getMapAsync(new OnMapReadyCallback() {
#Override
public void onMapReady(GoogleMap mMap) {
googleMap = mMap;
}
});
You also need these
MapView mMapView;
private GoogleMap googleMap;
I hope this helps somehow !

There was an issue with a blocking thread from RxJava on main thread. So it was not an Google Maps issue.

I don't quite understand why you are nesting fragments, specially because it can cause performance issues.
If you take a look at Google Samples, the Google Maps examples uses an Activity and SupportMapFragment:
public class MapsActivityCurrentPlace extends AppCompatActivity
implements OnMapReadyCallback, ConnectionCallbacks,
OnConnectionFailedListener {
#Override
public void onMapReady(GoogleMap map) {
mMap = map;
// Use a custom info window adapter to handle multiple lines of text in the
// info window contents.
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
#Override
// Return null here, so that getInfoContents() is called next.
public View getInfoWindow(Marker arg0) {
return null;
}
#Override
public View getInfoContents(Marker marker) {
// Inflate the layouts for the info window, title and snippet.
View infoWindow = getLayoutInflater().inflate(R.layout.custom_info_contents,
(FrameLayout)findViewById(R.id.map), false);
TextView title = ((TextView) infoWindow.findViewById(R.id.title));
title.setText(marker.getTitle());
TextView snippet = ((TextView) infoWindow.findViewById(R.id.snippet));
snippet.setText(marker.getSnippet());
return infoWindow;
}
});
// Turn on the My Location layer and the related control on the map.
updateLocationUI();
// Get the current location of the device and set the position of the map.
getDeviceLocation();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mLastKnownLocation = savedInstanceState.getParcelable(KEY_LOCATION);
mCameraPosition = savedInstanceState.getParcelable(KEY_CAMERA_POSITION);
}
setContentView(R.layout.activity_maps);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.enableAutoManage(this /* FragmentActivity */,
this /* OnConnectionFailedListener */)
.addConnectionCallbacks(this)
.addApi(LocationServices.API)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.build();
mGoogleApiClient.connect();
}
#Override
public void onConnected(Bundle connectionHint) {
SupportMapFragment mapFragment =
(SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult result) {
Log.d(TAG, result.getErrorMessage());
}
#Override
public void onConnectionSuspended(int cause) {
Log.d(TAG, "Play services connection suspended");
}
}

Related

how do i implement android mapbox android sdk successfully in fragment

I am using mapbox in a fragment with bottom navigation, when i exit and resume the app or when i change tabs rapidly, the app crashes. this is the error i get
10-07 22:20:36.046 21867-21886/com.dropexpress.driver.dropexpressdriver E/Mbgl-FileSource: Failed to read the storage key:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Bundle.getBoolean(java.lang.String, boolean)' on a null object reference
at com.mapbox.mapboxsdk.storage.FileSource.getCachePath(FileSource.java:88)
at com.mapbox.mapboxsdk.storage.FileSource$FileDirsPathsTask.doInBackground(FileSource.java:165)
at com.mapbox.mapboxsdk.storage.FileSource$FileDirsPathsTask.doInBackground(FileSource.java:155)
at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
at java.lang.Thread.run(Thread.java:761)
the below code always fails when i exit the app and resume, or when i change tabs rapidly, i am using bottom navigation.
Steps to reproduce
here is my fragment code
package com.dropexpress.driver.dropexpressdriver.fragments;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.dropexpress.driver.dropexpressdriver.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
public class HomeFragment extends Fragment {
private MapView mapView;
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public HomeFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment HomeFragment.
*/
// TODO: Rename and change types and number of parameters
public static HomeFragment newInstance(String param1, String param2) {
HomeFragment fragment = new HomeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#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);
Mapbox.getInstance(requireActivity(), "pk.eyJ1Ijoic3ludGF4bHRkIiwiYSI6ImNqaDJxNnhzbDAwNnMyeHF3dGlqODZsYjcifQ.pcz6BWpzCHeZ6hQg4AH9ww");
mapView = (MapView) view.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
return view;
}
// 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");
}
}
#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);
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
public void onPause() {
super.onPause();
mapView.onPause();
}
#Override
public void onStop() {
super.onStop();
mapView.onStop();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}
Android versions: 5.0 +
Device models: motorola g5
Mapbox SDK versions: 6.5.0
Put your Mapbox.getInstance before inflating your layout.
Mapbox.getInstance(requireActivity(),"Your Map Key");
View view = inflater.inflate(R.layout.fragment_home, container, false);
mapView = (MapView) view.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
I hope this helps you.
i opened this issue in github, you check their response here
https://github.com/mapbox/mapbox-gl-native/issues/13044#issuecomment-427861016
this was their response:
I can see 2 issues with the provided code:
You are not calling MapView#onDestroy, this has to be called from you fragment's #onDestroyView.
MapView#onCreate should be called from fragment's #onViewCreatedinstead of #onCreateView.
I applied the changes and it worked!

How to detect backbutton/home press from a service like messenger chat head service?

I have been looking through several stackoverflow question to find out how can I listen to backpress button on a service using windows manager. Most of the answers proposes that it's not possible, however I can see that messenger handle it very well.
How does messenger handle the backpress button on it's head chat service? (Or I am completely wrong and they are not a service using windows manager?)
To achieve what you need, you need to extend some ViewGroup that you are going to use as a root container for your views. Let's start with this:
public class BackButtonAwareLinearLayout extends LinearLayout {
public interface BackButtonListener {
void onBackButtonPressed();
}
#Nullable
private BackButtonListener mListener;
public BackButtonAwareLinearLayout(Context context) {
super(context);
}
public BackButtonAwareLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BackButtonAwareLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setBackButtonListener(#Nullable BackButtonListener listener) {
mListener = listener;
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& mListener != null) {
mListener.onBackButtonPressed();
return true;
}
return super.dispatchKeyEvent(event);
}
}
Basically, overriding dispatchKeyEvent is what does a trick for us here.
Then make a use of it in some xml (I have called it chat_head_container.xml):
<?xml version="1.0" encoding="utf-8"?>
<com.pablo432.myapplication.BackButtonAwareLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="48sp"
android:text="Hello, world!"
android:textColor="#000"
android:background="#f5f5f5"
android:gravity="center"/>
</com.pablo432.myapplication.BackButtonAwareLinearLayout>
Next, create a Service that adds our view to the WindowManager (though I suppose you know how to do it, I'll post it anyway for the sake of completeness):
public class ChatHeadService extends Service
implements BackButtonAwareLinearLayout.BackButtonListener {
private WindowManager mWindowManager;
private BackButtonAwareLinearLayout mRootContainer;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mRootContainer = (BackButtonAwareLinearLayout) inflater.inflate(
R.layout.chat_head_container, null, false);
mRootContainer.setBackButtonListener(this);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_FULLSCREEN,
PixelFormat.TRANSPARENT);
mWindowManager.addView(mRootContainer, layoutParams);
}
#Override
public void onBackButtonPressed() {
mRootContainer.setBackButtonListener(null);
mWindowManager.removeView(mRootContainer);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mRootContainer != null) mWindowManager.removeView(mRootContainer);
}
}
So long story short, BackButtonAwareLinearLayout exposes a listener interface, that our service needs to implement and subscribe itself to the Layout.
Also have in mind that this addresses handling back button. To handle home button, you may want to take a look at https://stackoverflow.com/a/31340960 and https://stackoverflow.com/a/33580971 - basically my answer is a bit of a summary from those two links + https://stackoverflow.com/a/15980900 but contains few tweaks (like, for example, you can't set FLAG_NOT_FOCUSABLE in WindowManager.LayoutParams).
Of course you need to start your service somewhere by calling startService, declare this service in AndroidManifest.xml and add a SYSTEM_ALERT_WINDOW permission.

Update ListView via AsyncTask or IntentService

I am trying to Update my Custom ListView which is fed by two String Arrays:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getStringArray(ARG_PARAM1);
mParam2 = getArguments().getStringArray(ARG_PARAM2);
}
setupListView();
}
private void setupListView() {
listItemList = new ArrayList();
if (mParam1 != null && mParam2 != null && mParam1.length == mParam2.length) {
for (int i = 0; i < mParam1.length; i++) {
listItemList.add(new MyListItem(mParam1[i], (mParam2[i]).substring(0, 75) + "..."));
}
} else {
listItemList.add(new MyListItem("Loading...", "Swipe Down for Update"));
}
mAdapter = new MyListAdapter(getActivity(), listItemList);
}
mParam1 and mParam2 are Values which are fetched by an XML parser (IntentService) class in the MainActivity which i can show if needed.
Now, if i am to fast, and the mPara1 and mPara2 is empty there won´t be any ListView shown. Now i want to solve this by some AsyncTask or IntentService whatever is useful. I tried AsyncTask, which didn´t work at all. I tried notifyDataSetChanged() which didn´t work too...
Now, how could i solve this....
Using AsyncTask i have the problem that i don´t know how to passt the two Arrays to publishProgress() correctly
THis is how my AsyncTask looks like:
class UpdateListView extends AsyncTask<Void, String, Void> {
private MyListAdapter adapter;
private ArrayList listItemList;
#Override
protected void onPreExecute() {
adapter = (MyListAdapter) mListView.getAdapter();
}
#Override
protected Void doInBackground(Void... params) {
for (String item1 : mParam1) {
publishProgress(item1);
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
adapter.add(new MyListItem(values[0], values[1]));
}
#Override
protected void onPostExecute(Void result) {
Log.d("onPostExecute", "Added successfully");
}
}
Okay solved it...My Fragments are running in same Activity where the Data is loaded in, so i just created getter and setter in MainActivity and access them in the needed Fragment via
String[] titles =(MainActivity) getActivity()).getTitlesArray();
String[] text=(MainActivity) getActivity()).getTextArray();
Whatever i do trying setting Bundle with
bundle.putStringArray(TITLES,titles);
doesn´t work. Should work using parceable/serializable class but didn´t try...

My Android App is crashed when I register SensorManager.registerListener

Below is my code. I am having a problem when I call SensorManager.registerListener, my app will crash. Can someone tell me what's going on?
I just follw the web guide to setup SensorManger, Sensor(Accelerometer) and then register the action lintener to detect the montion of accelerometer.
I used API 21 to develop this app.
public class MainActivity extends ActionBarActivity implements SensorEventListener{
private TextView tip;
private SensorManager mSensorManager;
private Sensor mSensor;
private float axisX = 0;
private float axisY = 0 ;
private float axisZ = 0;
#Override
protected void onResume() {
super.onResume();
setUpAcceleratorSensor();
mSensorManager.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
mSensorManager.unregisterListener(this);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setUpAcceleratorSensor();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
private void setUpAcceleratorSensor(){
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
if((mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)) != null);
else
Toast.makeText(this, "No Sensor Device Exist", Toast.LENGTH_LONG).show();
}
#Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
Sensor mySensor = event.sensor;
if (mySensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if(event.values[0] != 0 || event.values[1] != 0 || event.values[2] != 0){
axisX = event.values[0];
axisY = event.values[1];
axisZ = event.values[2];
tip.setText("Detect your montion");
}
}
else
Toast.makeText(this, "Cannot Get Sensor Device", Toast.LENGTH_LONG).show();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}
Thanks.
First that I always check when something like this goes wrong, is to check that you have all the correct permissions in the Android Manifest; however, I don't believe that there are any permissions associated with using the position sensors. I would check on this first. That is what comes to mind first, after you post logcat, we will be able to give a more detailed answer.
Try getting the sensor this way
mSensor = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0); instead in your setUpAccelerometer() method.

Eclipse DisplayMessageActivity error

I have a question about an error I get in Eclipse.
Eclipse says "The nested type DisplayMessageActivity cannot hide an enclosing type"
This is my script:
package com.example.warzonegaming;
public class DisplayMessageActivity {
public class DisplayMessageActivity extends Activity {
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
// Set the text view as the activity layout
setContentView(textView);
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
Does someone knows an fix for this, because I can't go further now.
Regards
Try learn basics of javapackage com.example.warzonegaming;
public class DisplayMessageActivity extends Activity {
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);
// Create the text view
TextView textView = new TextView(this);
textView.setTextSize(40);
textView.setText(message);
// Set the text view as the activity layout
setContentView(textView);
// Make sure we're running on Honeycomb or higher to use ActionBar APIs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
// Show the Up button in the action bar.
getActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}