I am currently building an android app. I understand the basics and I did a number of apps but now my project is bigger. My app include a number of screens with NavigationDrawer included which forces me to use an extension of Fragment class on every class I want to be displayed on my application.
Here is my problem -some time ago I create an app a simple one page google maps screen and it works just fine. I want to do the same thing on the app I am currently working on but all it gives me when I go to the page is the google log at the bottom left screen and the rest is grey like view (no map is displayed).I searched for solution in a lot of places including this site and I could get as an answer was that it might have to do with my API key given to me by google.I ckecked that and I am pretty sure it is not from the key because I applied it on my one page google map app and it worked perfect.I also have all the permissions needed I checked that like 6 times.So my conclusion is there is something in the code that is preventing the map to be displayed.
Here is my code:
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class guide extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflat and return the layout
View v = inflater.inflate(R.layout.test, container,
false);
return v;
}
class HoldFragmentPlace extends FragmentActivity{
private GoogleMap mMap;
public HoldFragmentPlace(){
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflat and return the layout
View v = inflater.inflate(R.layout.test, container,
false);
return v;
}
#Override
protected void onResume() {
super.onResume();
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
mMap = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map))
.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
}
}
I need that Fragment extension for my NavigationDrawer to work so I create an inner class and applied the code for the map there.
Here is what I have in my manifest:
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="#string/google_maps_key" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
And here is my xml for the map:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.gms.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="fill_parent"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_marginTop="-470dp" />
</LinearLayout>
I also tried a few other variations of the java code some of them does not include inner class and the result is still the same.I am either missing something very fundamental or I am misunderstanding some conception about Android.If you have read all that thank you for the spared time!
Check the APK signing. You have to assign a debug API key in testing and a Release API key when releasing APK. Insert the correct API key, clean and rebuild your project.
I've been there a year a go and I can assure that this was the problem. Double check your key and if it's a debug or release key.
Another thing to check is the package name of your app...
Let me know if you did and still get the grey view instead of the
UPDATE:
I was trying to include everything when I realized that your problem is only in the signing phase.
You only need to get the SHA-1 fingerprint of the debug keystore and put it in your API Key dialog. And trust me there's nothing I can write that can be more clear and informative than the Google documentation.
Follow the steps in this link to get the debug certificate and the SHA-1 fingerprint.
UPDATE 2:
In order to get the SHA-1 of the keystore you might check this thread .
I suspect some part missing :
(1) Declare permission to use MAPS_RECEIVE :
<permission android:name="com.example.yourpackage.permission.MAPS_RECEIVE" android:protectionLevel="signature"/>
<!-- after declare use this -->
<uses-permission android:name="com.example.yourpackage.permission.MAPS_RECEIVE"/>
(2) Missing Declare gms version variable :
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
(3) The API_KEY may have some problem with generation :
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your_key" />
Please check with above 3 suspects first : then if still error is there you can re-confirm steps to enable Google Maps from here
Check things related to API_KEY carefully
You can use SupportMapFragment to display map in your fragment.
The xml should be changed to
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/mapView"
android:layout_marginTop="-470dp"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
and your class would be like below
public class guide extends Fragment {
private GoogleMap mMap;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// inflat and return the layout
View v = inflater.inflate(R.layout.test, container, false);
((SupportMapFragment) getFragmentManager()
.findFragmentById(R.id.mapView)).getMapAsync (new OnMapReadyCallback(){
#Override
public void onMapReady(final GoogleMap map) {
this.mMap = map;
mMap.setMyLocationEnabled(true);
setUpMap();
}
});
return v;
}
private void setUpMap() {
mMap.addMarker(new MarkerOptions().position(new LatLng(0, 0)).title("Marker"));
}
}
Note: Please update your google play services if you dont find the getMapAsync method for your SupportMapFragment.
Related
My goal is to create a simple ball in the mobile screen center so I can move it around the screen as they drag my finger.
For that I wanted to use the Canvas and bitmap (I do not know if it's the best way seen as already said I am new in the Android world).
I created a function in my Activity so that when a button was clicked, a activity containing the script to the canvas design was created (Again not know if it's the best way. In a php script or javascript I would create the ball in the function itself). My code is as follows:
public void StartGame(View v) {
Intent i = new Intent(MainActivity.this, ball.class);
startActivity(i);
}
By doing this it should call the following activity:
com.teste package;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class ball extends View {
Paint pincelPreto private;
Paint pincelAmerelo private;
Public ball (Context context) {
super (context);
}
Public ball (Context context, attributeSet attrs) {
super (context, attrs);
setBackgroundColor (Color.LTGRAY);
pincelPreto = new Paint ();
pincelPreto.setColor (Color.BLACK);
pincelAmerelo = new Paint ();
pincelPreto.setColor (Color.YELLOW);
setFocusable (true);
}
#Override
protected void onDraw (Canvas canvas) {
super.onDraw (canvas);
canvas.drawCircle (200, 200, 200, pincelAmerelo);
}
}
And both draw a ball at every location ...
But I get the following error:
Android.content.ActivityNotFoundException: Unable to find explicit activity class {com.teste / com.teste.ball}; have you declared this activity in your AndroidManifest.xml?
What am I doing wrong?
OBS.: I maybe call activity because i dont know the real name of it.
Expanding on Neo's answer above and given your edited question:
The reason you are getting the Android.content.ActivityNotFoundException is because "ball" is a View, not an Activity, and so you cannot start "ball" as an activity.
public void StartGame(View v) {
Intent i = new Intent(MainActivity.this, ball.class);
startActivity(i);
}
Since you are new to Android, try to visualize an Activity as a component that usually takes over the whole screen, and a View as a smaller piece of that. You want your ball to display within your activity.
In your res/layout folder you should have a layout xml file for your MainActivity. You can add your ball view in here with some xml, similar to the following:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.teste.ball
android:id="#+id/ball"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</com.teste.ball>
</LinearLayout>
You may hit other problems once you've gotten that far, but it should be easier to debug then.
I agree with the comment above to learn the basics first before jumping in to a complicated application. Take a look at the Android Developer pages to learn the components and trying simple tutorials. There are a lot of components that make up an Android application and fully understanding them and how they interact with each other will make your life easier :). Good luck and welcome to Android!
Edit to answer question below ...can i do it with java? i searched something about "inflate" a view but i dont know if it is correct?
Yes you can add a view to the Activity's parent layout using addView. Inflate is for instantiating views in your XML into Java objects, so it will not work in your case because you don't have an xml file for your Ball layout. You would need to create a new Ball object and use addView to add it to your layout:
LinearLayout layout = findViewById(R.id.main);
Ball ball = new Ball(this);
ball.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
layout.addView(ball);
where layout is the parent layout found in your activity's XML. You may need to assign it an ID if you haven't already, so if we use my example above, your LinearLayout tag would look like:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
If you want to create an activity then you need to extend it by Activity class. By extending view you can create a custom view, which you can use within xml or dynamically in your activity or fragment. For example ImageView, TextView, EditText, All layouts extends View, that you can use within your activity or fragment either by xml or dynamically.
As others have noted, Ball extends View, which is not an Activity. To use the startActivity() method, you need to pass it an Activity. First create your BallView:
package com.test.myapplication;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class BallView extends View {
private final Paint pincelPreto;
private final Paint pincelAmerelo;
public BallView(final Context context) {
super(context);
setBackgroundColor(Color.LTGRAY);
pincelPreto = new Paint();
pincelPreto.setColor(Color.BLACK);
pincelAmerelo = new Paint();
pincelAmerelo.setColor(Color.YELLOW);
}
#Override
protected void onDraw(final Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(200, 200, 200, pincelAmerelo);
}
}
Then create a BallActivity. This consists of both a Java class and an XML resource that you put under res/layout/activity_ball.xml. Below is an example XML resource:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.test.myapplication.BallView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"/>
</FrameLayout>
And the BallActivity class:
package com.test.myapplication;
import android.app.Activity;
import android.os.Bundle;
public class BallActivity extends Activity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ball);
}
}
The last thing that needs to be done in order to launch BallActivity is to add it to AndroidManifest.xml (otherwise you'll continue to get ActivityNotFoundException):
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.test.myapplication"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".BallActivity"/>
</application>
</manifest>
Hope this helps.
What is the recommended way to show current location on a map along with custom markers? The code below is working fine, that is, it is showing my current location and also showing a marker near my location that i added.
Layout:activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<TextView
android:id="#+id/tv_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tv_location"
class="com.google.android.gms.maps.SupportMapFragment" />
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.geolocs"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- External storage for caching. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- My Location -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<!-- Maps API needs OpenGL ES 2.0. -->
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data android:name="com.google.android.maps.v2.API_KEY"
android:value="MY API KEY"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
MainActivity.java
import android.app.Dialog;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MainActivity extends FragmentActivity implements LocationListener {
GoogleMap googleMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Getting Google Play availability status
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getBaseContext());
// Showing status
if(status!=ConnectionResult.SUCCESS){ // Google Play Services are not available
int requestCode = 10;
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(status, this, requestCode);
dialog.show();
}else { // Google Play Services are available
// Getting reference to the SupportMapFragment of activity_main.xml
SupportMapFragment fm = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
// Getting GoogleMap object from the fragment
googleMap = fm.getMap();
// Enabling MyLocation Layer of Google Map
googleMap.setMyLocationEnabled(true);
// Getting LocationManager object from System Service LOCATION_SERVICE
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
// Creating a criteria object to retrieve provider
Criteria criteria = new Criteria();
// Getting the name of the best provider
String provider = locationManager.getBestProvider(criteria, true);
// Getting Current Location
Location location = locationManager.getLastKnownLocation(provider);
if(location!=null){
onLocationChanged(location);
}
locationManager.requestLocationUpdates(provider, 20000, 0, this);
//add a custom marker
googleMap.addMarker(new MarkerOptions()
.position(new LatLng(63.813293,20.308319))
.title("House Rent"));
}
}
#Override
public void onLocationChanged(Location location) {
TextView tvLocation = (TextView) findViewById(R.id.tv_location);
// Getting latitude of the current location
double latitude = location.getLatitude();
// Getting longitude of the current location
double longitude = location.getLongitude();
// Creating a LatLng object for the current location
LatLng latLng = new LatLng(latitude, longitude);
// Showing the current location in Google Map
googleMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
// Zoom in the Google Map
googleMap.animateCamera(CameraUpdateFactory.zoomTo(16));
// Setting latitude and longitude in the TextView tv_location
tvLocation.setText("Latitude:" + latitude + ", Longitude:"+ longitude );
}
#Override
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
// TODO Auto-generated method stub
}
#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;
}
}
My questions are, Is it a recommended (or atleast a correct) way? Is there any major issue that I have to rectify (or take care) in my MainActivity? Do I always need to extend FragmentActivity and implement LocationListener when displaying current location on a map with custom markers? Should I always add my custom markers inside onCreate() method (There are many example where it is inside onLocationChange()? Would highly appreciate some feedback.
Is there any major issue that I have to rectify (or take care) in my MainActivity? No it looks fine to me.
Do I always need to extend FragmentActivity and implement LocationListener when displaying current location on a map with custom markers? No, you do not need to do either. You just need to create a LocationListener object and obtain a reference to the map fragment you wish to use.
Should I always add my custom markers inside onCreate() method (There are many example where it is inside onLocationChange()? It depends on what you are trying to do, but using a method like onLocationChange() to move a markers is good practice if you are doing something that involves moving the marker every time the location changes. If the markers you're creating are not intended to move and they only need to be created once then the onCreate() method is a good place to do it.
I have a FragmentActivity with a lateral bar (like a menu bar), and a container to put fragments there.
From this FragmentActivity I call to other fragments using onClickListener of each button (from the lateral bar).
So for example, FragmentActivity is called MenuViewActivity. This calls Navigation fragment and sets it's layout on the container.
In Navigation Fragment, I have a button that starts GoogleMaps (or that is what I need to get)
[MenuViewActivity(FragmentActivity)] >> [NavigationFragment(Fragment)] >> [GoogleMapsFragment(Fragment)]
The idea is to fit the GoogleMaps windows in the same container that I set the other Fragments (like navigationFragment)
This is the code of NavigationFragment.java:
public class NavigationFragment extends Fragment implements OnClickListener {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/**Inflate the layout for this fragment*/
View mainView = inflater.inflate(R.layout.navegacion, container, false);
mapBtn = (ImageView) mainView.findViewById(R.id.mapsButton);
navBtn = (ImageView) mainView.findViewById(R.id.navigatorButton);
mapBtn.setOnClickListener(this);
navBtn.setOnClickListener(this);
return mainView;
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.mapsButton:
GoogleMapsFragment fragment_maps = new GoogleMapsFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment_container, fragment_maps).commit();
break;
}
}
This is the code of GoogleMapsFragment.java:
public class GoogleMapsFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
/**Inflate the layout for this fragment*/
View mainView = inflater.inflate(R.layout.google_maps, container, false);
SupportMapFragment fm = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.map);
mMap = fm.getMap();
return mainView;
}
And the code of the google_maps.xml:
<fragment
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:map="http://schemas.android.com/apk/res-auto"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="com.google.android.gms.maps.MapFragment"
map:cameraTilt="45"
map:cameraZoom="14"
class="com.google.android.gms.maps.SupportMapFragment" />
I think that I'm not calling right the GoogleMapsFragment on the onClick, or that I cannot call maybe to the *fragment_container* from other fragment like I do in NavigationFragment because this id belongs to the layout of MenuViewActivity.
The logCat output's this:
android.view.InflateException: Binary XML file line #3: Error inflating class fragment
at com.example.GoogleMapsFragment.onCreateView(GoogleMapsFragment.java:47)
Caused by: java.lang.IllegalStateException: A required meta-data tag in your app's
AndroidManifest.xml does not exist. You must have the following declaration within the <application> element:
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
The Exception is telling you exactly what the problem is. Since the last update of the google-play-services_lib you need to add the following to the AndroidManifest.xml within the application tag:
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
Also, you have:
android:name="com.google.android.gms.maps.MapFragment"
class="com.google.android.gms.maps.SupportMapFragment"
You should only have one of this attributes. Here you have two and they are pointing to two different classes. If you want backwards compatibility you should use com.google.android.gms.maps.SupportMapFragment.
One suggestion. If you only need to display a map why not extends SupportMapFragment or MapFragment instead of Fragment?
first off all I know here are many threads about this problem, but I read them all ,and try pretty much everything.
So what is my problem. I am developing an app with Google maps, and I also occur that well known problem that mapView is loaded fine, but it contains nothing (only grey blank rectangles).
Here is what I tried:
I tripplecheck my API code
I regenerate my API code
I check all the permmisions
And a lot of other stuff
main_layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.google.android.maps.MapView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:enabled="true"
android:apiKey="my key"/>
</RelativeLayout>
manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.gps.gpsclientsoftware"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<uses-library android:name="com.google.android.maps"/>
<activity
android:name="com.gps.gpsclientsoftware.GPSClientActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity code:
package com.gps.gpsclientsoftware;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
public class GPSClientActivity extends MapActivity {
private MapView mapView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
One warning that I found when I launch my app, was:
03-11 17:51:03.751: E/MapActivity(8581): Couldn't get connection factory client
Hope you can help me.
Check this...
http://ucla.jamesyxu.com/?p=287
You need to override all the method. Don't miss any one.
I did it, and I got a working MapView.
(onLowMemory seems can be skipped.)
(MapView works better than MapFragment.)
Since 12/2012 Google released Google maps version 2.
This means that new applications should use this version and that api keys are provided only for v2 maps.
Your implementation seems to be for google maps v1.
Check here for a detailed guide, but from a quick look I see that the following are missing from your android manifest:
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your_api_key"/>
<permission
android:name="your.project.permission.MAPS_RECEIVE"
android:protectionLevel="signature"/>
<uses-permission android:name="your.project.permission.MAPS_RECEIVE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="your key" />
Also to run google maps on your phone you need to install google play services. In order to check that it is already installed and google maps v2 work on your device I suggested using an application that uses v2 maps like trulia.
As hsu.tw pointed out, we need to call lifecycle method of MapView from fragment lifecycle methods.
But having MapView part of layout file causes issue as onCreate called before inflating fragments layout [So MapView's onCreate() never be called].
Below approach works for me. [Might need to take care of removing MapView if you are adding this Fragment to BackStack]
class MapFragment : BaseFragment() {
var mapView: MapView? = null
override fun getFragmentLayout() = R.layout.fragment_map
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
(view as? LinearLayout)?.addView(mapView, LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// create map view
mapView = MapView(context /*, GoogleMapOption for configuration*/)
mapView?.onCreate(savedInstanceState)
}
override fun onStart() {
super.onStart()
mapView?.onStart()
}
override fun onPause() {
super.onPause()
mapView?.onPause()
}
override fun onResume() {
super.onResume()
mapView?.onResume()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
mapView?.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mapView?.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView?.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView?.onDestroy()
}
}
Replace "my key" in your manifest with your actual API key.
android:apiKey="my key"/>
An API key can be otained here:
https://developers.google.com/maps/documentation/android/start#obtaining_an_api_key
I can't get the map ! all I can get is null.
here is the code.
public class MainActivity extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SupportMapFragment fragment = new SupportMapFragment();
getSupportFragmentManager().beginTransaction()
.add(android.R.id.content, fragment).commit();
GoogleMap map;
map = fragment.getMap();
//here i cant access this snippet because map = null
if(map!=null){
UiSettings mm = map.getUiSettings();
map.setMyLocationEnabled(true);
} }
}
The manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.anywhere_reminder"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true"/>
<permission
android:name="com.example.anywhere_reminder.permission.MAPS_RECEIVE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.anywhere_reminder.permission.MAPS_RECEIVE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity android:name="com.google.android.gms.BuildConfig" />
<activity
android:name="com.example.anywhere_reminder.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value=" my key "/>
</application>
</manifest>
here is the xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/hello_world" />
</RelativeLayout>
I tried to solve it like this solution Google Maps Android API v2 throws GooglePlayServicesNotAvailableException, out of date, SupportMapFragment.getMap() returns null
.. but still did not work
UPDATE:
I got my map working now .. here is the edited working version
public class MainActivity extends FragmentActivity {
private GoogleMap myMap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
android.support.v4.app.FragmentManager myFragmentManager = getSupportFragmentManager();
SupportMapFragment mySupportMapFragment
= (SupportMapFragment)myFragmentManager.findFragmentById(R.id.map);
myMap = mySupportMapFragment.getMap();
if(myMap!=null)
myMap.setMyLocationEnabled(true);
}
You are creating a dynamic fragment, via a FragmentTransaction. When you call commit(), the fragment has not yet been added to the screen, because the FragmentTransaction has only been scheduled to occur -- it has not occurred yet. Hence, the SupportMapFragment has not been called with onCreateView() yet, so there is no GoogleMap.
Either switch to static fragments (<fragment> tag in a layout), or delay your use of the GoogleMap until after the transaction has been processed.
executePendingTransactions() in FragmentManager class was designed to fix this delay.
From documantstion : After a FragmentTransaction is committed with FragmentTransaction.commit(), it is scheduled to be executed asynchronously on the process's main thread. If you want to immediately executing any such pending operations, you can call this function (only from the main thread) to do so. Note that all callbacks and other related behavior will be done from within this call, so be careful about where this is called from.
I have extended the MapFragment class and added a listener.
The doc about getMap() say:
... Null if the view of the fragment is not yet ready. This can happen if the fragment lifecyle have not gone through onCreateView(LayoutInflater, ViewGroup, Bundle) yet....
Then I call the listener after onCreateView. I add the class
public class MySupportMapFragment extends SupportMapFragment{
private MySupportMapFragmentListener listener;
public interface MySupportMapFragmentListener{
public void onMapCreated(GoogleMap googleMap);
}
// value taken from source code
private static final String MAP_OPTIONS = "MapOptions";
public static MySupportMapFragment newInstance() {
MySupportMapFragment f = new MySupportMapFragment();
return f;
}
public static MySupportMapFragment newInstance(GoogleMapOptions options) {
MySupportMapFragment f = new MySupportMapFragment();
Bundle args = new Bundle();
args.putParcelable(MAP_OPTIONS, options);
f.setArguments(args);
return f;
}
// other newInstance methods ...
/* (non-Javadoc)
* #see android.support.v4.app.Fragment#onViewCreated(android.view.View, android.os.Bundle)
*/
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onViewCreated(view, savedInstanceState);
// here, as doc say, the map can be initialized, or the service is not available
if(listener!=null){
listener.onMapCreated(getMap());
}
}
/**
* #return the listener
*/
public MySupportMapFragmentListener getListener() {
return listener;
}
/**
* #param listener the listener to set
*/
public void setListener(MySupportMapFragmentListener listener) {
this.listener = listener;
}
}
After in the calling activity or fragment ...
mapFragment = MySupportMapFragment.newInstance();
mapFragment.setListener(new MySupportMapFragmentListener() {
#Override
public void onMapCreated(GoogleMap googleMap) {
// TODO Auto-generated method stub
if(googleMap!=null){
// service is unaviable
}
}
Move the code snippet:
GoogleMap map;
map = fragment.getMap();
//here map is not null
if(map!=null){
UiSettings mm = map.getUiSettings();
map.setMyLocationEnabled(true);
}
to onResume() method, this will solve your issue.
Another way to solve it. Implemet an interface in the MapFragment to communicate to the activity when it is ready for GoogleMap creation.
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
listener.onGoogleMapCreattion();
}
Then you just need to implement the listener in the activtiy:
#Override
public void onGoogleMapCreation() {
setUpMapIfNeeded();
}
private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the map.
if (mMap == null) {
mMap = mMapFragment.getMap();
// Check if we were successful in obtaining the map.
if (mMap != null) {
// The Map is verified. It is now safe to manipulate the map.
setUpMap();
}
}
}