feat: Add SaveStateDemoActivity. (#431)

This commit is contained in:
Chris Arriola 2021-01-27 12:10:02 -08:00 committed by GitHub
parent 05b53a22d6
commit 0514d79efa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 202 additions and 3 deletions

View File

@ -52,6 +52,7 @@
<activity android:name=".ProgrammaticDemoActivity" />
<activity android:name=".RawMapViewDemoActivity" />
<activity android:name=".RetainMapDemoActivity" />
<activity android:name=".SaveStateDemoActivity" />
<activity android:name=".SplitStreetViewPanoramaAndMapDemoActivity" />
<activity android:name=".StreetViewPanoramaBasicDemoActivity" />
<activity android:name=".StreetViewPanoramaEventsDemoActivity" />

View File

@ -23,8 +23,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.GoogleMap.OnCameraIdleListener
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
@ -33,7 +31,6 @@ import com.google.maps.android.ktx.CameraIdleEvent
import com.google.maps.android.ktx.awaitMap
import com.google.maps.android.ktx.cameraEvents
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch

View File

@ -86,6 +86,9 @@ class DemoDetailsList {
DemoDetails(R.string.raw_map_view_demo_label,
R.string.raw_map_view_demo_description,
RawMapViewDemoActivity::class.java),
DemoDetails(R.string.save_state_demo_label,
R.string.save_state_demo_description,
SaveStateDemoActivity::class.java),
DemoDetails(R.string.street_view_panorama_basic_demo_label,
R.string.street_view_panorama_basic_demo_details,
StreetViewPanoramaBasicDemoActivity::class.java),

View File

@ -0,0 +1,160 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.example.kotlindemos
import android.os.Bundle
import android.os.Parcelable
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap.OnMarkerClickListener
import com.google.android.gms.maps.GoogleMap.OnMarkerDragListener
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.BitmapDescriptorFactory
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import com.google.maps.android.ktx.CameraEvent
import com.google.maps.android.ktx.addMarker
import com.google.maps.android.ktx.awaitMap
import com.google.maps.android.ktx.cameraEvents
import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.flow.collect
import java.util.Random
/**
* This activity shows how to save the state of a MapFragment when the activity is recreated, like
* after rotation of the device.
*/
class SaveStateDemoActivity : AppCompatActivity() {
@Parcelize
internal data class MarkerInfo(var hue: Float) : Parcelable
/**
* Example of a custom `MapFragment` showing how the position of a marker and other
* custom
* [Parcelable]s objects can be saved after rotation of the device.
*
*
* Storing custom [Parcelable] objects directly in the [Bundle] provided by the
* [.onActivityCreated] method will throw a `ClassNotFoundException`. This
* is due to the fact that this Bundle is parceled (thus losing its ClassLoader attribute at
* this moment) and unparceled later in a different ClassLoader.
* <br></br>
* A workaround to store these objects is to wrap the custom [Parcelable] objects in a
* new
* [Bundle] object.
*
*
* However, note that it is safe to store [Parcelable] objects from the Maps API (eg.
* MarkerOptions, LatLng, etc.) directly in the Bundle provided by the
* [.onActivityCreated] method.
*/
class SaveStateMapFragment : SupportMapFragment(), OnMarkerClickListener, OnMarkerDragListener {
private lateinit var mMarkerPosition: LatLng
private lateinit var mMarkerInfo: MarkerInfo
private var mMoveCameraToMarker = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Extract the state of the MapFragment:
// - Objects from the API (eg. LatLng, MarkerOptions, etc.) were stored directly in
// the savedInsanceState Bundle.
// - Custom Parcelable objects were wrapped in another Bundle.
mMarkerPosition =
savedInstanceState?.getParcelable(MARKER_POSITION) ?: DEFAULT_MARKER_POSITION
mMarkerInfo =
savedInstanceState?.getBundle(OTHER_OPTIONS)?.getParcelable(MARKER_INFO) ?: MarkerInfo(
BitmapDescriptorFactory.HUE_RED)
mMoveCameraToMarker = savedInstanceState == null
lifecycleScope.launchWhenCreated {
val map = awaitMap()
map.addMarker {
icon(BitmapDescriptorFactory.defaultMarker(mMarkerInfo.hue))
position(mMarkerPosition)
draggable(true)
}
map.setOnMarkerDragListener(this@SaveStateMapFragment)
map.setOnMarkerClickListener(this@SaveStateMapFragment)
if (mMoveCameraToMarker) {
map.animateCamera(CameraUpdateFactory.newLatLng(mMarkerPosition))
}
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// All Parcelable objects of the API (eg. LatLng, MarkerOptions, etc.) can be set
// directly in the given Bundle.
outState.putParcelable(MARKER_POSITION, mMarkerPosition)
// All other custom Parcelable objects must be wrapped in another Bundle. Indeed,
// failing to do so would throw a ClassNotFoundException. This is due to the fact that
// this Bundle is being parceled (losing its ClassLoader at this time) and unparceled
// later in a different ClassLoader.
val bundle = Bundle()
bundle.putParcelable(MARKER_INFO, mMarkerInfo)
outState.putBundle(OTHER_OPTIONS, bundle)
}
override fun onMarkerClick(marker: Marker): Boolean {
val newHue = MARKER_HUES[Random()
.nextInt(MARKER_HUES.size)]
mMarkerInfo.hue = newHue
marker.setIcon(BitmapDescriptorFactory.defaultMarker(newHue))
return true
}
override fun onMarkerDragStart(marker: Marker) {}
override fun onMarkerDrag(marker: Marker) {}
override fun onMarkerDragEnd(marker: Marker) {
mMarkerPosition = marker.position
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.save_state_demo)
}
companion object {
/** Default marker position when the activity is first created. */
private val DEFAULT_MARKER_POSITION = LatLng(48.858179, 2.294576)
/** List of hues to use for the marker */
private val MARKER_HUES = floatArrayOf(
BitmapDescriptorFactory.HUE_RED,
BitmapDescriptorFactory.HUE_ORANGE,
BitmapDescriptorFactory.HUE_YELLOW,
BitmapDescriptorFactory.HUE_GREEN,
BitmapDescriptorFactory.HUE_CYAN,
BitmapDescriptorFactory.HUE_AZURE,
BitmapDescriptorFactory.HUE_BLUE,
BitmapDescriptorFactory.HUE_VIOLET,
BitmapDescriptorFactory.HUE_MAGENTA,
BitmapDescriptorFactory.HUE_ROSE)
// Bundle keys.
private const val OTHER_OPTIONS = "options"
private const val MARKER_POSITION = "markerPosition"
private const val MARKER_INFO = "markerInfo"
}
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2012 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/instructions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/save_state_instructions" />
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.example.kotlindemos.SaveStateDemoActivity$SaveStateMapFragment" />
</LinearLayout>

View File

@ -310,4 +310,9 @@
<string name="retain_map_demo_label">Retain map</string>
<string name="retain_map_demo_description">Demonstrates how to reuse a MapFragment.</string>
<!-- Saved State -->
<string name="save_state_demo_label">Save the state of a MapFragment.</string>
<string name="save_state_demo_description">Demonstrates how to save the state of a MapFragment upon rotation of the device.</string>
<string name="save_state_instructions">Drag the marker, tap on it to change its color and rotate the device to check that the state of the map is preserved.</string>
</resources>