I would like to be able to create a path between two points by entering coordinates through two text fields and use the function I created, to create the path, using a button that takes the two coordinates entered as the end point.
when i try to insert the reference to the two text fields i have this error, how can i solve it?
my code is this below:
package uk.co.lorenzopulcinelli.trackapp
import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.os.StrictMode
import android.util.DisplayMetrics
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.res.ResourcesCompat
import androidx.preference.PreferenceManager
import com.google.android.material.textfield.TextInputEditText
import org.osmdroid.api.IMapController
import org.osmdroid.bonuspack.clustering.RadiusMarkerClusterer
import org.osmdroid.bonuspack.location.NominatimPOIProvider
import org.osmdroid.bonuspack.location.POI
import org.osmdroid.bonuspack.routing.OSRMRoadManager
import org.osmdroid.bonuspack.routing.Road
import org.osmdroid.bonuspack.routing.RoadManager
import org.osmdroid.bonuspack.routing.RoadNode
import org.osmdroid.bonuspack.utils.BonusPackHelper
import org.osmdroid.config.Configuration
import org.osmdroid.config.Configuration.*
import org.osmdroid.tileprovider.tilesource.TileSourceFactory
import org.osmdroid.util.GeoPoint
import org.osmdroid.views.CustomZoomButtonsController
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.compass.CompassOverlay
import org.osmdroid.views.overlay.compass.InternalCompassOrientationProvider
import org.osmdroid.views.overlay.*
import org.osmdroid.views.overlay.gestures.RotationGestureOverlay
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
import org.osmdroid.views.overlay.Marker
class MainActivity : AppCompatActivity() {
private lateinit var mapView : MapView
private lateinit var myLocationNewOverlay: MyLocationNewOverlay
private lateinit var compassOverlay: CompassOverlay
private lateinit var mapController: IMapController
private lateinit var road: Road
private lateinit var editTextLatitudine: TextInputEditText
private lateinit var editTextLongitudine: TextInputEditText
override fun onCreate(savedInstanceState: Bundle?) {
// disabilita la policy di strictMode nella onCreate per non fare chiamate network in async tasks
val policy: StrictMode.ThreadPolicy = StrictMode.ThreadPolicy.Builder().permitAll().build()
StrictMode.setThreadPolicy(policy)
super.onCreate(savedInstanceState)
//richiesta per gestire i permessi
requestPermission()
// inizializza la configurazione di osmdroid, non funziona se non si importa org.osmdroid.config.Configuration.*
getInstance().load(this, PreferenceManager.getDefaultSharedPreferences(this))
//crea la mappa
setContentView(R.layout.activity_main)
mapView = findViewById<MapView>(R.id.map)
mapView.setTileSource(TileSourceFactory.MAPNIK)
mapView.zoomController.setVisibility(CustomZoomButtonsController.Visibility.NEVER)
// crea MapController e setta posizione iniziale
mapController = mapView.controller
// crea overlay posizione
myLocationNewOverlay = MyLocationNewOverlay(GpsMyLocationProvider(this), mapView)
myLocationNewOverlay.enableMyLocation()
myLocationNewOverlay.enableMyLocation()
myLocationNewOverlay.isDrawAccuracyEnabled = true
myLocationNewOverlay.runOnFirstFix { runOnUiThread {
mapController.animateTo(myLocationNewOverlay.myLocation)
mapController.setZoom(9.0)
}
}
mapView.overlays.add(myLocationNewOverlay)
//set user agent
Configuration.getInstance().userAgentValue = "lolloMaps"
// controllo
println(myLocationNewOverlay.myLocation)
println("creato")
// attiva bussola, Non Funziona!
compassOverlay = CompassOverlay(this, InternalCompassOrientationProvider(this), mapView)
compassOverlay.enableCompass()
mapView.overlays.add(compassOverlay)
// attivare griglia latitudine e longitudine
// val overlay = LatLonGridlineOverlay2()
// mapView.overlays.add(overlay)
// abilita gesture rotazione e zoom
val rotationGestureOverlay = RotationGestureOverlay(mapView)
rotationGestureOverlay.isEnabled
mapView.setMultiTouchControls(true)
mapView.overlays.add(rotationGestureOverlay)
// abilita mia posizione
myLocationNewOverlay = MyLocationNewOverlay(GpsMyLocationProvider(this), mapView)
myLocationNewOverlay.enableMyLocation()
mapView.overlays.add(myLocationNewOverlay)
// abilita overlay scala
val dm : DisplayMetrics = resources.displayMetrics
val scaleBarOverlay = ScaleBarOverlay(mapView)
scaleBarOverlay.setCentred(true)
scaleBarOverlay.setScaleBarOffset(dm.widthPixels / 2, 10)
mapView.overlays.add(scaleBarOverlay)
val mapEventsReceiver: MapEventsReceiverImpl = MapEventsReceiverImpl()
val mapEventsOverlay: MapEventsOverlay = MapEventsOverlay(mapEventsReceiver)
mapView.overlays.add(mapEventsOverlay)
// traccia percorso tra i punti degli editText
editTextLatitudine = findViewById<TextInputEditText>(R.id.editTextLatitudine)
editTextLongitudine = findViewById<TextInputEditText>(R.id.editTextLongitudine)
val b = findViewById<Button>(R.id.location)
b.setOnClickListener{
Log.d("Percorso", "Premuto")
val lalati: Double = editTextLatitudine.text.toString().toDouble()
val lolong: Double = editTextLongitudine.text.toString().toDouble()
println("latitudine: $lolong, longitudine: $lalati")
routePath(22.22, 44.33, lolong, lalati)
}
// traccia percorso tra due punti
routePath(43.12628, 12.04705, 43.12124, 11.97211)
// inserisce POIs nella mappa
val startPoint1:GeoPoint = GeoPoint(43.12628, 12.04705)
val poiProvider: NominatimPOIProvider = NominatimPOIProvider("OSMBonusPackTutoUserAgent")
val pois: ArrayList<POI> = poiProvider.getPOICloseTo(startPoint1, "fuel", 50, 0.1)
val poisRoad: ArrayList<POI> = poiProvider.getPOIAlong(road.routeLow, "cinema", 50, 0.1)
val poiMarkers: FolderOverlay = FolderOverlay()
mapView.overlays.add(poiMarkers)
val poiIcon: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.marker_poi_default, null)
for (poi: POI in pois){
val poiMarker: Marker = Marker(mapView)
poiMarker.title = poi.mType
poiMarker.snippet = poi.mDescription
poiMarker.position = poi.mLocation
poiMarker.icon = poiIcon
/*if (poi.mThumbnail != null){
poiItem.setImage(BitmapDrawable(poi.mThumbnail))
}*/
poiMarkers.add(poiMarker)
mapView.invalidate()
}
for (poi: POI in poisRoad){
val rPoiMarker: Marker = Marker(mapView)
rPoiMarker.title = poi.mType
rPoiMarker.snippet = poi.mDescription
rPoiMarker.position = poi.mLocation
rPoiMarker.icon = poiIcon
/*if (poi.mThumbnail != null){
poiItem.setImage(BitmapDrawable(poi.mThumbnail))
}*/
poiMarkers.add(rPoiMarker)
mapView.invalidate()
}
// clustering markers
val radiusMarkerCluster: RadiusMarkerClusterer = RadiusMarkerClusterer(this)
val clusterIcon: Bitmap = BonusPackHelper.getBitmapFromVectorDrawable(this, R.drawable.marker_cluster)
radiusMarkerCluster.setIcon(clusterIcon)
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
//funzione per controllare se ho i permessi
private fun hasPermission() : Boolean {
// ritorna true quando abbiamo i permessi
return ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
//funzione per richiedere i permessi
private fun requestPermission() {
//aggiungo i permessi ad una lista
val permission = mutableListOf<String>()
// se non ho i permessi
if (!hasPermission()) {
// aggiungo i permesi alla lista
permission.add(Manifest.permission.ACCESS_FINE_LOCATION)
}
// concede i permessi nella lista
if (permission.isNotEmpty()) {
ActivityCompat.requestPermissions(this, permission.toTypedArray(), 0)
}
}
// funzione per aggiungere Marker
private fun mioMarker(lati: Double, longi: Double, i: Int) {
val pinMarker = Marker(mapView)
val geoPoint = GeoPoint(lati, longi)
pinMarker.position = geoPoint
pinMarker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_CENTER)
pinMarker.title = "Title"
pinMarker.subDescription = "io sono il pin #$i con coordinate $lati, $longi."
pinMarker.isDraggable = true
mapView.overlays.add(pinMarker)
mapView.invalidate()
}
// funzione per creare percorso fra due punti
private fun routePath(p1Latit: Double, p1Laong: Double, p2Latit: Double, p2Laong: Double){
println("inizio")
val roadManager:RoadManager = OSRMRoadManager(this, "lolloMaps")
OSRMRoadManager.MEAN_BY_FOOT
println("passo1 - creoArrayList")
val waypoints = arrayListOf<GeoPoint>()
println("passo2 - CreoPuntiEAggiungoInArrayList")
val startPoint: GeoPoint = GeoPoint(p1Latit, p1Laong) //43.12628, 12.04705
waypoints.add(startPoint)
val endPoint: GeoPoint = GeoPoint(p2Latit, p2Laong) //43.12124, 11.97211
waypoints.add(endPoint)
println("passo3 - CreoStrada")
road = roadManager.getRoad(waypoints)
if (road.mStatus != Road.STATUS_OK){
Toast.makeText(this, "Errore nel caricamento di road - status = " road.mStatus, Toast.LENGTH_SHORT).show()
}
println("passo4 - CreoPolilinea")
val roadOverlay: Polyline = RoadManager.buildRoadOverlay(road)
println("passo5 - AggiungoPolilineaAllaMappa")
mapView.overlays.add(roadOverlay)
mapView.invalidate()
// crea checkpoint lungo il percorso
val nodeIcon: Drawable? = ResourcesCompat.getDrawable(resources, R.drawable.marker_node, null)
for (i: Int in road.mNodes.indices){
val node: RoadNode = road.mNodes[i]
val nodeMarker: Marker = Marker(mapView)
nodeMarker.position = node.mLocation
nodeMarker.icon = nodeIcon
nodeMarker.title = "Passo $i"
mapView.overlays.add(nodeMarker)
// aggiunge informazioni nelle finestre dei checkpoint
nodeMarker.snippet = node.mInstructions
nodeMarker.subDescription = Road.getLengthDurationText(this,node.mLength, node.mDuration)
// var icon: Drawable = resources.getDrawable(R.drawable.ic_continue)
// nodeMarker.image = icon
}
}
}
this is my xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@ id/location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/location"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@ id/map" />
<EditText style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:id="@ id/editTextLatitudine"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:ems="10"
android:inputType="numberDecimal"
android:hint="@string/latitudine"
/>
<EditText style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:id="@ id/editTextLongitudine"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:ems="10"
android:inputType="numberDecimal"
android:hint="@string/longitudine"/>
</LinearLayout>
<org.osmdroid.views.MapView
android:id="@ id/map"
tilesource="Mapnik"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="-181dp"
tools:layout_editor_absoluteY="57dp">
</org.osmdroid.views.MapView>
</LinearLayout>
and this my gradle:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
}
android {
compileSdk 32
defaultConfig {
applicationId "uk.co.lorenzopulcinelli.trackapp"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.preference:preference:1.2.0' //aggiunta per utilizzare import androidx.preference.PreferenceManager
implementation 'com.google.android.gms:play-services-location:20.0.0' //aggiunta per richiedere permessi localizzazione
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.4.2'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
implementation files ('/home/acer/AndroidStudioProjects/TrackApp/app/libs/osmbonuspack_6.9.0.aar')
implementation files ('/home/acer/AndroidStudioProjects/TrackApp/app/libs/osmdroid-android-6.1.13.aar')
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
}
CodePudding user response:
A TextInputEditText
is (as the docs say):
A special sub-class of
EditText
designed for use as a child ofTextInputLayout
.Using this class allows us to display a hint in the IME when in 'extract' mode and provides accessibility support for
TextInputLayout
.
It's a special kind of EditText
that goes in a TextInputLayout
basically (which you're not using).
So a TextInputEditText
is an EditText
(because that's its superclass), but an EditText
is not a TextInputEditText
, in the same way an Integer
is a Number
, but a Number
is not an Integer
- and if you assume a Number
object is also an Integer
when it isn't, it'll crash when you cast it to that invalid type.
You're using plain EditText
s in your XML (technically AppCompatEditText
s like in the error, they're automatically converted and AppCompatEditText
is the superclass of TextInputEditText
- don't worry about it, basically). So when you do
findViewById<TextInputEditText>(R.id.editTextLatitudine)
The view with that ID is an EditText
and you're trying to cast it to a TextInputEditText
, which it ain't. Cast fails, you get a crash!
You're not even using a TextInputLayout
anyway, so you have no use for TextInputEditText
s. Just treat them as plain EditText
s in your code (which is what they are!) like in JustSightseeing's answer
CodePudding user response:
You cannot cast an editText to TextInputLayout. That is because they are different items with different types. Change these 2 lines of code:
private lateinit var editTextLatitudine: TextInputEditText
private lateinit var editTextLongitudine: TextInputEditText
and those 2:
// traccia percorso tra i punti degli editText
editTextLatitudine = findViewById<TextInputEditText>(R.id.editTextLatitudine)
editTextLongitudine = findViewById<TextInputEditText>(R.id.editTextLongitudine)
to:
// traccia percorso tra i punti degli editText
editTextLatitudine = findViewById<EditText>(R.id.editTextLatitudine)
editTextLongitudine = findViewById<EditText>(R.id.editTextLongitudine)
private lateinit var editTextLatitudine: EditText
private lateinit var editTextLongitudine: EditText
as shown here, AppCompatEditText extends EditText, so you just have to change the type of those and it should run