Android Studio使用ArcGIS Runtime SDK for Android做地图软件
基础版,完整版在完成
需要准备的内容(本项目不提供数据,以及运行截图)
地图文件:.shx .shp .dbf .prj
文本文件 .dbf 转.txt 本项目使用名字是data
1、下载ArcGIS Runtime SDK for Android
链接如下:下载v100.15.5
https://developers.arcgis.com/android/downloads/
选择Download(107 MB);
2、创建项目
打开Android studio
选择New Project
选择No Activity
写项目名字,路径,包名,语言,SDK,build configuration language
本项目的SDK:API 24(“Nougat”; Android 7.0)
本项目语言:Java
本项目build configuration language:Groovy DSL (build.gradle)
本项目名称为:testApplication
本项目包名为:com.test.testApplication
提示:下面的MyApplication是演示作用
点击finish,等待加载完成,这个是默认目录
在app目录下,也就是和src同级创建libs
3、导入到libs
下载完成后打开压缩包里面应该有一下文件
打开libs/aar 把里面的内容解压出来
解压后,把这两个文件粘贴到项目文件的libs中
4、配置文件(加载ArcGIS Runtime SDK for Android)
打开app下的build.gradle修改以下内容(不要打开项目级别的)
//修改后
plugins {
alias(libs.plugins.android.application)
}
android {
namespace 'com.test.myapplication'
compileSdk 34
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
defaultConfig {
applicationId "com.test.testApplication"
minSdk 23
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
android.applicationVariants.all {
variant ->
variant.outputs.all {
outputFileName = "test.apk"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
sourceSets{
main{
jniLibs.srcDirs = ['libs']
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation 'com.esri.arcgisruntime:arcgis-android:100.15.5'
implementation 'org.osmdroid:osmdroid-android:6.1.11'
implementation 'androidx.annotation:annotation:1.8.0';
implementation libs.appcompat
implementation libs.material
implementation libs.play.services.maps
implementation libs.annotation.jvm
testImplementation libs.junit
androidTestImplementation libs.ext.junit
androidTestImplementation libs.espresso.core
}
打开项目级别的settings.gradle
//修改后的
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
jcenter()
maven { url = uri("https://esri.jfrog.io/artifactory/arcgis") }
}
}
rootProject.name = "Test Application"
include ':app'
5、创建asserts文件夹
本文件夹应该与res同级
本文件夹放入的是地图文件
6、创建layout文件夹和raw文件
两个文件夹都应当在res文件夹下
raw 文件的内容
应该有一个data.txt的文件
layout文件夹下的内容
index.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.esri.arcgisruntime.mapping.view.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"></com.esri.arcgisruntime.mapping.view.MapView>
<Button
android:id="@+id/shrink"
android:layout_width="48dp"
android:layout_height="58dp"
android:text="-"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.435" />
<Button
android:id="@+id/magnify"
android:layout_width="48dp"
android:layout_height="58dp"
android:text="+"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.931"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.325" />
<EditText
android:id="@+id/editTextText"
android:layout_width="379dp"
android:layout_height="55dp"
android:background="#ffffff"
android:ems="10"
android:padding="15dp"
android:hint="请输入地名"
android:inputType="text"
android:rotationX="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.023" />
<Button
android:id="@+id/Attribute_queries"
android:layout_width="150dp"
android:layout_height="50dp"
android:onClick="Attribute_queries"
android:text="属性查询"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.05"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.976" />
<Button
android:id="@+id/Load_layer"
android:layout_width="150dp"
android:layout_height="50dp"
android:text="加载矢量图层"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.943"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.976" />
</androidx.constraintlayout.widget.ConstraintLayout>
input_select.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/return_button1"
android:layout_width="91dp"
android:layout_height="49dp"
android:text="首页"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.115"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.054" />
<Button
android:id="@+id/submit_button1"
android:layout_width="100dp"
android:layout_height="60dp"
android:text="提交"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.879" />
<Button
android:id="@+id/select_button"
android:layout_width="100dp"
android:layout_height="60dp"
android:text="选择输入"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.769" />
<EditText
android:id="@+id/editTextText2"
android:layout_width="327dp"
android:layout_height="44dp"
android:ems="10"
android:hint="请输入列名"
android:inputType="text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.511"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.189" />
<EditText
android:id="@+id/editTextText3"
android:layout_width="328dp"
android:layout_height="49dp"
android:ems="10"
android:hint="请输入列值"
android:inputType="text"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.506"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.329" />
</androidx.constraintlayout.widget.ConstraintLayout>
attribute_select.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Spinner
android:id="@+id/value_spinner"
android:layout_width="337dp"
android:layout_height="57dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.391" />
<TextView
android:id="@+id/textView"
android:layout_width="267dp"
android:layout_height="37dp"
android:text="请选择列名"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.256"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.188" />
<Spinner
android:id="@+id/line_spinner"
android:layout_width="337dp"
android:layout_height="57dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.232" />
<TextView
android:id="@+id/textView2"
android:layout_width="267dp"
android:layout_height="37dp"
android:text="请选择值"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.256"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.342" />
<Button
android:id="@+id/return_button"
android:layout_width="91dp"
android:layout_height="49dp"
android:text="返回"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.115"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.054" />
<Button
android:id="@+id/submit_button"
android:layout_width="100dp"
android:layout_height="60dp"
android:text="提交"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.879" />
<Button
android:id="@+id/input_button"
android:layout_width="100dp"
android:layout_height="60dp"
android:text="直接输入"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.769" />
</androidx.constraintlayout.widget.ConstraintLayout>
7、创建Java类
Main类
package com.test.testApplication;
import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ShapefileFeatureTable;
import com.esri.arcgisruntime.geometry.Envelope;
import com.esri.arcgisruntime.geometry.GeometryEngine;
import com.esri.arcgisruntime.layers.FeatureLayer;
import com.esri.arcgisruntime.mapping.ArcGISMap;
import com.esri.arcgisruntime.mapping.view.BackgroundGrid;
import com.esri.arcgisruntime.mapping.view.MapView;
import com.esri.arcgisruntime.symbology.SimpleFillSymbol;
import com.esri.arcgisruntime.symbology.SimpleLineSymbol;
import com.esri.arcgisruntime.symbology.SimpleRenderer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
public class Main extends AppCompatActivity {
private static final String TAG = "MainActivity";
private MapView mapView; // 地图视图组件
private FeatureLayer mFeatureLayer; // 要素图层
// 需要检查的文件列表(实际只需要.shx .shp .dbf .prj)
private final List<String> filesToCheck = Arrays.asList(
"测试数据.shp",
"测试数据.shp.xml",
"测试数据.shx",
"测试数据.dbf",
"测试数据.prj",
"测试数据.shp.DESKTOP-AVS74CA.17660.18312.sr.lock",
"测试数据.cpg",
"测试数据.sbn",
"测试数据.sbx"
);
// onCreate 方法,当活动创建时调用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.index); // 设置布局文件
// 设置按钮点击事件
setupButtonClickListeners();
// 检查写入外部存储的权限
handlePermission();
// 初始化地图视图
mapView = findViewById(R.id.mapView);
mapView.setAttributionTextVisible(false);
// 复制 Shapefile 文件到内部存储
copyShapefilesToInternalStorage(this);
// 获取 Shapefile 文件的路径
String shapefilePath = getInternalStorageFilePath(this, "测试数据.shp");
// 设置 Shapefile 特征表
setupShapefileFeatureTable(shapefilePath);
// 检查文件是否为空
for (String fileName : filesToCheck) {
checkNullFile(fileName);
}
// 设置地图视图的视点
mapView.setViewpointGeometryAsync(mFeatureLayer.getFullExtent());
// 设置地图背景
setBackgroundGrid();
}
// 设置按钮点击事件
private void setupButtonClickListeners() {
// 放大按钮
Button magnifyButton = findViewById(R.id.magnify);
magnifyButton.setOnClickListener(v -> handleMagnifyButtonClick());
// 缩小按钮
Button shrinkButton = findViewById(R.id.shrink);
shrinkButton.setOnClickListener(v -> handleShrinkButtonClick());
// 提交按钮,用于启动另一个活动
Button submitButton = findViewById(R.id.Attribute_queries);
submitButton.setOnClickListener(v -> {
Intent intent = new Intent(Main.this, Attribute_select.class);
startActivityForResult(intent, 1);
});
// 加载图层按钮,可以添加加载图层的代码
Button loadLayerButton = findViewById(R.id.Load_layer);
loadLayerButton.setOnClickListener(v -> {
// 可以添加加载图层的代码
});
}
// onActivityResult 方法,处理从另一个活动返回的结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1) {
String fieldName = data.getStringExtra("fieldName");
String fieldValue = data.getStringExtra("fieldValue");
// 高亮显示符合条件的要素
highlightFeatures(fieldName, fieldValue);
}
}
// 高亮显示符合条件的要素
private void highlightFeatures(String fieldName, String fieldValue) {
// 确保图层已加载
if (mFeatureLayer != null && mFeatureLayer.getFeatureTable() != null) {
// 清除之前的选择
mFeatureLayer.clearSelection();
// 设置查询条件
String queryExpression = fieldName + " = '" + fieldValue + "'";
QueryParameters queryParameters = new QueryParameters();
queryParameters.setWhereClause(queryExpression);
// 设置选择模式为新选择
FeatureLayer.SelectionMode selectionMode = FeatureLayer.SelectionMode.NEW;
// 发起异步查询和选择操作
final ListenableFuture<FeatureQueryResult> future = mFeatureLayer.selectFeaturesAsync(queryParameters, selectionMode);
future.addDoneListener(() -> {
try {
// 获取查询结果
FeatureQueryResult result = future.get();
// 检查查询结果是否为空
if (result == null || !result.iterator().hasNext()) {
// 如果没有查询结果,显示提示对话框
showAlertDialog("未找到要素");
} else {
// 处理查询结果并高亮显示要素
highlightFeaturesFromResult(result);
}
} catch (InterruptedException | ExecutionException e) {
// 显示异常信息对话框
showAlertDialog("查询要素失败: " + e.getMessage());
Log.e("selected", "Select feature failed: " + e.getMessage());
}
});
}
}
// 显示提示对话框
private void showAlertDialog(String message) {
// 在 UI 线程中执行
runOnUiThread(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
String pattern = "com.esri.arcgisruntime.ArcGISRuntimeException:";
String pattern_error = "SQLite data type mismatch.: SQLite: 20\n" + "Data type mismatch";
String message1 = message.replace(pattern, "");
message1 = message1.replace(pattern_error, "数据类型不匹配");
Log.d("showAlertDialog", "showAlertDialog: " + message1);
builder.setMessage(message1);
builder.setPositiveButton("确定", null);
try {
builder.show();
} catch (WindowManager.BadTokenException e) {
// 处理异常
Log.e("AlertDialogError", "Unable to show AlertDialog", e);
}
});
}
// 处理查询结果并高亮显示要素
private void highlightFeaturesFromResult(FeatureQueryResult result) {
// 创建一个列表来存储查询到的要素
List<Feature> features = new ArrayList<>();
// 遍历查询结果,并将要素添加到列表中
for (Feature feature : result) {
features.add(feature);
}
// 在地图上选择和高亮显示这些要素
if (!features.isEmpty()) {
// mFeatureLayer.setSelectionColor(R.color.Green_200);
mFeatureLayer.setSelectionWidth(1);
mFeatureLayer.selectFeatures(features);
}
// 获取要素的范围,并调整地图视角以显示这些要素
Envelope extent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
extent = GeometryEngine.combineExtents(features.stream()
.map(Feature::getGeometry)
.filter(Objects::nonNull) // 过滤掉可能的null值
.collect(Collectors.toList()));
}
if (extent != null) {
mapView.setViewpointGeometryAsync(extent, 100);
}
}
// 处理放大按钮点击事件
private void handleMagnifyButtonClick() {
double currentScale = mapView.getMapScale();
final double MAX_SCALE = currentScale * 5.0;
final double MIN_SCALE = 1.0;
double newScale = currentScale * 0.8; // 每次放大到原来的80%
if (newScale > MAX_SCALE) {
newScale = MAX_SCALE;
} else if (newScale < MIN_SCALE) {
newScale = MIN_SCALE;
}
mapView.setViewpointScaleAsync(newScale);
}
// 处理缩小按钮点击事件
private void handleShrinkButtonClick() {
double currentScale = mapView.getMapScale();
final double MIN_SCALE = 1.0;
final double MAX_SCALE = currentScale * 1.6;
double newScale = currentScale * 1.2;
if (newScale > MAX_SCALE) {
newScale = MAX_SCALE;
} else if (newScale < MIN_SCALE) {
newScale = MIN_SCALE;
}
mapView.setViewpointScaleAsync(newScale);
}
// 处理权限请求
private void handlePermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
// 将资源文件复制到内部存储
public boolean copyAssetToInternalStorage(Context context, String assetName, String destFileName) {
if (destFileName == null) {
destFileName = assetName;
}
File fileDir = context.getFilesDir();
File destFile = new File(fileDir, destFileName);
try (InputStream in = context.getAssets().open(assetName);
FileOutputStream fos = new FileOutputStream(destFile)) {
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
// 获取内部存储文件路径
public String getInternalStorageFilePath(Context context, String fileName) {
File fileDir = context.getFilesDir();
File file = new File(fileDir, fileName);
return file.getAbsolutePath();
}
// 检查文件是否为空
public void checkNullFile(String filename) {
try (RandomAccessFile reader = new RandomAccessFile(getInternalStorageFilePath(this, filename), "r")) {
long fileLength = reader.length();
if (fileLength > 0) {
Log.d(TAG, filename + ":文件大小: " + fileLength + " 字节");
byte[] bytes = new byte[10];
reader.read(bytes);
} else {
Log.d(TAG, filename + "文件为空");
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 设置 Shapefile 特征表
private void setupShapefileFeatureTable(String shapefilePath) {
ShapefileFeatureTable shapefileFeatureTable = new ShapefileFeatureTable(shapefilePath);
shapefileFeatureTable.loadAsync();
mFeatureLayer = new FeatureLayer(shapefileFeatureTable);
ArcGISMap map = new ArcGISMap();
// 设置符号和渲染器
SimpleLineSymbol lineSymbol = new SimpleLineSymbol(SimpleLineSymbol.Style.SOLID, Color.RED, 1.0f);
SimpleFillSymbol fillSymbol = new SimpleFillSymbol(SimpleFillSymbol.Style.SOLID, Color.GREEN, lineSymbol);
SimpleRenderer renderer = new SimpleRenderer(fillSymbol);
mFeatureLayer.setRenderer(renderer);
map.getOperationalLayers().add(mFeatureLayer);
mapView.setMap(map);
}
// 设置地图背景
private void setBackgroundGrid() {
BackgroundGrid mainBackgroundGrid = new BackgroundGrid();
mainBackgroundGrid.setColor(Color.WHITE);
mainBackgroundGrid.setGridLineColor(Color.WHITE);
mainBackgroundGrid.setGridLineWidth(0);
mapView.setBackgroundGrid(mainBackgroundGrid);
}
// 复制 Shapefile 文件到内部存储
private void copyShapefilesToInternalStorage(Context context) {
for (String file : filesToCheck) {
boolean copied = copyAssetToInternalStorage(context, file, file);
Log.d(TAG, file + "文件复制完毕");
if (!copied) {
Log.e(TAG, "Failed to copy: " + file);
}
}
}
}
Attribute_select类
package com.test.testApplication;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
public class Attribute_select extends AppCompatActivity {
private List<String> field_value;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.attribute_select);
Button return_button = findViewById(R.id.return_button);
return_button.setOnClickListener(v -> finish());
List<String> field_Name = read_firstName();
Spinner line_spinner = findViewById(R.id.line_spinner);
ArrayAdapter<String> fieldsAdapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, field_Name);
fieldsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
line_spinner.setAdapter(fieldsAdapter);
Spinner value_spinner = findViewById(R.id.value_spinner);
line_spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
field_value = readAndSortValuesSkippingFirstLine(position);
ArrayAdapter<String> valuesAdapter = new ArrayAdapter<>(Attribute_select.this, android.R.layout.simple_spinner_item, field_value);
valuesAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
value_spinner.setAdapter(valuesAdapter);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
Button sumbit_button=findViewById(R.id.submit_button);
sumbit_button.setOnClickListener(v -> {
String selectedFieldName = line_spinner.getSelectedItem().toString();
String selectedFieldValue = value_spinner.getSelectedItem().toString();
Intent intent = new Intent();
intent.putExtra("fieldName", selectedFieldName);
intent.putExtra("fieldValue", selectedFieldValue);
setResult(RESULT_OK, intent);
finish();
});
Button inputButton=findViewById(R.id.input_button);
inputButton.setOnClickListener(v -> {
Intent intent = new Intent(Attribute_select.this, Input_select.class);
startActivityForResult(intent, 1);
});
}
public List<String> read_firstName() {
Resources res = getResources();
InputStream is = res.openRawResource(R.raw.data);
List<String> namesList = new ArrayList<>(); // 使用ArrayList以支持删除操作
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) {
String firstLine = reader.readLine();
if (firstLine != null) {
String[] namesArray = firstLine.split(",");
for (String name : namesArray) {
namesList.add(name.trim()); // 将分割后的字符串添加到列表中
}
// 删除列表中的"FID"元素,如果存在
namesList.remove("FID");
} else {
throw new Exception("文件是空的");
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("读取文件时发生错误:" + e.getMessage());
} catch (Exception e) {
throw new RuntimeException(e);
}
return namesList;
}
public List<String> readAndSortValuesSkippingFirstLine(int position) {
List<String> valuesList = new ArrayList<>();
//在活动中
Resources res = getResources();
InputStream is = null;
try {
is = res.openRawResource(R.raw.data);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
// 标记是否正在读取第一行
boolean isFirstLine = true;
while ((line = reader.readLine()) != null) {
if (isFirstLine) {
isFirstLine = false;
continue;
}
String[] values = line.split(",");
if (position+1 < values.length) {
String value = values[position+1].trim();
if (!value.isEmpty()) {
valuesList.add(value);
}
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 使用LinkedHashSet来去除重复的值
LinkedHashSet<String> uniqueValues = new LinkedHashSet<>(valuesList);
// 将LinkedHashSet转换为List以便排序
List<String> sortedValues = new ArrayList<>(uniqueValues);
// 自定义比较器
Collections.sort(sortedValues, (o1, o2) -> {
// 检查是否为数字
boolean isNumeric1 = o1.matches("\\d+");
boolean isNumeric2 = o2.matches("\\d+");
// 如果两个字符串都是数字
if (isNumeric1 && isNumeric2) {
return Integer.compare(Integer.parseInt(o1), Integer.parseInt(o2));
}
// 如果两个字符串都不是数字
else if (!isNumeric1 && !isNumeric2) {
return o1.compareTo(o2);
}
// 如果第一个字符串是数字,第二个不是
else if (isNumeric1) {
return -1; // 数字应该排在前面
}
// 如果第一个字符串不是数字,第二个是
else {
return 1; // 字符串应该排在后面
}
});
return sortedValues;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1) {
String fieldName = data.getStringExtra("fieldName");
String fieldValue = data.getStringExtra("fieldValue");
Intent intent = new Intent();
intent.putExtra("fieldName", fieldName);
intent.putExtra("fieldValue", fieldValue);
setResult(RESULT_OK, intent);
finish();
}
}
}
Input_select类
package com.test.testApplication;
import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
public class Input_select extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.input_select);
Button select_button= findViewById(R.id.select_button);
Button ret_button= findViewById(R.id.return_button1);
select_button.setOnClickListener(v -> finish());
ret_button.setOnClickListener(v -> {
// 创建一个Intent来启动首页Activity
Intent intent = new Intent(Input_select.this, Main.class);
// 可选:添加flags来清除任务栈,这样用户点击返回时不会回到当前Activity
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动首页Activity
startActivity(intent);
// 结束当前Activity
finish();
});
Button sumit_button = findViewById(R.id.submit_button1);
sumit_button.setOnClickListener(v -> {
EditText e1 = findViewById(R.id.editTextText2);
EditText e2 = findViewById(R.id.editTextText3);
String selectedFieldName = e1.getText().toString().trim().toUpperCase();
String selectedFieldValue = e2.getText().toString().trim();
if(selectedFieldName.isEmpty() | selectedFieldValue.isEmpty()){
showAlertDialog();
}else{
Intent intent = new Intent();
intent.putExtra("fieldName", selectedFieldName);
intent.putExtra("fieldValue", selectedFieldValue);
setResult(RESULT_OK, intent);
finish();
}
});
}
private void showAlertDialog() {
// 在 UI 线程中执行
runOnUiThread(() -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("列名或列值不能为空");
builder.setPositiveButton("确定", null);
try {
builder.show();
} catch (WindowManager.BadTokenException e) {
Log.e("AlertDialogError", "Unable to show AlertDialog", e);
}
});
}
}
8、修改AndroidManifest.xml文件
打开app下的AndroidManifest.xml
修改后的:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="Manifest.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.TestApplication"
android:requestLegacyExternalStorage="true"
tools:targetApi="31" >
<activity android:name=".Attribute_select" />
<activity android:name=".Input_select" />
<activity android:name=".Main"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
9、修改暗夜和白天模式的样式
在本项目中,暗夜和白天模式的样式都应该一致
两个文件夹都在res下
打开values下的themes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestApplication" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>
打开values-night下的themes.xml
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.TestApplication" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<item name="hintTextColor">@color/black</item>
<!-- Customize your theme here. -->
</style>
</resources>
打开color文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="Green_200">#82FFDC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>
结语
当这些全部写完已经写完项目!
但是只有copyright的权利
搜索框和加载图层会再之后补充
©寥若晨星