Android集成Google Streetview API遇阻,XML片段识别异常求助
问题:Android集成Google Street View API实现随机点位街景展示及XML布局问题
我在谷歌上找不到合适的资源,GPT也没给出有效方案。现在我要在Android项目里集成Google Street View API,让随机生成的标记点显示对应街景,但不知道具体怎么实现。同时XML里的片段提示未知,我想让地图和街景同屏显示,试过FrameLayout但更倾向用Fragment实现。作为编程新手,我不确定Google Streetview API是否正确导入,恳请帮助。
现有Java代码
public class MainActivity extends AppCompatActivity implements OnMapReadyCallback { private AppBarConfiguration appBarConfiguration; private ActivityMainBinding binding; private GoogleMap myMap; private Geocoder geocoder; private static final double MIN_LATITUDE = -90; private static final double MAX_LATITUDE = 90; private static final double MIN_LONGITUDE = -180; private static final double MAX_LONGITUDE = 180; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String geocodingApiKey = getResources().getString(R.string.com_google_android_geo_API_KEY_value1); String mapsApiKey = getResources().getString(R.string.com_google_android_geo_API_KEY_value2); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map); mapFragment.getMapAsync(this); setSupportActionBar(binding.toolbar); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.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(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } @Override public void onMapReady(@NonNull GoogleMap googleMap) { myMap = googleMap; Random random = new Random(); double lat = MIN_LATITUDE + (MAX_LATITUDE - MIN_LATITUDE) * random.nextDouble(); double lng = MIN_LONGITUDE + (MAX_LONGITUDE - MIN_LONGITUDE) * random.nextDouble(); LatLng randomLocation = new LatLng(lat, lng); Geocoder geocoder = new Geocoder(this, Locale.getDefault()); ArrayList<Address> addresses = null; try { addresses = (ArrayList<Address>) geocoder.getFromLocation(lat, lng, 1); if (addresses.size() > 0) { Address address = addresses.get(0); String locality = address.getLocality(); String adminArea = address.getAdminArea(); String countryName = address.getCountryName(); String postalCode = address.getPostalCode(); // use the address information as needed } } catch (IOException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } // street view //add marker w address as title String addressString = addresses.get(0).getAddressLine(0); myMap.addMarker(new MarkerOptions().position(randomLocation).title(addressString)); myMap.moveCamera(CameraUpdateFactory.newLatLng(randomLocation)); } public void showStreetView() { } }
现有XML代码
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.fragment.app.FragmentContainerView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/map" tools:context=".MapsActivity" android:name="com.google.android.gms.maps.SupportMapFragment" /> <androidx.fragment.app.FragmentContainerView android:id="@+id/streetviewpanorama_fragment" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <com.google.android.gms.maps.StreetViewPanoramaView android:id="@+id/street_view_panorama" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone" /> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/Theme.TheRealFinalGeoGuesser.AppBarOverlay"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/Theme.TheRealFinalGeoGuesser.PopupOverlay" /> </com.google.android.material.appbar.AppBarLayout> <include layout="@layout/content_main" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
解决方案
一、确认Google Street View API导入及配置
- 在
build.gradle(Module)中添加依赖:dependencies { implementation 'com.google.android.gms:play-services-maps:18.2.0' implementation 'com.google.android.gms:play-services-streetview:18.0.0' } - 在
AndroidManifest.xml中添加权限和API密钥:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <application> <meta-data android:name="com.google.android.geo.API_KEY" android:value="你的Google Cloud API密钥"/> </application> - 登录Google Cloud控制台,启用Street View API和Maps SDK for Android,确保API密钥拥有这两项服务的调用权限。
二、修正XML布局(实现地图与街景同屏)
你的XML存在两处错误:街景Fragment的类名写错,且两个全屏Fragment会互相覆盖。改用LinearLayout分屏显示:
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/Theme.TheRealFinalGeoGuesser.AppBarOverlay"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/Theme.TheRealFinalGeoGuesser.PopupOverlay" /> </com.google.android.material.appbar.AppBarLayout> <!-- 左右分屏显示地图和街景 --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:layout_marginTop="?attr/actionBarSize"> <!-- 地图Fragment --> <androidx.fragment.app.FragmentContainerView android:id="@+id/map" android:name="com.google.android.gms.maps.SupportMapFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <!-- 街景Fragment(修正类名) --> <androidx.fragment.app.FragmentContainerView android:id="@+id/streetviewpanorama_fragment" android:name="com.google.android.gms.maps.StreetViewPanoramaFragment" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> </LinearLayout> <include layout="@layout/content_main" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
三、实现随机点位的街景展示
- 在
MainActivity中添加街景对象声明:private StreetViewPanorama mStreetViewPanorama; - 在
onCreate中初始化街景Fragment:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... 原有代码 ... // 初始化街景Fragment StreetViewPanoramaFragment streetViewFragment = (StreetViewPanoramaFragment) getSupportFragmentManager() .findFragmentById(R.id.streetviewpanorama_fragment); streetViewFragment.getStreetViewPanoramaAsync(new OnStreetViewPanoramaReadyCallback() { @Override public void onStreetViewPanoramaReady(StreetViewPanorama panorama) { mStreetViewPanorama = panorama; } }); } - 修改
onMapReady方法,处理随机点位并加载街景(修复空指针问题):@Override public void onMapReady(@NonNull GoogleMap googleMap) { myMap = googleMap; Random random = new Random(); double lat = MIN_LATITUDE + (MAX_LATITUDE - MIN_LATITUDE) * random.nextDouble(); double lng = MIN_LONGITUDE + (MAX_LONGITUDE - MIN_LONGITUDE) * random.nextDouble(); LatLng randomLocation = new LatLng(lat, lng); Geocoder geocoder = new Geocoder(this, Locale.getDefault()); ArrayList<Address> addresses = null; String addressString = "未知地点"; try { addresses = (ArrayList<Address>) geocoder.getFromLocation(lat, lng, 1); if (addresses != null && addresses.size() > 0) { Address address = addresses.get(0); addressString = address.getAddressLine(0) != null ? address.getAddressLine(0) : "未知地点"; // 添加标记 myMap.addMarker(new MarkerOptions().position(randomLocation).title(addressString)); } } catch (IOException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } // 移动地图到随机点位 myMap.moveCamera(CameraUpdateFactory.newLatLngZoom(randomLocation, 12)); // 加载街景 if (mStreetViewPanorama != null) { mStreetViewPanorama.setPosition(randomLocation); // 监听街景加载状态 mStreetViewPanorama.setOnStreetViewPanoramaChangeListener(location -> { if (location == null) { Toast.makeText(MainActivity.this, "该地点无街景数据", Toast.LENGTH_SHORT).show(); } }); } }
四、额外注意事项
- 随机生成的经纬度可能位于无街景区域,必须添加加载失败提示。
- Android 6.0及以上版本,需要动态申请
ACCESS_FINE_LOCATION权限,否则Geocoder可能无法正常工作。 - 测试阶段暂时关闭API密钥的IP/应用限制,避免权限问题。
内容的提问来源于stack exchange,提问作者dudewhoislearning
相关产品推荐
相关产品推荐

