1. 程式人生 > >ArcGIS Runtime SDK for Android 入門(5):顯示移動裝置當前位置

ArcGIS Runtime SDK for Android 入門(5):顯示移動裝置當前位置

    本文主要講解如何使用ArcGIS Runtime SDK for Android 在地圖中顯示移動裝置的當前位置。

1.建立Android專案   

2.新增Runtime SDK依賴   

3.新增許可權及OpenGL ES支援

在AndroidManifest.xml中新增:

<uses-permission android:name="android.permission.INTERNET" /><!--聯網許可權-->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /><!--粗略定位許可權-->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><!--精確定位許可權-->
    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" /><!--OpenGL ES支援-->

注1:若移動裝置Android版本為6.0及以上,不僅要在manifest中新增許可權,還需要在Activity中程式碼動態獲取許可權。

注2:若使用Android模擬器AVD進行除錯,需要設定模擬定位,步驟:

點選模擬器右側工具欄的按鈕,在出現的介面的Location選項卡中設定Longtitude及Latitude數值,之後點選“send”即可,注意經緯度為WGS84座標系,若要進行座標拾取,推薦使用谷歌地球獲取。

4.設定介面佈局

在layout中的佈局XML中新增:

    <!-- MapView控制元件 -->
    <com.esri.arcgisruntime.mapping.view.MapView
        android:id="@+id/mapView"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </com.esri.arcgisruntime.mapping.view.MapView>
    <!-- 下拉框控制元件 -->
    <Spinner
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/spinner"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="22dp"
        android:background="#00000000"
        android:popupBackground="#00000000"
        android:overlapAnchor="false"/>

由於本例使用的Spinner下拉框比較特殊,列表項是由文字和圖片組成,因此需要設定下拉框的佈局,在layout中的佈局XML中新增spinner_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android= "http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">
    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingTop="5dp"
        android:textColor="#FFF"
        android:textSize="20sp"
        android:gravity="end"
        android:textStyle="bold|normal"
        android:layout_weight="0.9"/>
    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="10dp"
        android:layout_weight="0.1"
        android:contentDescription="@null"/>
</LinearLayout>

5.Spinner圖片素材準備,準備了各個按鈕的適用不同解析度的影象:

下載地址:https://download.csdn.net/download/smart3s/10541268

6.編寫程式碼:

程式碼實現基本流程:

  (1)從MapView中獲取LocationDisplay
  (2)對LocationDisplay設定定位模式
               Re-Center – 中心點顯示定位
               Navigation Mode – 導航模式
               Compass Mode – 羅盤模式
  (3)開啟或結束定位 
               開始定位:mLocationDisplay.startAsync();
               結束定位:mLocationDisplay.stop();
               定位是否開啟:mLocationDisplay.isStarted();

詳細步驟:

(1)Spinner擴充套件:

ItemData.java:Spinner下拉框項變數,儲存操作名稱和圖片ID

public class ItemData {
    private final String text;
    private final Integer imageId;
    public ItemData(String text, Integer imageId) {
        this.text = text;
        this.imageId = imageId;
    }
    public String getText() {
        return text;
    }
    public Integer getImageId() {
        return imageId;
    }
}

SpinnerAdapter.java:下拉框介面卡變數,用來控制Spinner的顯示

public class SpinnerAdapter extends ArrayAdapter<ItemData> {
    private final int groupid;
    private final ArrayList<ItemData> list;
    private final LayoutInflater inflater;

    public SpinnerAdapter(Activity context, int groupid, int id, ArrayList<ItemData>
            list) {
        super(context, id, list);
        this.list = list;
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.groupid = groupid;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View itemView = inflater.inflate(groupid, parent, false);
        ImageView imageView = (ImageView) itemView.findViewById(R.id.img);
        imageView.setImageResource(list.get(position).getImageId());
        TextView textView = (TextView) itemView.findViewById(R.id.txt);
        textView.setText(list.get(position).getText());
        return itemView;
    }

    public View getDropDownView(int position, View convertView, ViewGroup
            parent) {
        return getView(position, convertView, parent);

    }
}

(2)MainActivity.java:

變數準備:

  //MapView控制元件變數
  private MapView mMapView;
  //位置顯示變數
  private LocationDisplay mLocationDisplay;
  //下拉框變數
  private Spinner mSpinner;
  //若系統環境為Android6.0及以上版本,僅在manifest中新增許可權是不夠的,需要程式碼動態獲取許可權
  //許可權請求碼
  private int requestCode = 2;
  //許可權名稱
  String[] reqPermissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission
      .ACCESS_COARSE_LOCATION};

onCreate方法:

    // 定位按鈕列表
    mSpinner = (Spinner) findViewById(R.id.spinner);
    // 從佈局中獲取MapView,並使用影像作為底圖
    mMapView = (MapView) findViewById(R.id.mapView);
    ArcGISMap mMap = new ArcGISMap(Basemap.createImagery());
    mMapView.setMap(mMap);

    //獲取定位元件類
    mLocationDisplay = mMapView.getLocationDisplay();

    // 設定位置改變監聽
    mLocationDisplay.addDataSourceStatusChangedListener(new LocationDisplay.DataSourceStatusChangedListener() {
      @Override
      public void onStatusChanged(LocationDisplay.DataSourceStatusChangedEvent dataSourceStatusChangedEvent) {

        // 如果LocationDisplay啟動OK,則繼續。
        if (dataSourceStatusChangedEvent.isStarted()){
          return;
        }
        // 沒有錯誤報告,然後繼續。
        if (dataSourceStatusChangedEvent.getError() == null){
          return;
        }
        // 如果發現錯誤,處理啟動失敗。
        // 檢查許可權,看看是否失敗可能是由於缺乏許可權。
        boolean permissionCheck1 = ContextCompat.checkSelfPermission(MainActivity.this, reqPermissions[0]) ==
            PackageManager.PERMISSION_GRANTED;
        boolean permissionCheck2 = ContextCompat.checkSelfPermission(MainActivity.this, reqPermissions[1]) ==
            PackageManager.PERMISSION_GRANTED;
        if (!(permissionCheck1 && permissionCheck2)) {
          // 如果許可權尚未授予,請向使用者請求許可權。
          ActivityCompat.requestPermissions(MainActivity.this, reqPermissions, requestCode);
        } else {
          // 向用戶報告其他未知的故障型別—例如,在裝置上可能無法啟用位置服務。
          String message = String.format("Error in DataSourceStatusChangedListener: %s", dataSourceStatusChangedEvent
              .getSource().getLocationDataSource().getError().getMessage());
          Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show();
          // 更新UI以反映位置顯示,實際上沒有啟動
          mSpinner.setSelection(0, true);
        }
      }
    });
    // 設定位置按鈕列表
    ArrayList<ItemData> list = new ArrayList<>();
    list.add(new ItemData("Stop", R.drawable.locationdisplaydisabled));
    list.add(new ItemData("On", R.drawable.locationdisplayon));
    list.add(new ItemData("Re-Center", R.drawable.locationdisplayrecenter));
    list.add(new ItemData("Navigation", R.drawable.locationdisplaynavigation));
    list.add(new ItemData("Compass", R.drawable.locationdisplayheading));
    //建立並繫結Spinner介面卡
    SpinnerAdapter adapter = new SpinnerAdapter(this, R.layout.spinner_layout, R.id.txt, list);
    mSpinner.setAdapter(adapter);
    //Spinner點選事件
    mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
      @Override
      public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        switch (position) {
          case 0:
            // 停止顯示位置
            if (mLocationDisplay.isStarted())
              mLocationDisplay.stop();
              break;
          case 1:
            // 開始顯示位置
            if (!mLocationDisplay.isStarted())
              mLocationDisplay.startAsync();
              break;
          case 2:
            // 底圖地圖顯示到中心
            mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.RECENTER);
            if (!mLocationDisplay.isStarted())
              mLocationDisplay.startAsync();
              break;
          case 3:
            // 開始導航模式(此模式,最佳適用於駕車導航)
            mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.NAVIGATION);
            if (!mLocationDisplay.isStarted())
              mLocationDisplay.startAsync();
            break;
          case 4:
            // 開始羅盤模式(此模式最佳適用於使用者步行時的路徑導航)
            mLocationDisplay.setAutoPanMode(LocationDisplay.AutoPanMode.COMPASS_NAVIGATION);
            if (!mLocationDisplay.isStarted())
              mLocationDisplay.startAsync();
              break;
        }
      }
      @Override
      public void onNothingSelected(AdapterView<?> parent) { }
    });

其他:

  //當接收到許可權請求回撥時呼叫
  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    // 如果請求被拒絕,結果陣列是空值
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
      // 位置被授予許可。這可能是由於未能啟動該系統而引發的。
      // LocationDisplay,再次定位
      mLocationDisplay.startAsync();
    } else {
      // 如果被拒絕,顯示toast以告知使用者所選擇的內容。如果LocationDisplay再次啟動,請求許可權UX將被再次顯示,選項應該被顯示以允許不再顯示UX。
      // 另一種方法是禁用功能,因此請求不再顯示
      Toast.makeText(MainActivity.this, getResources().getString(R.string.location_permission_denied), Toast
          .LENGTH_SHORT).show();

      // 更新UI以反映位置顯示,實際上沒有啟動
      mSpinner.setSelection(0, true);
    }
  }

7.執行App可以進行簡單的定位的相關操作:

感謝luq老師的指導