Android java GoogleMAP API を使用した、アプリ制作（ゴミ処理業者　検索アプリ）

### ■ UI

・郵便番号を入力
<img width="300" alt="夏目 智徹 android map app 01" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/fb497f97-7401-2491-533c-39a8aea68eb2.jpeg">
<br>
・入力された郵便番号の【5km】圏内で、CSVファイルで取得した業者の経度・緯度を計算して表示する。
<img width="300" alt="夏目智徹 android map app 02" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/41c20159-2017-8e73-e3cd-8e149f47c4bc.jpeg">

・入力された郵便番号の【10km】圏内で、CSVファイルで取得した業者の経度・緯度を計算して表示する。
<img width="300" alt="夏目 智徹 android map app 03" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/732a7bf4-322f-8ab1-4986-7168d3fa5692.jpeg">
<br>
・リストをタップしたら、マップ画面表示
<img width="300" alt="夏目 智徹 android map app 03" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478380/59c0e72d-d2c4-32ae-c428-eae000360b63.jpeg">

### ■ソースコード
```java MainActivity.java
package com.example.map_kensaku_app_01;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.gms.maps.model.LatLng;

import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.os.AsyncTask;
import android.os.Bundle;
import android.renderscript.ScriptGroup;
import android.text.InputType;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

public class MainActivity extends AppCompatActivity {

    private EditText editTextPostalCode;
    private Button buttonSearch;
    private ListView listViewLocations;
    private LocationAdapter locationAdapter;

    private List<LocationData> locationDataList;

    private List<LocationData> items;
    private int kensaku_i;
    private RadioButton RadioButtonB2;
    private ImageButton ImageButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        editTextPostalCode = findViewById(R.id.editTextPostalCode);
        buttonSearch = findViewById(R.id.buttonSearch);
        listViewLocations = findViewById(R.id.listViewLocations);


        locationAdapter = new LocationAdapter(this);
        listViewLocations.setAdapter(locationAdapter);

        // === エディットテキスト　数字入力設定
        editTextPostalCode.setInputType(InputType.TYPE_CLASS_NUMBER);

        /**
         *    // CSVファイルからデータを読み込む
         */
        locationDataList = loadLocationData();

        buttonSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // === 住所（入力された住所を取得）
                String postalCode = editTextPostalCode.getText().toString().trim();
                System.out.println("onclick ::: postalCode ::: 値 :::" + postalCode);

                if (!TextUtils.isEmpty(postalCode)) {
                    new GeocodeAsyncTask().execute(postalCode);
                } else {
                    Toast.makeText(MainActivity.this, "郵便番号を入力してください", Toast.LENGTH_SHORT).show();
                }
            }
        });


        /**
         *  リストビュー
         */
        listViewLocations.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                // クリックした位置の情報を取得する
                LocationData clickedLocation = (LocationData) locationAdapter.getItem(position);

                Double ido = clickedLocation.getLatitude(); // 緯度
                Double keido = clickedLocation.getLongitude(); // 経度取得

                // === マップへ飛ばす
                openMapActivity(ido, keido);

               //Toast.makeText(MainActivity.this, "クリックOK" + clickedLocation.getFacilityName(), Toast.LENGTH_SHORT).show();

            }
        });



        /**
         *  ========= ラジオボタン （検索範囲を、何キロにするかをきめる　デフォルト 3km） =========
         */

        RadioGroup radioGroup = (RadioGroup) findViewById(R.id.RadioGroupB);
        RadioButton radioButton2 = (RadioButton) findViewById(R.id.RadioButtonB2);

        // === 初期値　取得
        RadioButtonB2 = findViewById(R.id.RadioButtonB2);
        String tmp_radio = (String) RadioButtonB2.getText();
        kensaku_i = Str_replace_int(tmp_radio, "km");

        // ラジオグループのチェック状態が変更された時に呼び出されるコールバックリスナーを登録します
        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                RadioButton radioButton = (RadioButton) findViewById(checkedId);

                String tmp_radio = (String) radioButton.getText();
                kensaku_i = Str_replace_int(tmp_radio, "km");

            }
        });

        // 指定した ID のラジオボタンをチェックします
        radioButton2.setChecked(true);

    }

    private List<LocationData> loadLocationData() {
        List<LocationData> dataList = new ArrayList<>();

        try {
            InputStream inputStream = getResources().openRawResource(R.raw.location_data);
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            Integer count = 1;
            while ((line = reader.readLine()) != null) {
                String[] data = line.split(",");
                if (data.length >= 3) {
                    String facilityName = data[0];
                    String zyuusyo = data[1];
                    double latitude = Double.parseDouble(data[2]); // 緯度
                    double longitude = Double.parseDouble(data[3]); // 経度

                    System.out.println("loadLocationData => facilityName:::" + count + "行データ:::" + facilityName + ":::latitude:::" +
                            latitude + ":::latitude:::" + latitude);

                    // === 行数カウント
                    count++;

                    LocationData locationData = new LocationData(facilityName, latitude, longitude, zyuusyo);
                    dataList.add(locationData);
                }
            }

            reader.close();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return dataList;
    }

    private class GeocodeAsyncTask extends AsyncTask<String, Void, LatLng> {

        @Override
        protected LatLng doInBackground(String... params) {
            String postalCode = params[0];
            double latitude = 0.0, longitude = 0.0;

            System.out.println("doInBackground ::: postalCode 値 :::" + postalCode);

            // === 郵便番号を座標へ変換
            LatLng location = getLocationFromAddress(postalCode);
            System.out.println("doInBackgroundlocation ::: 値 :::" + location);

            String location_tmp = location.toString();
            String start = "(";
            String end = ",";

            String start_02 = ",";
            String end_02 = ")";

            String location_lat = Substring(location_tmp, start, end);
            String location_lon = Substring(location_tmp, start_02, end_02);

            double location_lat_d = Double.parseDouble(location_lat);
            double location_lon_d = Double.parseDouble(location_lon);

            latitude = location_lat_d;  // 緯度
            longitude = location_lon_d; // 経度


            return new LatLng(latitude, longitude);
        }

        @Override
        protected void onPostExecute(LatLng latLng) {
            if (latLng == null) {
                Toast.makeText(MainActivity.this, "該当する場所が見つかりませんでした", Toast.LENGTH_SHORT).show();
            } else {
                List<LocationData> filteredList = new ArrayList<>();

                Location location1 = new Location("");
                location1.setLatitude(latLng.latitude);
                location1.setLongitude(latLng.longitude);

                System.out.println("onPostExecute ::: ********* location1 ********* latLng.latitude:::値:::" + latLng.latitude);
                System.out.println("onPostExecute ::: ********* location1 ********* latLng.longitude:::値:::" + latLng.longitude);

                for (LocationData data : locationDataList) {
                    Location location2 = new Location("");
                    location2.setLatitude(data.getLatitude());
                    location2.setLongitude(data.getLongitude());

                    System.out.println("onPostExecute :::location2 data.getLatitude:::値:::" + data.getLatitude());
                    System.out.println("onPostExecute :::location2 data.getLongitude:::値:::" + data.getLongitude());

                    System.out.println("onPostExecute ::: ********* location2 ********* :::値:::" + location2);

                    float distance = location1.distanceTo(location2) / 1000; // メートルをキロメートルに変換

                    System.out.println("onPostExecute distance 値:::" + distance);

                    /**
                     *   kensaku_i => デフォルト値 ３キロ
                     *   === distance <= 3    ３キロ以内
                     */
                    if (distance <= kensaku_i) {
                        filteredList.add(data);
                    }
                }

                if (filteredList.isEmpty()) {
                    Toast.makeText(MainActivity.this, "半径3km以内の施設が見つかりませんでした", Toast.LENGTH_SHORT).show();
                } else {
                    locationAdapter.setLocationDataList(filteredList);
                    locationAdapter.notifyDataSetChanged();
                }
            }
        }
    }

    /**
     *   住所から座標を取得
     */
    private LatLng getLocationFromAddress(String strAddress) {
        Geocoder coder = new Geocoder(this);
        List<Address> addressList;
        LatLng location = null;

        try {
            addressList = coder.getFromLocationName(strAddress, 1);
            if (addressList != null && !addressList.isEmpty()) {
                Address address = addressList.get(0);
                double latitude = address.getLatitude();
                double longitude = address.getLongitude();
                location = new LatLng(latitude, longitude);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return location;
    }

    /**
     *    開始文字と、終了文字を指定して、その間の文字列を取得
     *
     */
    public static String Substring(String all_str, String start, String end) {

        int startIndex = all_str.indexOf(start);
        System.out.println("startIndex:::" + startIndex); // 5

        int endIndex = all_str.indexOf(end, startIndex + start.length());

        System.out.println("endIndex:::" + endIndex); // 12
        System.out.println("start.length():::" + start.length()); // 1

        return all_str.substring(startIndex + start.length(), endIndex);

    }

    private void openMapActivity(double latitude, double longitude) {
        Intent intent = new Intent(MainActivity.this, MapActivity.class);
        intent.putExtra("latitude", latitude);
        intent.putExtra("longitude", longitude);
        startActivity(intent);
    }

    /**
     *  文字列を空白に置換して、integer型に変換する。
     */
    public int Str_replace_int(String str, String cut) {

        String result_str = str.replace(cut, "");

        int result_num = Integer.parseInt(result_str);
        return result_num;

    }


}

```java LocationAdapter.java

package com.example.map_kensaku_app_01;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;

/**
 *  リストビュー　用　アダプター
 */
public class LocationAdapter extends BaseAdapter {

    private Context context;
    private List<LocationData> locationDataList;

    public LocationAdapter(Context context) {
        this.context = context;
        this.locationDataList = new ArrayList<>();
    }

    public void setLocationDataList(List<LocationData> locationDataList) {
        this.locationDataList = locationDataList;
    }

    @Override
    public int getCount(){
        return locationDataList.size();
    }

    @Override
    public Object getItem(int position) {
        return locationDataList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ViewHolder viewHolder;

        if(convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.item_location, parent, false);

            viewHolder = new ViewHolder();
            viewHolder.textViewName = convertView.findViewById(R.id.textViewName);
            viewHolder.textViewLatitude = convertView.findViewById(R.id.textViewLatitude);
            viewHolder.textViewLongitude = convertView.findViewById(R.id.textViewLongitude);
            viewHolder.textView_addres = convertView.findViewById(R.id.textView_addres);

            // 地図アイコン ボタン
            viewHolder.list_image_icon = convertView.findViewById(R.id.list_image_icon);

            convertView.setTag(viewHolder);

        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        LocationData locationData = locationDataList.get(position);

        // === 値をセット
        viewHolder.textViewName.setText(locationData.getFacilityName());
        viewHolder.textViewLatitude.setText("●緯度：" + String.valueOf(locationData.getLatitude()));
        viewHolder.textViewLongitude.setText("●経度：" + String.valueOf(locationData.getLongitude()));

        viewHolder.textView_addres.setText(locationData.getZyuusyo()); // === 住所

        viewHolder.list_image_icon.setText("");

        return convertView;
    }

    private static class ViewHolder {
        TextView textViewName;
        TextView textViewLatitude;
        TextView textViewLongitude;
        TextView textView_addres; // 住所

        TextView list_image_icon;
    }



}

```

```xml activity_main.xml

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:background="#F9F4F5"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".MainActivity">


    <androidx.cardview.widget.CardView
        android:id="@+id/card_view_01"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="8dp"
        card_view:cardElevation="8dp"
        card_view:cardCornerRadius="4dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        >

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="3dp"
            >


            <!--  何キロか範囲を指定するラジオボタン -->
            <RadioGroup
                android:id="@+id/RadioGroupB"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:layout_marginLeft="16dp"
                android:layout_marginRight="16dp"
                android:orientation="horizontal"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                >
                <RadioButton
                    android:text="3km"
                    android:id="@+id/RadioButtonB1"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/btn_radio_left"
                    android:textColor="@drawable/btn_radio_textcolor"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center">
                </RadioButton>
                <RadioButton
                    android:text="5km"
                    android:id="@+id/RadioButtonB2"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/btn_radio_center"
                    android:textColor="@drawable/btn_radio_textcolor"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center">
                </RadioButton>
                <RadioButton
                    android:text="10km"
                    android:id="@+id/RadioButtonB3"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/btn_radio_center"
                    android:textColor="@drawable/btn_radio_textcolor"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center">
                </RadioButton>
                <RadioButton
                    android:text="100km"
                    android:id="@+id/RadioButtonB4"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/btn_radio_right"
                    android:textColor="@drawable/btn_radio_textcolor"
                    android:layout_weight="1"
                    android:button="@null"
                    android:gravity="center">
                </RadioButton>
            </RadioGroup>


            <com.google.android.material.textfield.TextInputLayout
        android:id="@+id/editTextPostalCode_box"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toBottomOf="@+id/RadioGroupB"
        app:layout_constraintLeft_toLeftOf="parent"
        android:layout_marginTop="35dp"
        app:errorEnabled="true"
        app:counterEnabled="true"
        app:counterMaxLength="7"
        app:hintEnabled="true"
        app:hintAnimationEnabled="true"
        android:paddingHorizontal="30dp"
        app:boxStrokeColor="#ffffff"
        >

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/editTextPostalCode"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="郵便番号を入力してください。（-ハイフンは無し）"
            android:imeOptions="actionDone"
            android:inputType="textEmailAddress"
            android:maxLength="7"
            android:maxLines="1"
            android:textSize="15sp"
            android:letterSpacing="0.2"
            />

    </com.google.android.material.textfield.TextInputLayout>



    <com.google.android.material.button.MaterialButton
        android:id="@+id/buttonSearch"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_gravity="bottom"
        android:text="検索"
        android:textAppearance="@style/TextAppearance.MaterialComponents.Button"
        app:backgroundTint="#2979ff"
        app:cornerRadius="9dp"
        android:layout_marginHorizontal="52dp"
        android:layout_marginTop="25dp"
        android:textSize="15.5dp"
        android:letterSpacing="0.2"
        app:layout_constraintTop_toBottomOf="@+id/editTextPostalCode_box"
        app:layout_constraintLeft_toLeftOf="parent"
        />



        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

    <ListView
        android:id="@+id/listViewLocations"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="295dp"
        app:layout_constraintTop_toBottomOf="@+id/card_view_01"
        app:layout_constraintLeft_toLeftOf="parent"
        />

</androidx.constraintlayout.widget.ConstraintLayout>


```

```xml activity_map.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapActivity">

    <fragment
        android:id="@+id/map_fragment"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>


```