■ UI
・郵便番号を入力
・入力された郵便番号の【5km】圏内で、CSVファイルで取得した業者の経度・緯度を計算して表示する。
・入力された郵便番号の【10km】圏内で、CSVファイルで取得した業者の経度・緯度を計算して表示する。
・リストをタップしたら、マップ画面表示
■ソースコード
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 => デフォルト値 3キロ
* === distance <= 3 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>