0

I have an app that displays a ListView with Cards, and these cards have already the latitude and longitude information. I need to show in each card the address of that location. First i was calling Geocoder directly in each card and it really works, but the app takes a long time to answer. So I read the documentation and it recommends:

you should not call it from the main, user interface (UI) thread of your app

So it recommends to create a service and use the Geocoder there. The problem is that i can't implement the suggested code to each card (elements of the ListView). My code is the following. I have a FeaturesFragment:

@Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
        View myView = inflater.inflate(R.layout.features_layout, container, false);

        // Used to operate the database
        PhotoDAO photoDAO = new PhotoDAO(getActivity());
        //Receives the cursor with the result of the search
        final Cursor cursor = photoDAO.searchAll();

        // list that shows the items. Cards are set into the adapter
        ListView listView = (ListView) myView.findViewById(R.id.list);
        PhotoAdapter adapter = new PhotoAdapter(getActivity(), cursor);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                String description = cursor.getString(cursor.getColumnIndexOrThrow(PhotoContract.PhotoEntry.COLUMN_PHOTO_DESCRIPTION));
                String path = cursor.getString(cursor.getColumnIndexOrThrow(PhotoContract.PhotoEntry.COLUMN_PHOTO_PATH));
                Long id_photo = cursor.getLong(cursor.getColumnIndexOrThrow(PhotoContract.PhotoEntry._ID));

                Log.v(TAG, path);
                Intent i = new Intent(getActivity(), PhotoDescriptionActivity.class);
                i.putExtra("id", id_photo);
                i.putExtra("path", path);
                i.putExtra("description", description);
                startActivity(i);
            }
        });

        return myView;
    }

I'm using a custon CursorAdapter called PhotoAdapter that is: (the commented part is the old geocoder code)

@Override
    public void bindView(View view, Context context, Cursor cursor) {

        // First, select the category to show on the card
        int id_cat = cursor.getInt(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_ID_CATEGORY));
        CategoryDAO categoryDAO = new CategoryDAO(context);
        Category category = categoryDAO.search(String.valueOf(id_cat));

        // Get the object located at this position in the list
        String path = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_PATH));
        String description = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_DESCRIPTION));
        String time = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_TIME));
        Double latitude = cursor.getDouble(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_LATITUDE));
        Double longitude = cursor.getDouble(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_LONGITUDE));
        Date dt = FormatDateTimeUtil.stringToDate(time, FormatDateTimeUtil.FORMAT_DATE);

        TextView txtCategory = (TextView) view.findViewById(R.id.text_category);
        ImageView imageResource = (ImageView) view.findViewById(R.id.photo_card);
        ExpandableTextView txtDescription = (ExpandableTextView) view.findViewById(R.id.expand_text_view);
        TextView txtTime = (TextView) view.findViewById(R.id.text_time);
        TextView txtCity = (TextView) view.findViewById(R.id.text_city);

        String cidade;
        String estado;
        String pais;

        /*Geocoder gcd = new Geocoder(context, Locale.getDefault());
        try {
            List<Address> add = gcd.getFromLocation(latitude, longitude, 1);

            if (add.size() > 0) {
                cidade = add.get(0).getLocality();
                estado = add.get(0).getAdminArea();
                pais = add.get(0).getCountryName();

                txtCity.setText(cidade+", "+estado+". "+pais);
            } else {
                txtCity.setText(R.string.location_unknown);
            }


        } catch (IOException e) {
            Log.e(TAG, "It wasn't possible to get location");
            e.printStackTrace();
        }*/

        //controls the heap to load images, preventing a memory overload
        Glide.with(context).load(path).into(imageResource);
        txtDescription.setText(description);

        txtTime.setText(FormatDateTimeUtil.dateToString(dt));

        txtCategory.setText(category.getDescription());

    }

So how can I use the service in each element of the ListView? Or is there some other way to get these locations?

1 Answers1

1

I fixed the problem by using a GeocoderHandler and other thread like this:

PhotoAdapter

public void bindView(View view, Context ctx, Cursor cursor) {

    final Context context = ctx;

    appLocationService = new AppLocationService(
            context);

    // First, select the category to show on the card
    int id_cat = cursor.getInt(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_ID_CATEGORY));
    CategoryDAO categoryDAO = new CategoryDAO(context);
    Category category = categoryDAO.search(String.valueOf(id_cat));

    // Get the object located at this position in the list
    final String id = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry._ID));
    final String path = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_PATH));
    final String description = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_DESCRIPTION));
    final String time = cursor.getString(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_TIME));
    final Double latitude = cursor.getDouble(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_LATITUDE));
    final Double longitude = cursor.getDouble(cursor.getColumnIndexOrThrow(PhotoEntry.COLUMN_PHOTO_LONGITUDE));

    Date dt = FormatDateTimeUtil.stringToDate(time, FormatDateTimeUtil.FORMAT_DATE);

    TextView txtCategory = (TextView) view.findViewById(R.id.text_category);
    ImageView imageResource = (ImageView) view.findViewById(R.id.photo_card);
    ExpandableTextView txtDescription = (ExpandableTextView) view.findViewById(R.id.expand_text_view);
    TextView txtTime = (TextView) view.findViewById(R.id.text_time);
    txtCity = (TextView) view.findViewById(R.id.text_city);

    //controls the heap to load images, preventing a memory overload
    Glide.with(context).load(path).into(imageResource);
    txtDescription.setText(description);
    txtTime.setText(FormatDateTimeUtil.dateToString(dt));
    txtCategory.setText(category.getDescription());

    LocationAddress locationAddress = new LocationAddress();
    locationAddress.getAddressFromLocation(latitude, longitude,
            getApplicationContext(), new GeocoderHandler());


    imageResource.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent i = new Intent(v.getContext(), PhotoDescriptionActivity.class);
            i.putExtra("id", id);
            i.putExtra("path", path);
            i.putExtra("description", description);
            v.getContext().startActivity(i);
        }
    });
}

private class GeocoderHandler extends Handler {
    @Override
    public void handleMessage(Message message) {
        String locationAddress;
        switch (message.what) {
            case 1:
                Bundle bundle = message.getData();
                locationAddress = bundle.getString("address");
                break;
            default:
                locationAddress = null;
        }
        txtCity.setText(locationAddress);
    }
}

In my FeaturesFragment I just removed the clicklistener because it had to be moved to PhotoAdapter. Using the GeocoderHandler for each card the location is loaded in background, not hindering the user interface. As reference, i used the answer of EricLarch in this link