Creating an array of type double (not a multidimensional array)

2

I need to pass two values of type double to 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};

In this way, I was able to create the array . However, at the time of recovering the values, I am not achieved. I'm moving to AsyncTask as follows:

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

... and trying to recover within the doInBackground method 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 is not working. What is the correct way to recover a value from this array ? Is there another type of array that I can use that can store values of type double ?

    
asked by anonymous 23.06.2014 / 21:26

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 varargs notation of Java, so the reticence after the argument type (in the method declaration doInBackground ).

So you just pass the two parameters in the execute() call and treat the argument as an array, and read positions 0 and 1. Note that you could pass as many arguments as you wish or even an array of type Double. Here's what your subclass statement would look like:

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

You need to use the Double wrapper type because AsyncTask expects an object as an argument, not a primitive type.

To create AsyncTask, at some point before you use it:

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

And in the doInBackground method:

@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;
}
    
24.06.2014 / 08:34
1

Assuming you're already using version 2 of the Google Maps API, the goal here is to show you how to search by addresses or coordinates (available in the source) using Google's APIs, both from the Android API or from Online geolocation API (accessed through an HTTP request).

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

GeoLocationSearch: This encapsulates the entire process.   GeocoderTask: This searches for address using Android API features. GeocoderTaskJSon: This one also does the address search, but using the external API (request). GeocoderTaskLatLng: This looks for the address corresponding to a coordinate. Use the API for Android. GeocoderTaskLatLngJSon: This also searches for the address corresponding to a coordinate, but uses the external API. Location: This class serves as an entity for the address data to be encapsulated in 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 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 search by API request   because the GeoLocationSearch class gives preference to the   available in the Android API (using the Geocoder class).

It first calls the execution made by the class GeocoderTask and if it does not find the address (due to network failure or 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 whether something has been returned. If it is not (null list of addresses), it is called an execution of the class that makes the query using the external API, as stated above.

Below is the implementation of the class that makes the request 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 takes place throughout this implementation, but the feature itself is used 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: GeocoderTaskLatLng and GeocoderTaskLatLngJson.

  

TIP: If you want to handle 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 due situations, ie when the network fails or when the address is not found. You must follow the same pattern by calling these methods where a Toast message call exists.

Link to the updated and complete library

    
28.06.2014 / 04:10