0

I want to convert 4.5 km to mile in depending on the user's location.
Is it possible in Android?

In iOS I can use something like

fileprivate let _distanceFormatter = 
MKDistanceFormatter()_distanceFormatter.string(fromDistance: model.distanse)
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
proft
  • 36
  • 3
  • 5
  • 1
    @Rotwang, why you edit my question? I know that I can convert it using some math. My main question is: is any existed solution in Android API? – proft Jul 06 '17 at 11:39
  • Read please my question carefully! I want only **reformat** distance depending on the user's location. Steps: check local, format distance. I don't want 'convert' for users from German! They don't know what is miles! – proft Jul 06 '17 at 11:42
  • I'm looking for DistanceFormat, like DateFormat in Java. – proft Jul 06 '17 at 11:48
  • There is no such a thing. You want to **convert** from a measurement unit to another one. It's a simple multiplication. Like inches to centimeters is 2.54 * inches. – Phantômaxx Jul 06 '17 at 12:34
  • 1
    No. I want format like SimpleDateFormat. I have base value from Google Map in km + I have user's locale = distance in user's locale. Do you use term "convert" when you reformat date via SimpleDateFormat? – proft Jul 06 '17 at 12:47
  • **Formatting** is simply a string repositioning/beautifying. But the value does not change. You actually want to **convert** the measurement units from Imperial to Metric (and/or vice-versa). Which requires a **calculation**. – Phantômaxx Jul 06 '17 at 12:51
  • Please look at http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/text/SimpleDateFormat.java#873 in jdk developers use "format" term instead of "convert" though there are for loop and etc. – proft Jul 06 '17 at 15:23
  • Yes, because a date doesn't need any conversion. Its value does not change whichever **format** you give it. But if you change measurement unit, you need a **conversion**. But maybe you live in a quantum-distortion where dates and measurements (i.e.: time and space) are similar and comparable. – Phantômaxx Jul 06 '17 at 15:27
  • BTW, I don't change base value. I just want represent distance in another way in depending of user's location. – proft Jul 06 '17 at 15:50
  • So... do you mean that you want to display 1 Mile as 1 Km?! Then simply use `string.replace()`. But... well, no comment. – Phantômaxx Jul 06 '17 at 15:51
  • I have a value in km format, I want to display it in another format (mile, feet, etc). I know iOS has a solution for it and it has name "MKDistanceFormatter". My question was if Android system has the same possibility. – proft Jul 06 '17 at 16:21
  • **WRONG**. You have a value in Km. You want to **convert** the value to another **mesurement unit** (which is not a "format"): Miles, feet, etc. I.e.: You have `1 Km` and you want to **convert** it to miles, which gives you `0,621371 Miles`. This is a **conversion**, not a **formatting**. Hope it is finally clear. – Phantômaxx Jul 07 '17 at 07:32
  • Developers from iOS (MKDistanceFormatter method) and from SimpleDateFormat (see link above) use term "format" and it's normal for other developers use the same vocabulary. Maybe you live in a quantum-distortion where there are another terminology. No real examples (links) from your side, just emotions. Finish. – proft Jul 07 '17 at 07:40
  • iOS developers use an IMPROPER terminology (due to the *genius* who called that component "MKDistance**Formatter**" - while it should have been called "MKDistance**Converter**"). And `SimpleDateFormatter`, as I already told you, is actually a **format** changer, because **no conversion occurs**. – Phantômaxx Jul 07 '17 at 08:03

3 Answers3

5

Is it possible in Android? YES

1 Km = 0.621371 Miles.

You can make a helper function from the above formula.

public float convertKmsToMiles(float kms){
    float miles = 0.621371 * kms;
    return miles;
}

Pass your Kms value to this function and you will get the Miles value for it. :)

float miles = convertKmsToMiles(4.5);
SripadRaj
  • 1,687
  • 2
  • 22
  • 33
  • Thanks! But read my question carefully! I want only **reformat** distance depending on the user's location. Steps: check local, format distance (maybe, there are some solution in Android API for all steps). I don't want 'convert' for users from German! They don't know what is miles! – proft Jul 06 '17 at 11:41
  • Oops! Sorry, i misunderstood your question. If that is the case, you can refer the link provided by @Andrea Ebano. :) – SripadRaj Jul 06 '17 at 12:09
0

I don't think there's necessarily a correct answer for all locales. For example, in the UK they generally use miles for large distances like a car journey, feet and inches for people's height but may use meters to describe the dimensions of a room.

You can try to do something like this: Using locale settings to detect wheter to use imperial units

or you can just give the user the option to choose a preferred unit in a settings menu.

Hope it helps.

Andrea Ebano
  • 563
  • 1
  • 4
  • 16
  • Thanks! I saw it. I don't want know anything about country or something else :). Just user locale. I thought there is prepared API for it like in iOS. – proft Jul 06 '17 at 12:50
0

My understanding is that OP wants to be able to convert a given distance to Miles or Kilo-meters depending on the user's location. For example if user is in America, the distance should be in Miles by default, not in Km nor Yard nor Ft, or if the user is in Europe the distance should be in Km by default, not anything else unless specified.

To answer OP question, you can use the Geocoder api to achieve what you're tryna do. Simply, get user location data,then use the Geocoder class/object to get the user's country name and finally you create a function to display/convert the distance.

Remember

  1. add this to your build.gradle (app module, not project module) so you can use location services

implementation 'com.google.android.gms:play-services-location:17.0.0'

  1. in order to get access to user gps data, you need a fusedLocationClient.

Here's how you could use it in this instance.

ExampleFragment.kt

class ExampleFragment : Fragment() {

private lateinit var fusedLocationClient: FusedLocationProviderClient
private lateinit var textView: TextView
private lateinit var geocoder: Geocoder

// test locations
val eiffelTower : Location = Location("et").apply {
    latitude = 48.858093
    longitude = 2.294694
}
val empireStateBulding : Location = Location("esb").apply {
    latitude = 40.748817
    longitude = -73.985428
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? {

    val root = inflater.inflate(R.layout.fragment_explore, container, false)

    textView = root.findViewById(R.id.text_home)

    /* Let's initialize the fused location client in order
    to get user location data via gps means */
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireActivity())

    // initialize the geocoder
    geocoder = Geocoder(requireContext())

    val button: Button = root.findViewById(R.id.button)
    button.setOnClickListener {
        getLocationData()
    }

    return root
}

private fun getLocationData() {
    /* get or check user's permission to so your app
    can have access to the user location */
    if (ActivityCompat.checkSelfPermission(requireActivity(),
            Manifest.permission.ACCESS_FINE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
        && ActivityCompat.checkSelfPermission(requireActivity(),
            Manifest.permission.ACCESS_COARSE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        /* if the above permissions are not granted
        we request them. Request code 101 is a random number. */
        ActivityCompat.requestPermissions(requireActivity(),
            arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION
            ), 101)
    }

  // get user current location from the client's and do some work.. 

    fusedLocationClient.lastLocation
        .addOnSuccessListener { currentLocation ->
            val currentCountryName = getCountryName(currentLocation)

            val distance: Int = currentLocation.distanceTo(eiffelTower).roundToInt()
            val distanceToDisplay = getDistanceToDisplay(currentCountryName, distance)

            val textToDisplay =
                """Distance to Eiffel Tower is: ${distanceToDisplay}
                    |Your current country is: ${currentCountryName}
                """.trimMargin()


            textView.text = textToDisplay

        }
}


private fun getCountryName(location: Location): String {
    /* the getFromLocation() provides a list of address,
    where we pick the first address item and
    return the countryName property or No found country if null */

    return geocoder.getFromLocation(location.latitude, location.longitude, 1)
            .first()
            .countryName ?: "No country found"

}

private fun getDistanceToDisplay(currentCountryName: String, distance: Int): String {
    // you can add more cases in here, these are for brevity

    return when (currentCountryName) {
        "France" -> " ${distance} meters"
        "USA", "United States" -> " ${distance / 1609} miles "
        else -> "Intl Unit : ${distance}m"
   }
}}

fragment_example.xml

 <?xml version="1.0" encoding="utf-8"?>
 <androidx.constraintlayout.widget.ConstraintLayout 
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=".ExampleFragment">

<TextView
    android:id="@+id/text_home"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:layout_marginEnd="8dp"
    android:lines="3"
    android:maxLines="4"
    android:textAlignment="center"
    android:textSize="20sp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Get my location"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/text_home" />
 </androidx.constraintlayout.widget.ConstraintLayout>

To test this out, I used the emulator GPS to select a country, and based on the country the distance will be displayed either in Miles or Km.

Example 1 Example 1

Example 2 Example 2

To learn more, refer to this Google API documentation on Location

Koch
  • 555
  • 4
  • 15