Android——getResources().getColor()方法报错,提示需API23以上才可使用

本文介绍了在Android开发中遇到的颜色资源获取错误,并提供了两种解决方案。一是使用getIdentifier方法代替getColor,二是通过ContextCompat.getColor方法来解决问题。这些方法可以帮助开发者避免在调用颜色资源时出现的常见错误。
部署运行你感兴趣的模型镜像

问题:

调用 getResources().getColor(R.color.selector_thumb_color, null)时,出现以下错误

解决一:改用getIdentifier方法。

getResources().getIdentifier("colorAccent", "color", getActivity().getPackageName())

第一个参数,colors.xml资源文件中的字段名:

第二个参数,引用的资源类型,可以是“string”、“drawable”等。

第三个参数,项目包名。

解决二:调用

ContextCompat.getColor(context, R.color.colorBlue))

 

您可能感兴趣的与本文相关的镜像

ComfyUI

ComfyUI

AI应用
ComfyUI

ComfyUI是一款易于上手的工作流设计工具,具有以下特点:基于工作流节点设计,可视化工作流搭建,快速切换工作流,对显存占用小,速度快,支持多种插件,如ADetailer、Controlnet和AnimateDIFF等

那么,目前代码如下:package com.example.bus; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.amap.api.maps.AMap; import com.amap.api.maps.CameraUpdateFactory; import com.amap.api.maps.MapView; import com.amap.api.maps.UiSettings; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.Marker; import com.amap.api.maps.model.MarkerOptions; import com.amap.api.maps.model.MyLocationStyle; import com.amap.api.services.core.LatLonPoint; import com.amap.api.services.core.PoiItem; import com.amap.api.services.poisearch.PoiResult; import com.amap.api.services.poisearch.PoiSearch; import com.amap.api.services.geocoder.GeocodeSearch; import com.amap.api.services.geocoder.RegeocodeQuery; import com.amap.api.services.geocoder.RegeocodeResult; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import androidx.activity.OnBackPressedCallback; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.app.AlertDialog; import android.view.ViewGroup; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.PolylineOptions; import com.amap.api.maps.model.LatLngBounds; import com.amap.api.services.busline.BusLineSearch; import com.amap.api.services.busline.BusLineQuery; import com.amap.api.services.busline.BusLineResult; import com.amap.api.services.busline.BusLineItem; import com.amap.api.services.busline.BusStationItem; import com.amap.api.services.core.AMapException; public class SearchResultActivity extends AppCompatActivity implements PoiSearch.OnPoiSearchListener, GeocodeSearch.OnGeocodeSearchListener { private Button searchBtn, goToBtn, btnToggleMode; private RecyclerView resultListView; private List<PoiItem> poiList = new ArrayList<>(); private ResultAdapter adapter; public static final String EXTRA_SEARCH_TYPE = "search_type"; // 0=普通,1=线路 public static final int SEARCH_TYPE_NORMAL = 0; public static final int SEARCH_TYPE_LINE = 1; private int searchType = SEARCH_TYPE_NORMAL; private final Map<String, PoiItem> suggestionPoiCache = new ConcurrentHashMap<>(); // 地图相关 private MapView mapView; private AMap aMap; private Marker selectedMarker; // 输入提示 private GeocodeSearch geocodeSearch; // 当前城市 private String currentCity = ""; // 是否已与地图交互 private boolean userHasInteracted = false; private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001; // 空状态提示视图 private TextView emptyView; // 【关键新增】保存定位得到的“我的位置” private double myCurrentLat = 0; private double myCurrentLng = 0; private boolean isLocationReady = false; // 缓存关键词 private String pendingKeyword = null; // ✅ 实时建议助手 private RealTimePoiSuggestHelper suggestHelper; // 🔽 新增缓存字段 private List<PoiItem> nationalResults = new ArrayList<>(); private List<PoiItem> localResults = new ArrayList<>(); private List<PoiItem> nearbyResults = new ArrayList<>(); private boolean isNearbyLoaded = false; private boolean isInNearbyMode = false; // ✅ 将搜索输入框提升为成员变量 private android.widget.AutoCompleteTextView searchInput; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search_result); initViews(); setupMap(savedInstanceState); String keyword = getIntent().getStringExtra("keyword"); if (keyword != null && !keyword.isEmpty()) { searchInput.setText(keyword); // 立即显示在输入框中 } try { geocodeSearch = new GeocodeSearch(this); geocodeSearch.setOnGeocodeSearchListener(this); } catch (Exception e) { e.printStackTrace(); } // 保留原来的 pendingKeyword 用于后续搜索控制 pendingKeyword = keyword; // 接收搜索类型 searchType = getIntent().getIntExtra(EXTRA_SEARCH_TYPE, 0); // 初始化 suggestHelper suggestHelper = new RealTimePoiSuggestHelper(this); suggestHelper.setCurrentCity(currentCity); suggestHelper.setUseDistanceSort(true); suggestHelper.setPoiCallback(poiItems -> { if (poiItems.length > 0) { List<String> titles = new ArrayList<>(); suggestionPoiCache.clear(); for (PoiItem item : poiItems) { String title = item.getTitle(); titles.add(title); suggestionPoiCache.put(title, item); // 仍可缓存用于后续优化 } ArrayAdapter<String> adapter = new ArrayAdapter<>( SearchResultActivity.this, android.R.layout.simple_dropdown_item_1line, titles ) { @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); view.setOnClickListener(v -> { String selectedText = getItem(position); if (selectedText != null) { searchInput.setText(selectedText); searchInput.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); if (imm != null) { imm.hideSoftInputFromWindow(searchInput.getWindowToken(), 0); } // ✅【关键修复】不再直接 handleSelectedPoiItem // 而是触发完整搜索流程 searchBtn.performClick(); } }); return view; } }; new Handler(Looper.getMainLooper()).post(() -> { searchInput.setAdapter(adapter); if (getCurrentFocus() == searchInput) { searchInput.showDropDown(); } }); } else { new Handler(Looper.getMainLooper()).post(() -> searchInput.setAdapter(null) ); } }); // 使用 OnBackPressedDispatcher 兼容手势返回 getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { @Override public void handleOnBackPressed() { Intent result = new Intent(); String currentText = searchInput.getText().toString().trim(); result.putExtra("updated_keyword", currentText); // 🔥 加上这一行即可! result.putExtra(SearchResultActivity.EXTRA_SEARCH_TYPE, searchType); setResult(RESULT_OK, result); finish(); } }); // =========== 初始化搜索图标与点击事件 =========== updateSearchIcon(); // 设置初始图标和 hint searchInput.setOnTouchListener((v, event) -> { if (event.getAction() == android.view.MotionEvent.ACTION_UP) { Drawable[] drawables = searchInput.getCompoundDrawables(); Drawable leftDrawable = drawables[0]; if (leftDrawable instanceof LayerDrawable) { int totalIconWidth = searchInput.getCompoundPaddingLeft(); if (event.getX() < totalIconWidth && event.getX() > 0) { showSearchTypeDialog(); return true; } } } return false; }); // ================= END ================= } /** * ✅ 更新搜索框左侧图标:主图标 + 右侧小下拉箭头 + 竖线分隔符 * 与 HomeFragment 完全保持一致的视觉效果和布局逻辑 */ private void updateSearchIcon() { // 搜索类型常量(建议提取成全局常量,这里为了独立可运行保留) int mainIconRes = searchType == SEARCH_TYPE_NORMAL ? R.drawable.ic_location : R.drawable.ic_subway; Drawable mainDrawable = ContextCompat.getDrawable(this, mainIconRes); Drawable dropdownArrow = ContextCompat.getDrawable(this, R.drawable.ic_arrow_drop_down); if (mainDrawable == null || dropdownArrow == null) return; float density = getResources().getDisplayMetrics().density; // ======== 尺寸定义(与 HomeFragment 严格一致)======== int iconSize = (int) (20 * density); // 图标大小统一为 20dp int gapBetween = 0; // 主图标与箭头之间无间隙 int dividerWidth = (int) (1 * density); // 竖线宽度 1px int paddingAfterDivider = (int) (2 * density); // 竖线到文字的距离 = 12dp int lineHeight = searchInput.getLineHeight(); int drawableTop = (lineHeight - iconSize) / 2; // 垂直居中 // 扩展竖线高度(上下多出 6dp) int extend = (int)(6 * density); int extendedDividerHeight = lineHeight + 2 * extend; // 创建 LayerDrawable 所图层 GradientDrawable verticalDividerShape = new GradientDrawable(); verticalDividerShape.setShape(GradientDrawable.RECTANGLE); verticalDividerShape.setColor(0xFFCCCCCC); // 浅灰 LayerDrawable layerDrawable = new LayerDrawable(new Drawable[]{ mainDrawable, dropdownArrow, verticalDividerShape }); // 计算位置 int arrowLeft = iconSize + gapBetween; // 箭头紧贴主图标右侧 int dividerLeft = arrowLeft + iconSize; // 分割线在箭头之后 int totalWidth = dividerLeft + dividerWidth + paddingAfterDivider; // 总宽 // 设置主图标 int rightOfMain = totalWidth - iconSize; layerDrawable.setLayerSize(0, iconSize, iconSize); layerDrawable.setLayerInset(0, 0, drawableTop, rightOfMain, drawableTop); // 设置箭头图标 layerDrawable.setLayerSize(1, iconSize, iconSize); layerDrawable.setLayerInset(1, arrowLeft, drawableTop, totalWidth - arrowLeft - iconSize, drawableTop); // 设置竖线 layerDrawable.setLayerSize(2, dividerWidth, extendedDividerHeight); layerDrawable.setLayerInset( 2, dividerLeft, -extend, totalWidth - dividerLeft - dividerWidth, -extend ); // 设置整个 LayerDrawable 的 bounds layerDrawable.setBounds(0, 0, totalWidth, lineHeight); // 应用到 EditText searchInput.setCompoundDrawables(layerDrawable, null, null, null); searchInput.setCompoundDrawablePadding(paddingAfterDivider); } /** * 弹出搜索类型选择对话框 */ private void showSearchTypeDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("选择搜索类型"); String[] items = {"📍 地点搜索", "🚇 公交线路搜索"}; Drawable[] icons = { ContextCompat.getDrawable(this, R.drawable.ic_location), ContextCompat.getDrawable(this, R.drawable.ic_subway) }; ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.select_dialog_singlechoice, items) { @Override public View getView(int position, View convertView, ViewGroup parent) { TextView tv = (TextView) super.getView(position, convertView, parent); tv.setCompoundDrawablesRelativeWithIntrinsicBounds(icons[position], null, null, null); tv.setCompoundDrawablePadding(16); return tv; } }; builder.setAdapter(adapter, (dialog, which) -> { int oldType = searchType; searchType = which == 0 ? SEARCH_TYPE_NORMAL : SEARCH_TYPE_LINE; if (oldType != searchType) { updateSearchIcon(); Toast.makeText(this, searchType == 0 ? "已切换为【地点】模式" : "已切换为【线路】模式", Toast.LENGTH_SHORT).show(); } }); builder.show(); } private void initViews() { searchBtn = findViewById(R.id.search_btn); resultListView = findViewById(R.id.result_list); goToBtn = findViewById(R.id.btn_go_to); btnToggleMode = findViewById(R.id.btn_toggle_mode); emptyView = findViewById(R.id.empty_view); searchInput = findViewById(R.id.search_input); goToBtn.setEnabled(false); adapter = new ResultAdapter(poiList, this::onPoiItemSelected); resultListView.setLayoutManager(new LinearLayoutManager(this)); resultListView.setAdapter(adapter); resultListView.setVisibility(View.GONE); emptyView.setVisibility(View.GONE); goToBtn.setOnClickListener(v -> { if (selectedMarker == null) { Toast.makeText(this, "请先选择一个位置", Toast.LENGTH_SHORT).show(); return; } LatLng targetPos = selectedMarker.getPosition(); if (!isLocationReady) { Toast.makeText(this, "正在获取您的位置,请稍后再试", Toast.LENGTH_SHORT).show(); return; } Intent intent = new Intent(SearchResultActivity.this, RoutePlanActivity.class); intent.putExtra("start_lat", myCurrentLat); intent.putExtra("start_lng", myCurrentLng); intent.putExtra("target_lat", targetPos.latitude); intent.putExtra("target_lng", targetPos.longitude); intent.putExtra(RoutePlanActivity.EXTRA_SOURCE, RoutePlanActivity.SOURCE_FROM_SEARCH_RESULT); startActivity(intent); finish(); }); btnToggleMode.setOnClickListener(v -> { if (isInNearbyMode) { exitNearbyMode(); } else { enterNearbyMode(); } }); } private void setupMap(Bundle savedInstanceState) { mapView = findViewById(R.id.map_view); mapView.onCreate(savedInstanceState); aMap = mapView.getMap(); if (aMap != null) { initMapSettings(); } else { new Handler(Looper.getMainLooper()).post(() -> { aMap = mapView.getMap(); if (aMap != null) { initMapSettings(); } else { waitAMapReady(); } }); } } private void waitAMapReady() { new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { int retry = 0; @Override public void run() { if (mapView == null) return; aMap = mapView.getMap(); if (aMap != null) { initMapSettings(); } else if (retry++ < 30) { new Handler(Looper.getMainLooper()).postDelayed(this, 100); } } }, 100); } private void initMapSettings() { UiSettings uiSettings = aMap.getUiSettings(); uiSettings.setZoomControlsEnabled(true); uiSettings.setCompassEnabled(true); uiSettings.setScrollGesturesEnabled(true); uiSettings.setMyLocationButtonEnabled(true); new Handler(Looper.getMainLooper()).post(() -> aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(35.8617, 104.1954), 4f)) ); enableMyLocationLayer(); } private void enableMyLocationLayer() { if (aMap == null) return; if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { MyLocationStyle myLocationStyle = new MyLocationStyle(); myLocationStyle.myLocationType(MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER); aMap.setMyLocationStyle(myLocationStyle); aMap.setMyLocationEnabled(true); AMap.OnMyLocationChangeListener listener = location -> { if (location != null && !userHasInteracted) { LatLng curLatlng = new LatLng(location.getLatitude(), location.getLongitude()); myCurrentLat = location.getLatitude(); myCurrentLng = location.getLongitude(); isLocationReady = true; suggestHelper.setLocationBias(myCurrentLat, myCurrentLng); aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(curLatlng, 16f), 500, null); userHasInteracted = true; LatLonPoint point = new LatLonPoint(myCurrentLat, myCurrentLng); RegeocodeQuery query = new RegeocodeQuery(point, 200, GeocodeSearch.AMAP); try { geocodeSearch.getFromLocationAsyn(query); } catch (Exception e) { e.printStackTrace(); } new Handler(Looper.getMainLooper()).postDelayed(() -> { if (pendingKeyword != null && !pendingKeyword.isEmpty()) { performSearchWithKeyword(pendingKeyword); } }, 800); aMap.setOnMyLocationChangeListener(null); } }; aMap.setOnMyLocationChangeListener(listener); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_REQUEST_CODE); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { enableMyLocationLayer(); } } } private void setupSearchSuggestion() { Handler handler = new Handler(Looper.getMainLooper()); final Runnable[] pendingRequest = new Runnable[1]; // ✅ 使用数组包装 // 初始化 suggestHelper(已在 onCreate 中创建,这里确保设置参数) suggestHelper.setCurrentCity(currentCity); suggestHelper.setUseDistanceSort(true); // 设置建议回调 suggestHelper.setCallback(suggestions -> { if (suggestions.length > 0) { ArrayAdapter<String> adapter = new ArrayAdapter<>( this, android.R.layout.simple_dropdown_item_1line, suggestions ) { @Override public View getView(int position, View convertView, ViewGroup parent) { View view = super.getView(position, convertView, parent); view.setOnClickListener(v -> { String selectedText = getItem(position); if (selectedText != null && !selectedText.isEmpty()) { searchInput.setText(selectedText); searchInput.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); if (imm != null) { imm.hideSoftInputFromWindow(searchInput.getWindowToken(), 0); } // 🔥 直接触发搜索(与 HomeFragment 一致) searchBtn.performClick(); } }); return view; } }; new Handler(Looper.getMainLooper()).post(() -> { searchInput.setAdapter(adapter); if (getCurrentFocus() == searchInput) { searchInput.showDropDown(); } }); } else { new Handler(Looper.getMainLooper()).post(() -> searchInput.setAdapter(null) ); } }); // 输入监听 + 防抖 searchInput.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if (pendingRequest[0] != null) { handler.removeCallbacks(pendingRequest[0]); } if (s.length() == 0) { searchInput.setAdapter(null); return; } boolean hasPermission = ContextCompat.checkSelfPermission(SearchResultActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; if (!hasPermission) { searchInput.setAdapter(null); return; } // ✅ 将新任务赋值给 pendingRequest[0] pendingRequest[0] = () -> { String keyword = s.toString().trim(); CityManager.ParsedQuery parsed = CityManager.parse(keyword); String searchKeyword = parsed.keyword.isEmpty() ? keyword : parsed.keyword; String explicitCity = parsed.targetCity; // 如果指定了城市,则不走 suggestHelper if (!explicitCity.isEmpty()) { new Handler(Looper.getMainLooper()).post(() -> searchInput.setAdapter(null)); return; } suggestHelper.setCurrentCity(currentCity); suggestHelper.requestSuggestions(searchKeyword); }; handler.postDelayed(pendingRequest[0], 300); } @Override public void afterTextChanged(Editable s) {} }); // 回车和按钮事件保持不变 searchInput.setOnEditorActionListener((v, actionId, event) -> { if ((actionId & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_SEARCH) { searchBtn.performClick(); return true; } return false; }); searchBtn.setOnClickListener(v -> { String keyword = searchInput.getText().toString().trim(); if (!keyword.isEmpty()) { performSearch(keyword); } else { Toast.makeText(this, "请输入关键词", Toast.LENGTH_SHORT).show(); } }); } private void performSearchWithKeyword(String keyword) { searchInput.setText(keyword); searchInput.clearFocus(); searchBtn.performClick(); } private void performSearch(String keyword) { if (keyword.isEmpty()) return; // 【重置状态】清空缓存数据 nationalResults.clear(); localResults.clear(); nearbyResults.clear(); isNearbyLoaded = false; isInNearbyMode = false; btnToggleMode.setText("📍 附近"); emptyView.setText("🔍 搜索中..."); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); // ✅【核心修改】不再使用正则自动识别,完全由 searchType 控制行为 if (searchType == SEARCH_TYPE_LINE) { doLineModeSearch(keyword); return; } // ❌ 原有普通搜索逻辑保持不变(全国+本地合并) CityManager.ParsedQuery parsed = CityManager.parse(keyword); String searchKeyword = parsed.keyword.isEmpty() ? keyword : parsed.keyword; String explicitCity = parsed.targetCity; if (!explicitCity.isEmpty()) { PoiSearch.Query query = new PoiSearch.Query(searchKeyword, "", explicitCity); query.setPageSize(20); try { PoiSearch search = new PoiSearch(this, query); search.setOnPoiSearchListener(this); search.searchPOIAsyn(); } catch (Exception e) { Toast.makeText(this, "搜索失败", Toast.LENGTH_SHORT).show(); } } else { nationalResults.clear(); localResults.clear(); PoiSearch.Query nationalQuery = new PoiSearch.Query(searchKeyword, "", ""); nationalQuery.setPageSize(20); try { PoiSearch nationalSearch = new PoiSearch(this, nationalQuery); nationalSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() { @Override public void onPoiSearched(PoiResult result, int rCode) { if (rCode == 1000 && result != null && result.getPois() != null) { nationalResults.clear(); nationalResults.addAll(result.getPois()); } requestLocalSearch(searchKeyword); } @Override public void onPoiItemSearched(PoiItem item, int rCode) {} }); nationalSearch.searchPOIAsyn(); } catch (Exception e) { e.printStackTrace(); requestLocalSearch(searchKeyword); } } } /** * ✅【全新实现】纯线路模式搜索 —— 使用高德官方 BusLineSearch 精确获取公交线路 * 功能: * - 查询如“北京300路”、“地铁4号线”的完整线路信息 * - 获取真实运行轨迹 polyline * - 获取所有站点并按顺序展示 * - 支持多结果选择(如内环/外环) */ private void doLineModeSearch(String keyword) { // 清空地图和列表 aMap.clear(); poiList.clear(); adapter.notifyDataSetChanged(); emptyView.setText("🔍 正在加载线路信息..."); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); // 构造查询对象:关键字 + 当前城市 BusLineQuery query = new BusLineQuery(keyword.trim(), currentCity); query.setPageSize(5); // 最多返回几条匹配线路(如内外环) query.setPageNumber(0); try { BusLineSearch busLineSearch = new BusLineSearch(this, query); busLineSearch.setOnBusLineSearchListener(new BusLineSearch.OnBusLineSearchListener() { @Override public void onBusLineSearched(BusLineResult result, int rCode) { runOnUiThread(() -> { if (rCode == AMapException.CODE_SUCCESS && result != null && !result.getBusLineItems().isEmpty()) { List<BusLineItem> lines = result.getBusLineItems(); if (lines.size() > 1) { showLineChoiceDialog(lines); } else { displayBusLine(lines.get(0)); } } else { // 显示详细提示,指导用户如何操作 emptyView.setText( "❌ 未找到匹配的公交线路\n\n" + "请检查输入是否正确(如“300路”、“地铁4号线”)\n\n" + "💡 若想搜索地点,请点击搜索框左侧图标切换模式" ); emptyView.setTextColor(ContextCompat.getColor(this, android.R.color.holo_red_dark)); emptyView.setTextSize(14f); emptyView.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); // 可选:弹出一次长提示,进一步引导 Toast.makeText(this, "未找到线路,可点击左侧图标切换搜索类型", Toast.LENGTH_LONG).show(); } }); } }); // 发起异步请求 busLineSearch.searchBusLineAsyn(); } catch (Exception e) { Log.e("BusLineSearch", "启动失败", e); runOnUiThread(() -> { emptyView.setText("⚠️ 线路服务异常"); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); Toast.makeText(this, "线路查询服务异常,请重试", Toast.LENGTH_SHORT).show(); }); } } /** * 展示一条公交线路:绘制路径 + 添加站点标记 + 更新 RecyclerView 列表 */ private void displayBusLine(BusLineItem line) { // === 1. 绘制线路轨迹 === List<LatLonPoint> pathPoints = line.getPolyline(); if (!pathPoints.isEmpty()) { PolylineOptions options = new PolylineOptions(); for (LatLonPoint point : pathPoints) { options.add(new LatLng(point.getLatitude(), point.getLongitude())); } options.color(0xFFE91E63).width(8f); aMap.addPolyline(options); } // === 2. 添加所有站点为 Marker === List<BusStationItem> stations = line.getBusStations(); for (int i = 0; i < stations.size(); i++) { BusStationItem station = stations.get(i); LatLonPoint pos = station.getLatLonPoint(); LatLng latLng = new LatLng(pos.getLatitude(), pos.getLongitude()); aMap.addMarker(new MarkerOptions() .position(latLng) .title((i + 1) + ". " + station.getBusStationName()) .snippet(line.getBusLineName()) // 可选:副标题显示线路名 .icon(BitmapDescriptorFactory.fromResource(R.drawable.ic_station_dot)) ); } // === 3. 将站点转成 PoiItem 显示在下方列表中 === List<PoiItem> stationPois = new ArrayList<>(); suggestionPoiCache.clear(); for (int i = 0; i < stations.size(); i++) { BusStationItem station = stations.get(i); LatLonPoint pos = station.getLatLonPoint(); // 手动构造一个 PoiItem(适配 ResultAdapter) PoiItem item = new PoiItem( "station_" + line.getBusLineId() + "_" + i, pos, station.getBusStationName(), "公交站" ); item.setCityName(currentCity); item.setAdName(line.getBaseStation()); // 起始终点作为区域描述 stationPois.add(item); suggestionPoiCache.put(station.getBusStationName(), item); } updateResultList(stationPois); // === 4. 聚焦地图到整条线路范围 === focusMapOnStations(stationPois); // === 5. UI 提示 === emptyView.setVisibility(View.GONE); resultListView.setVisibility(View.VISIBLE); Toast.makeText(this, "已加载:" + line.getBusLineName(), Toast.LENGTH_SHORT).show(); } /** * 当搜索结果有多个线路时,弹窗让用户选择 */ private void showLineChoiceDialog(List<BusLineItem> lines) { String[] items = lines.stream() .map(BusLineItem::getBusLineName) .toArray(String[]::new); new AlertDialog.Builder(this) .setTitle("请选择线路") .setItems(items, (dialog, which) -> displayBusLine(lines.get(which))) .setNegativeButton("取消", null) .show(); } /** * 聚焦地图到所有站点范围 */ private void focusMapOnStations(List<PoiItem> stations) { LatLngBounds.Builder builder = new LatLngBounds.Builder(); for (PoiItem s : stations) { LatLonPoint p = s.getLatLonPoint(); if (p != null) { builder.include(new LatLng(p.getLatitude(), p.getLongitude())); } } try { aMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 100)); } catch (Exception e) { // bounds 可能太小或为空 } } private void requestLocalSearch(String keyword) { if (currentCity.isEmpty()) { showCombinedResults(); return; } PoiSearch.Query localQuery = new PoiSearch.Query(keyword, "", currentCity); localQuery.setPageSize(20); try { PoiSearch localSearch = new PoiSearch(this, localQuery); localSearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() { @Override public void onPoiSearched(PoiResult result, int rCode) { if (rCode == 1000 && result != null && result.getPois() != null) { localResults.clear(); localResults.addAll(result.getPois()); } showCombinedResults(); } @Override public void onPoiItemSearched(PoiItem item, int rCode) {} }); localSearch.searchPOIAsyn(); } catch (Exception e) { e.printStackTrace(); showCombinedResults(); } } /** * 排序规则: * 1. 核心关键词匹配度最高优先 * 2. 若匹配度相同 → 本市结果优先 * 3. 高匹配度全国结果可排在低匹配度本地结果前 */ private void showCombinedResults() { String keyword = searchInput.getText().toString().trim(); CityManager.ParsedQuery parsed = CityManager.parse(keyword); final String coreKeyword = (parsed.keyword.isEmpty() ? keyword : parsed.keyword).toLowerCase().trim(); Set<String> seen = new HashSet<>(); List<PoiItem> combined = new ArrayList<>(); // 合并去重 for (PoiItem item : localResults) { if (seen.add(item.getPoiId())) { combined.add(item); } } for (PoiItem item : nationalResults) { if (seen.add(item.getPoiId())) { combined.add(item); } } // ✅ 排序:使用 final 变量,并将评分逻辑封装在局部 final 引用中 final String finalCoreKeyword = coreKeyword; combined.sort((a, b) -> { int scoreA = calculateMatchScore(a.getTitle(), finalCoreKeyword); int scoreB = calculateMatchScore(b.getTitle(), finalCoreKeyword); if (scoreA != scoreB) { return Integer.compare(scoreB, scoreA); // 高分优先 } boolean aIsLocal = isSameCity(getDisplayCity(a), currentCity); boolean bIsLocal = isSameCity(getDisplayCity(b), currentCity); if (aIsLocal && !bIsLocal) return -1; if (!aIsLocal && bIsLocal) return 1; return 0; }); adapter.clearExtraText(); for (PoiItem item : combined) { String city = getDisplayCity(item); adapter.setExtraText(item, " | " + city); } updateResultList(combined); } /** * 计算标题与关键词的核心匹配得分 * 规则: * - 完全包含关键词:+50 * - 开头匹配加分 * - 分词命中加分 */ private int calculateMatchScore(String title, String keyword) { if (title == null || keyword == null || title.isEmpty() || keyword.isEmpty()) { return 0; } title = title.toLowerCase(); int score = 0; // 完整包含关键词 if (title.contains(keyword)) { score += 50; // 越靠前分越高 int index = title.indexOf(keyword); if (index == 0) score += 20; else if (index < 4) score += 10; } // 分词命中(如“北京 大学”拆开都出现) String[] words = keyword.split("\\s+"); int matchCount = 0; for (String word : words) { if (word.length() > 1 && title.contains(word)) { matchCount++; } } if (matchCount == words.length) { score += 30; // 全部命中 } else { score += matchCount * 8; // 部分命中也有分 } return score; } private String getDisplayCity(PoiItem item) { if (item == null) return "未知城市"; String city = item.getCityName(); if (city != null && !city.isEmpty() && !city.equals("[]")) { return city; } String adName = item.getAdName(); if (adName != null && !adName.isEmpty() && !adName.equals("[]")) { return adName; } String province = item.getProvinceName(); if (province != null && !province.isEmpty()) { return province; } return "未知城市"; } private void enterNearbyMode() { if (!isLocationReady) { Toast.makeText(this, "正在获取位置...", Toast.LENGTH_SHORT).show(); return; } String keyword = searchInput.getText().toString().trim(); CityManager.ParsedQuery parsed = CityManager.parse(keyword); String explicitCity = parsed.targetCity; String searchKeyword = parsed.keyword.isEmpty() ? keyword : parsed.keyword; // 🔴【关键】如果指定城市非当前城市,则禁止 nearby if (!explicitCity.isEmpty() && !isSameCity(explicitCity, currentCity)) { nearbyResults.clear(); localResults.clear(); nationalResults.clear(); poiList.clear(); adapter.notifyDataSetChanged(); emptyView.setText("📍 所选城市非当前所在城市\n无法搜索附近"); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); isInNearbyMode = false; return; } // 只有同城才允许加载 nearby if (!isNearbyLoaded) { startNearbySearch(searchKeyword); } else { showNearbyResults(); } isInNearbyMode = true; btnToggleMode.setText("🌐 全范围"); } private boolean isSameCity(String city1, String city2) { if (city1 == null || city2 == null) return false; String c1 = city1.endsWith("市") ? city1.substring(0, city1.length() - 1) : city1; String c2 = city2.endsWith("市") ? city2.substring(0, city2.length() - 1) : city2; return c1.equals(c2); } private void exitNearbyMode() { showCombinedResults(); isInNearbyMode = false; btnToggleMode.setText("📍 附近"); } // ✅【重点增强】增加内部防护 private void startNearbySearch(String keyword) { String rawKeyword = searchInput.getText().toString().trim(); CityManager.ParsedQuery parsed = CityManager.parse(rawKeyword); String explicitCity = parsed.targetCity; // 🔒 再次检查是否跨城(防御性编程) if (!explicitCity.isEmpty() && !isSameCity(explicitCity, currentCity)) { Log.w("SearchResult", "拒绝发起跨城 nearby 搜索: " + explicitCity); emptyView.setText("📍 所选城市非当前所在城市\n无法搜索附近"); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); return; } LatLonPoint center = new LatLonPoint(myCurrentLat, myCurrentLng); PoiSearch.Query query = new PoiSearch.Query(keyword, "", ""); query.setPageSize(20); try { PoiSearch nearbySearch = new PoiSearch(this, query); nearbySearch.setBound(new PoiSearch.SearchBound(center, 3000)); nearbySearch.setOnPoiSearchListener(new PoiSearch.OnPoiSearchListener() { @Override public void onPoiSearched(PoiResult res, int code) { if (code == 1000 && res != null && res.getPois() != null && !res.getPois().isEmpty()) { nearbyResults.clear(); nearbyResults.addAll(sortByDistance(res.getPois(), myCurrentLat, myCurrentLng)); isNearbyLoaded = true; showNearbyResults(); } else { emptyView.setText("⚠️ 附近未找到地点"); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); } } @Override public void onPoiItemSearched(PoiItem item, int rCode) {} }); nearbySearch.searchPOIAsyn(); } catch (Exception e) { e.printStackTrace(); emptyView.setText("⚠️ 附近搜索失败"); emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); } } private void showNearbyResults() { List<PoiItem> list = new ArrayList<>(nearbyResults); adapter.clearExtraText(); LatLng me = new LatLng(myCurrentLat, myCurrentLng); for (PoiItem item : nearbyResults) { double dist = com.amap.api.maps.AMapUtils.calculateLineDistance(toLatLng(item.getLatLonPoint()), me); String distText = dist < 1000 ? ((int) dist) + "m" : String.format("%.1fkm", dist / 1000); adapter.setExtraText(item, " | " + distText); } updateResultList(list); } private void onPoiItemSelected(PoiItem item) { LatLng latLng = new LatLng(item.getLatLonPoint().getLatitude(), item.getLatLonPoint().getLongitude()); if (selectedMarker != null) { selectedMarker.remove(); selectedMarker = null; } selectedMarker = aMap.addMarker(new MarkerOptions() .position(latLng) .title("终点:" + item.getTitle()) .icon(com.amap.api.maps.model.BitmapDescriptorFactory.defaultMarker( com.amap.api.maps.model.BitmapDescriptorFactory.HUE_RED))); aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 14f)); goToBtn.setEnabled(true); } private LatLng toLatLng(LatLonPoint point) { if (point == null) return null; return new LatLng(point.getLatitude(), point.getLongitude()); } private List<PoiItem> sortByDistance(List<PoiItem> list, double lat, double lng) { LatLng me = new LatLng(lat, lng); return list.stream() .sorted((a, b) -> { double da = com.amap.api.maps.AMapUtils.calculateLineDistance(toLatLng(a.getLatLonPoint()), me); double db = com.amap.api.maps.AMapUtils.calculateLineDistance(toLatLng(b.getLatLonPoint()), me); return Double.compare(da, db); }) .collect(java.util.stream.Collectors.toList()); } @Override public void onPoiSearched(PoiResult result, int rCode) { String keyword = searchInput.getText().toString().trim(); CityManager.ParsedQuery parsed = CityManager.parse(keyword); if (parsed.targetCity.isEmpty()) return; if (rCode == 1000 && result != null && result.getPois() != null && !result.getPois().isEmpty()) { updateResultList(result.getPois()); } else { if (rCode == 1000) { emptyView.setText("⚠️ 未找到相关地点"); } else { // 是 API 错误 handleSearchError(rCode); emptyView.setText("⚠️ 未找到相关地点"); } emptyView.setVisibility(View.VISIBLE); resultListView.setVisibility(View.GONE); } } private void updateResultList(List<PoiItem> list) { poiList.clear(); poiList.addAll(list); adapter.notifyDataSetChanged(); resultListView.scrollToPosition(0); emptyView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE); resultListView.setVisibility(list.isEmpty() ? View.GONE : View.VISIBLE); if (!list.isEmpty()) { adapter.setSelected(0); onPoiItemSelected(list.get(0)); } } @Override public void onPoiItemSearched(PoiItem item, int rCode) {} @Override public void onRegeocodeSearched(RegeocodeResult result, int rCode) { if (result == null || result.getRegeocodeQuery() == null) return; LatLonPoint point = result.getRegeocodeQuery().getPoint(); if (rCode == 1000 && result.getRegeocodeAddress() != null) { String city = result.getRegeocodeAddress().getCity(); String updatedCity = (city != null && !city.isEmpty()) ? city : result.getRegeocodeAddress().getProvince(); if (Math.abs(point.getLatitude() - myCurrentLat) < 0.0001 && Math.abs(point.getLongitude() - myCurrentLng) < 0.0001) { currentCity = updatedCity; if (suggestHelper != null) { suggestHelper.setCurrentCity(currentCity); } Log.d("SearchResultActivity", "🎯 currentCity 已更新为: " + currentCity); } } else { Log.e("SearchResultActivity", "❌ 反编译失败: rCode=" + rCode); } } private void handleSearchError(int rCode) { String msg; switch (rCode) { case 12: msg = "API Key 错误"; break; case 27: msg = "网络连接失败"; break; case 30: msg = "SHA1 或包名错误"; break; case 33: msg = "请求频繁"; break; default: msg = "搜索失败: " + rCode; break; } Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } @Override public void onGeocodeSearched(com.amap.api.services.geocoder.GeocodeResult geocodeResult, int i) {} @Override protected void onResume() { super.onResume(); mapView.onResume(); setupSearchSuggestion(); } @Override protected void onPause() { super.onPause(); mapView.onPause(); } @Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); geocodeSearch = null; } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); } @Override public boolean onSupportNavigateUp() { onBackPressed(); return true; } } 报错:Expected 3 arguments but found 2、Cannot resolve symbol 'CODE_SUCCESS'、Cannot resolve method 'getBusLineItems' in 'BusLineResult'、'getColor(android.content.Context, int)' in 'androidx.core.content.ContextCompat' cannot be applied to '(anonymous com.amap.api.services.busline.BusLineSearch.OnBusLineSearchListener, int)'、Cannot resolve method 'makeText(OnBusLineSearchListener, String, int)'、Cannot resolve method 'getPolyline' in 'BusLineItem'、Cannot resolve method 'getBaseStation' in 'BusLineItem'。我发现BusLineItem其实是在busline里面就有个BusLineItem.class,现在好像是去BusLineResult.class里面找这个BusLineItem
最新发布
12-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值