Creating a double array (not a multidimensional array)

Asked

Viewed 813 times

2

I need to pass two values of the kind double for a AsyncTask in my application. I tried to define an array using the following code:

double latitude = location.getLatitude();
double longitude = location.getLongitude();

double[] coords = {latitude, longitude};

That way, I was able to create the array. However, when it comes to recovering the values, I am not able to. I am passing to the AsyncTask as follows:

private class GeocoderTask extends AsyncTask<double[], Void, List<Address>>{
        ... códigos da task
}

... and trying to recover within the method doInBackground as follows:

        @Override
        protected List<Address> doInBackground(double[]... coords) {            
            Geocoder geocoder = new Geocoder(getBaseContext());
            List<Address> addresses = null;

            try {
                // Getting a maximum of 3 Address that matches the input text
                addresses = geocoder.getFromLocation(coords[0], coords[1], 1);
                } catch (IOException e) {
                e.printStackTrace();
            }
            return addresses;
        }

But it’s not working. What’s the right way to recover a value like this array? There’s another kind of array I can use that can store values like double?

  • Just index his first position, double[] coord = coords[0] and keeps everything as it is.

  • It didn’t work, the ADT accuses the following: The method getFromLocation(double, double, int) in the type Geocoder is not applicable for the arguments (double[], double[], int)

  • The problem is this, you need to set in a local variable the first position of the coords and then use it within that method as well

  • Something like this: double[] coord = coords[0]; double lat = coord[0]; double lng = coord[1];?

  • That, and then pass the coord pro getFromLocation also

  • I haven’t tried it yet, but at least I haven’t gotten a bug. Thank you!

Show 1 more comment

2 answers

3


When you create an Asynctask, the first parameter indicates which type of argument the InBackground method will receive as an array of arguments, using the Java varargs notation, so the reticence after the argument type (in the method declaration doInBackground).

Therefore, just pass the two parameters in the call of execute() and treat the argument as an array, and read positions 0 and 1. Note that you could pass as many arguments as you want or even a double array. Here’s what your subclass declaration would look like:

private class GeocoderTask extends AsyncTask<Double, Void, List<Address>>{
        ... códigos da task
}

It is necessary to use the Double wrapper type, as Asynctask expects an object as argument, not a primitive type.

To make the creation of Asynctask, at some point before you use it:

GeocoderTask task = new GeocoderTask<Double, Void, List<Address>>();
task.execute(latitude, longitude);

And in the method doInBackground:

@Override
protected List<Address> doInBackground(Double... coords) {            
    Geocoder geocoder = new Geocoder(getBaseContext());
    List<Address> addresses = null;

    try {
        // Getting a maximum of 3 Address that matches the input text
        addresses = geocoder.getFromLocation(coords[0], coords[1], 1);
    } catch (IOException e) {
        e.printStackTrace();
    }

    return addresses;
}

1

Assuming you already make use of version 2 of Google’s Maps API, the goal here is to show how to search by addresses or coordinates (available at source) using either Google’s API for Android or the online geolocation API (accessed through an HTTP request).

To do this, we will create a class that will have five other nested classes:

Geolocationsearch: This encapsulates the whole process. Geocodertask: This searches by address using API features for Android. Geocodertaskjson: This other one also searches by address, but using the external API (request). Geocodertasklatlng: This one searches for the address corresponding to a coordinate. Uses the API for Android. Geocodertasklatlngjson: It also searches for the address corresponding to a coordinate, but uses the external API. Local: This class serves as an entity for address data to be encapsulated into objects of the same. Within the Geolocationsearch class there is also an interface that will serve as an event at the time an address is found.

OnLocationSearchListener

Let’s go to structure...

The class starts as follows:

public class GeoLocationSearch
{
    private Context context;
    private OnLocationSearchListener onLocationSearchListener;

    public OnLocationSearchListener getOnLocationSearchListener() {
        return onLocationSearchListener;
    }

    public void setOnLocationSearchListener(OnLocationSearchListener onLocationSearchListener) {
        this.onLocationSearchListener = onLocationSearchListener;
    }

    public Context getContext() {
        return context;
    }

    public GeoLocationSearch(Context context)
    {
        this.context = context;
    }


Deve ser passado para ela o Context, pois  dentro dela existem chamadas de diálogos, e esses precisam de um contexto para serem exibidos.

Ela possui como atributo, um objeto da interface citada anteriormente, que servirá de evento quando um endereço for encontrado.

Abaixo, vemos a implementação dessa interface:

public  interface  OnLocationSearchListener{

    public void onLocationSearch(Local local);
}
Ou seja, caso você informe um listener, um método que escutará o evento, ele deve informar para esse  atributo (no fim isso ficará claro ). Com certeza você fará isso =)



Consulta por endereço

O objetivo da consulta por um endereço é saber a coordenada daquele endereço pesquisado e exibir um ponto no mapa.

NOTA:  Outra utilidade também é em formulários onde é necessário informar endereço. O usuário pode digitar apenas o CEP e você poderá realizar a busca passando esse CEP como se fosse um endereço. O Google encontra!!!
Para consultar por endereços ou coordenadas, você pode chamar um dos métodos abaixo:

public void searchByAddress(String address, int maxResult){

    new GeocoderTask(address,maxResult).execute();
}

public void searchByAddress(String address, int maxResult, OnLocationSearchListener onLocationSearchListener){

    setOnLocationSearchListener(onLocationSearchListener);
    new GeocoderTask(address,maxResult).execute();
}

public void searchByCoordenate(LatLng address){

    new GeocoderTaskLatLng().execute(address);
}

public void searchByCoordenate(LatLng address, OnLocationSearchListener onLocationSearchListener){

    setOnLocationSearchListener(onLocationSearchListener);
    new GeocoderTaskLatLng().execute(address);
}

NOTE: You will not use the classes that query by request the API external, because the Geolocationsearch class gives preference to the service available in the API for Android (using the Geocoder class).

It first calls the execution done by the Geocodertask class and if it does not find the address (because of network failure or for some other reason), it tries to request the external API (calling the execution of the other class).

Here is the implementation of this class:

private class GeocoderTask extends AsyncTask<Void, Void, List<Address>>
{
        //Máximo de resultados a serem retornados na pesquisa
    private int MAX_REQUESTS_RETURNS = 5;

    public GeocoderTask(String endereco){
        this.endereco = endereco;
    }

    public GeocoderTask(String endereco,int maxResult){

        MAX_REQUESTS_RETURNS = maxResult;
        this.endereco = endereco;
    }

    private String endereco;

    private ProgressDialog progressDialog;

    @Override
    public void onPreExecute(){

        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage(Html.fromHtml("Pesquisando...<br><b>" + endereco + "</b></br>"));
        progressDialog.show();
    }

    @Override
    protected List<Address> doInBackground(Void... args)
    {
                ///este objeto é o responsável pela busca
        Geocoder geocoder = new Geocoder(context);
                //esta lista irá armazenar o resultado da busca
        List<Address> addresses = null;

        try
        {
           addresses = geocoder.getFromLocationName(this.endereco, MAX_REQUESTS_RETURNS);
        }
        catch (IOException e)
        {
            Log.e("GEO_TASK",e.getMessage());
        }
        catch(Exception e)
        {
            Log.e("GEO_TASK",e.getMessage());
        }

                //retorna o que foi encontrado
                //se houver falha na rede ou algum outro tipo de falha, é retornado null
        return addresses;
    }

    @Override
    protected void onPostExecute(final List<Address> addresses)
    {

        progressDialog.dismiss();

                //nesse caso, tenta a pesquisa pela requisição da API externa
        if(addresses == null)
        {
            //Tenta pesquisar pelo JSon
            new GeocoderTaskJSon(endereco).execute();
            return;
        }

        if(addresses.size() == 0 )
        {

            Toast.makeText(context, "Não foi possível encontrar o endereço pesquisado", Toast.LENGTH_SHORT).show();
            return;
        }

        if(addresses.size() == 1)
        {
            //Retorna endereço pesquisado
            Local local = new Local();
            String cidade_estado_cep = (addresses.get(0).getMaxAddressLineIndex() > 0 ?
            addresses.get(0).getAddressLine(1) : "") + (addresses.get(0).getMaxAddressLineIndex() > 1 ? ", " + addresses.get(0).getAddressLine(2) : "");
            local.setDescricao(cidade_estado_cep);

            LatLng latLng = new LatLng(addresses.get(0).getLatitude(), addresses.get(0).getLongitude());
            local.setCoordenadas(latLng);
            local.setCidade_estado(addresses.get(0).getMaxAddressLineIndex() >= 0 ? addresses.get(0).getAddressLine(0) : "");

            //Retorna o endereço encontrado passando para o escutador
            if(onLocationSearchListener != null)
                onLocationSearchListener.onLocationSearch(local);
        }
        else
        {
                        //Quando mais de um endereço é encontrado (no caso de endereços de nome semelhantes)
                        //uma lista é exibida para o usuário escolher o endereço que deseja
            AlertDialog.Builder alert = new AlertDialog.Builder(context);
            alert.setTitle("Você quis dizer:");
            ListAdapter adapter = getAdapterSuggestions(addresses);
            alert.setAdapter(adapter, new DialogInterface.OnClickListener()
            {

                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    //Retonra endereço pesquisado
                    Local local = new Local();
                    String cidade_estado_cep = (addresses.get(0).getMaxAddressLineIndex() > 0 ?
                            addresses.get(0).getAddressLine(1) : "") + (addresses.get(0).getMaxAddressLineIndex() > 1 ? ", " + addresses.get(0).getAddressLine(2) : "");
                    local.setDescricao(cidade_estado_cep);

                    LatLng latLng = new LatLng(addresses.get(0).getLatitude(), addresses.get(0).getLongitude());
                    local.setCoordenadas(latLng);
                    local.setCidade_estado(addresses.get(0).getMaxAddressLineIndex() >= 0 ? addresses.get(0).getAddressLine(0) : "");

                    //Retorna o endereço encontrado passando para o escutador
                    if(onLocationSearchListener != null)
                        onLocationSearchListener.onLocationSearch(local);

                }
            });

            alert.create().show();
        }

    }

        // Retorna um adapter com os itens a serem exibidos para o usuário
    private ListAdapter getAdapterSuggestions(final List<Address> items)
    {
        ListAdapter adapter = new ArrayAdapter<Address>(context, R.layout.address_item, items)
        {

            ViewHolder holder;
            class ViewHolder
            {
                private TextView title;
                private TextView sub_title;

                public TextView getDescricao()
                {
                    return title;
                }
                public void setDescricao(TextView title) {
                    this.title = title;
                }
                public TextView getImagePin() {
                    return sub_title;
                }
                public void setSubTitle(TextView sub_title) {
                    this.sub_title = sub_title;
                }
            }

            public View getView(int position, View convertView, ViewGroup parent)
            {
                final LayoutInflater inflater = (LayoutInflater)context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

                if (convertView == null)
                {

                    convertView = inflater.inflate(R.layout.address_item, null);
                }
                holder = new ViewHolder();
                holder.setDescricao((TextView) convertView.findViewById(R.id.TextViewEndereco));
                holder.setSubTitle((TextView) convertView.findViewById(R.id.TextViewBairroMunEst));

                Address address = items.get(position);
                holder.getDescricao().setText(address.getMaxAddressLineIndex() >= 0 ? address.getAddressLine(0) : "");

                String cidade_estado_cep = (address.getMaxAddressLineIndex() > 0 ? address.getAddressLine(1) : "")
                        + (address.getMaxAddressLineIndex() > 1 ? ", " + address.getAddressLine(2) : "");

                holder.getImagePin().setText(cidade_estado_cep);

                return convertView;
            }
        };

        return adapter;
    }

}

This class is executed and at the end, in the onPostExecute method, it is checked if something has been returned. If it is not (null address list), it is called an execution of the class that does the query using the external API, as stated above.

Below, the implementation of the class that requests using the external API:

private class GeocoderTaskJSon extends AsyncTask<Void, Void, List<Local>>
{
    private int MAX_REQUESTS_RETURNS = 5;

    public GeocoderTaskJSon(String endereco){
        this.endereco = endereco;
    }

    public GeocoderTaskJSon(String endereco,int maxResult){

        MAX_REQUESTS_RETURNS = maxResult;
        this.endereco = endereco;
    }

    private String endereco;

    private ProgressDialog progressDialog;

    @Override
    public void onPreExecute(){

        progressDialog = new ProgressDialog(context);
        progressDialog.setMessage("Pesquisando...");
        progressDialog.show();
    }

    @Override
    protected List<Local> doInBackground(Void... args)
    {
        // POR LATITUDE
        List<Local> addresses = null;
        StringBuilder stringBuilder = new StringBuilder();

        try
        {
            String query_uri = String.format("https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=true",this.endereco).replace(" ", "%20");

            HttpGet httpGet = new HttpGet(query_uri);

            HttpClient client = new DefaultHttpClient();

            HttpResponse response = client.execute(httpGet);
            StatusLine placeSearchStatus = response.getStatusLine();

            //only carry on if response is OK
            if (placeSearchStatus.getStatusCode() == 200)
            {
                //get response entity
                HttpEntity placesEntity = response.getEntity();
                //get input stream setup
                InputStream placesContent = placesEntity.getContent();
                //create reader
                InputStreamReader placesInput = new InputStreamReader(placesContent);
                //use buffered reader to process
                BufferedReader placesReader = new BufferedReader(placesInput);
                //read a line at a time, append to string builder
                String lineIn;
                while ((lineIn = placesReader.readLine()) != null)
                {
                    stringBuilder.append(lineIn);
                }

                JSONObject jsonObject = new JSONObject(stringBuilder.toString());
                JSONArray results = (JSONArray)jsonObject.get("results");
                JSONArray components;
                if(results != null)
                {

                    addresses = new ArrayList<Local>();
                    String endereco, cidade_estado;
                    LatLng coord;
                    double lat,lng;
                    Local local;
                    int max = results.length();

                    for (int i = 0; i < max && i < MAX_REQUESTS_RETURNS; i++)
                    {
                        lng = results.getJSONObject(i)
                                .getJSONObject("geometry")
                                .getJSONObject("location")
                                .getDouble("lng");

                        lat = results.getJSONObject(i)
                                .getJSONObject("geometry")
                                .getJSONObject("location")
                                .getDouble("lat");

                        components = results.getJSONObject(i).getJSONArray("address_components");

                        //Verifica se é o número
                        int i_bairro = 1;
                        try
                        {
                            Double.parseDouble(components.getJSONObject(0).getString("long_name"));
                            i_bairro = 2;
                            endereco = components.getJSONObject(1).getString("long_name") + ", " + components.getJSONObject(0).getString("long_name");

                        }
                        catch (Exception e)
                        {
                            endereco = components.getJSONObject(0).getString("long_name");
                        }

                        endereco += " - " + components.getJSONObject(i_bairro).getString("long_name");

                        cidade_estado = components.getJSONObject(i_bairro + 1 ).getString("long_name");
                        cidade_estado += " - " + components.getJSONObject( i_bairro + 2).getString("short_name");
                        cidade_estado += ", " + components.getJSONObject(i_bairro + 4).getString("long_name");

                        coord = new LatLng(lat, lng);

                        local =  new Local();
                        local.setEndereco(endereco);
                        local.setCidade_estado(cidade_estado);
                        local.setCoordenadas(coord);

                        addresses.add(local);
                    }
                }
            }
        }
        catch (ClientProtocolException e)
        {
            Log.e("GEO_TASK", e.getMessage());
        }
        catch (JSONException e)
        {
            Log.e("GEO_TASK",e.getMessage());
        }
        catch (IOException e)
        {
            Log.e("GEO_TASK",e.getMessage());
        }
        catch(Exception e)
        {
            Log.e("GEO_TASK",e.getMessage());
        }

        return addresses;
    }

    @Override
    protected void onPostExecute(final List<Local> addresses)
    {
        progressDialog.dismiss();

        if(addresses == null)
        {
            Toast.makeText(context,"Falha na rede", Toast.LENGTH_LONG).show();
            return;
        }
        else if(addresses.size() == 0 )
        {
            Toast.makeText(context, "Não foi possível encontrar o endereço pesquisado", Toast.LENGTH_SHORT).show();
            return;
        }

        if(addresses.size() == 1)
        {

           //Retorna o endereço encontrado passando para o escutador
            if(onLocationSearchListener != null)
                onLocationSearchListener.onLocationSearch(addresses.get(0));
        }
        else
        {

            //Pede o usuário para selecionar um entre os encontrados
            AlertDialog.Builder alert = new AlertDialog.Builder(context);
            alert.setTitle("Você quis dizer:");
            ListAdapter adapter = getAdapterSuggestions(addresses);
            alert.setAdapter(adapter, new DialogInterface.OnClickListener()
            {

                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    Local address = addresses.get(which);
                    //Retorna o endereço encontrado passando para o escutador
                    if(onLocationSearchListener != null)
                        onLocationSearchListener.onLocationSearch(address);

                }
            });

            alert.create().show();
        }

    }

    private ListAdapter getAdapterSuggestions(final List<Local> items)
    {
        ListAdapter adapter = new ArrayAdapter<Local>(context, R.layout.address_item, items)
        {

            ViewHolder holder;
            class ViewHolder
            {
                private TextView title;
                private TextView sub_title;

                public TextView getDescricao()
                {
                    return title;
                }
                public void setDescricao(TextView title) {
                    this.title = title;
                }
                public TextView getImagePin() {
                    return sub_title;
                }
                public void setSubTitle(TextView sub_title) {
                    this.sub_title = sub_title;
                }
            }

            public View getView(int position, View convertView, ViewGroup parent)
            {
                final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

                if (convertView == null)
                {
                    convertView = inflater.inflate(R.layout.address_item, null);
                }

                holder = new ViewHolder();
                holder.setDescricao((TextView) convertView.findViewById(R.id.TextViewEndereco));
                holder.setSubTitle((TextView) convertView.findViewById(R.id.TextViewBairroMunEst));

                Local address = items.get(position);
                holder.getDescricao().setText(address.getEndereco());
                holder.getImagePin().setText(address.getCidade_estado());

                return convertView;
            }
        };

        return adapter;
    }
}
Basicamente, esta classe executa o mesmo procedimento feito pela classe GeocoderTask, porém utiliza outra fonte.



Como você pode ver, quando o endereço é retornado, um objeto da classe Local é instanciado e repassado ao evento, caso informado.



Exemplo de utilização da classe: 

GeoLocationSearch geoLocationSearch = new GeoLocationSearch(this);
geoLocationSearch.searchByAddress("Av. Cristiano Machado, 1682",10,new GeoLocationSearch.OnLocationSearchListener() {
    @Override
    public void onLocationSearch(GeoLocationSearch.Local local) {

        //Se houver algum resultado, ele será retornado aqui
                //Na chamada do método, informei que quero no máximo 10 resultados
    }
});

As you can see above, the functionality is given throughout this implementation, but the actual use of the resource is made in less than 10 lines of code :)

Here is the simple implementation of the Local class:

public class Local implements Serializable
{
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private String endereco;
    private String cidade_estado;
    private LatLng coordenadas;
    private String descricao;

    public String getEndereco() {
        return endereco;
    }
    public void setEndereco(String endereco) {
        this.endereco = endereco;
    }
    public LatLng getCoordenadas() {
        return coordenadas;
    }
    public void setCoordenadas(LatLng coordenadas) {
        this.coordenadas = coordenadas;
    }
    public String getCidade_estado() {
        return cidade_estado;
    }
    public void setCidade_estado(String cidade_estado) {
        this.cidade_estado = cidade_estado;
    }

    public String getDescricao() {
        return descricao;
    }
    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }

}
Para os itens que são exibidos para o usuário, no caso de mais de um endereço ser retornado, é utilizado o seguinte layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_margin="5dp"
    android:background="@android:drawable/list_selector_background"
    android:orientation="vertical"
    android:weightSum="1" >

    <TextView
        android:id="@+id/TextViewEndereco"
        style="?android:attr/spinnerItemStyle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:ellipsize="end"
        android:paddingLeft="5dp"
        android:paddingRight="5dp"
        android:paddingTop="5dp"
        android:singleLine="true"
        android:text="Av. Cristiano Machado, 1682"
        android:textSize="15sp"
        android:textStyle="bold" />

     <TextView
         android:id="@+id/TextViewBairroMunEst"
         style="?android:attr/spinnerItemStyle"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
         android:ellipsize="end"
         android:paddingBottom="5dp"
         android:paddingLeft="5dp"
         android:paddingRight="5dp"
         android:paddingTop="3dp"
         android:singleLine="true"
         android:text="Cidade Nova, Belo Horizonte -MG, Minas Gerais"
         android:textSize="14sp" />

</LinearLayout>



NOTA: Esse arquivo de layout deve ser inserido na pasta res/layout do seu projeto.

See the source to see how it is done with coordinates, that is, you pass a Latlng object and the class also searches for the address of that coordinate. In this case two other classes will be used at the beginning: Geocodertasklatlng and Geocodertasklatlngjson.

TIP: If you want to treat when an address is not returned, you can make the following modification:

  public  interface  OnLocationSearchListener{

        public void onLocationSearch(Local local);
        public void onNetworkFailed();
        public void onAddressNotFound();
    }

Thus, these two additional methods will be called in the appropriate situations, ie when there is network failure or when the address is not found. You must follow the same pattern by calling these methods where there is a Toast message call.

Link to the library updated and complete

Browser other questions tagged

You are not signed in. Login or sign up in order to post.