20169221 2016-2017-2 《移動平臺應用開發實踐》

第十四周做業

第48章 廣播接收器

廣播接收器是應用程序組件,監聽特定意圖廣播。根據android.content.Internet類中的定義,能夠針對其編寫一個接收器。要建立一個接收器,必須擴展android.content.BroadcastReceiver類或者其一個子類。 在類中必須提供OnReceive的方法的實現。
1 基於時鐘的廣播接收器
android自帶有可以顯示時鐘的接收器。基於ACTION_TIME_TICK廣播的時鐘微件。意圖動做是每分鐘廣播的,很適合適中。下面是一個廣播接收器和一個活動的簡單程勳。java

package com.example.broadcastreceiverdemo1;
import java.util.Calendar;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
BroadcastReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public void onResume() {
super.onResume();
setTime();
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
setTime();
}
};
IntentFilter intentFilter = new IntentFilter(
Intent.ACTION_TIME_TICK);
this.registerReceiver(receiver, intentFilter);
}
public void onPause() {
this.unregisterReceiver(receiver);
super.onPause();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
private void setTime() {
Calendar calendar = Calendar.getInstance();
CharSequence newTime = DateFormat.format(
"kk:mm", calendar);
TextView textView = (TextView) findViewById(
R.id.textView1);
textView.setText(newTime);
}
}
//重要的部分是onReceive方法:
@Override
public void onReceive(Context context, Intent intent) {
setTime();
}

IntentFilter intentFilter = new IntentFilter(
Intent.ACTION_TIME_TICK);
this.registerReceiver(receiver, intentFilter);

2 取消通知
通知操做須要一個PendingInternet,而且能夠對一個PendingInternet變成已發送廣播,須要創建一個名爲cancel_notification的用戶定義意圖操做。android

package com.example.cancelnotificationdemo;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class MainActivity extends Activity {
private static final String CANCEL_NOTIFICATION_ACTION
= "cancel_notification";
int notificationId = 1002;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(CANCEL_NOTIFICATION_ACTION);
this.registerReceiver(receiver, filter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
public void setNotification(View view) {
Intent cancelIntent = new Intent("cancel_notification");
PendingIntent cancelPendingIntent =
PendingIntent.getBroadcast(this, 100,
cancelIntent, 0);
Notification notification = new Notification.Builder(this)
.setContentTitle("Stop Press")
.setContentText(
"Everyone gets extra vacation week!")
.setSmallIcon(android.R.drawable.star_on)
.setAutoCancel(true)
.addAction(android.R.drawable.btn_dialog,
"Dismiss", cancelPendingIntent)
.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
}
public void clearNotification(View view) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(
NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
}

第49章 鬧鐘服務

1.概念與相關屬性方法:
AlarmManager:
一、AlarmManager,顧名思義,就是「提醒」,是Android中經常使用的一種系統級別的提示服務,在特定的時刻爲咱們廣播一個指定的Intent。簡單的說就是咱們設定一個時間,而後在該時間到來時,AlarmManager爲咱們廣播一個咱們設定的Intent,一般咱們使用 PendingIntent,PendingIntent能夠理解爲Intent的封裝包,簡單的說就是在Intent上在加個指定的動做。在使用Intent的時候,咱們還須要在執行startActivity、startService或sendBroadcast才能使Intent有用。而PendingIntent的話就是將這個動做包含在內了。
定義一個PendingIntent對象。
PendingIntent pi = PendingIntent.getBroadcast(this,0,intent,0);
二、AlarmManager的經常使用方法有三個:
(1)set(int type,long startTime,PendingIntent pi);
該方法用於設置一次性鬧鐘,第一個參數表示鬧鐘類型,第二個參數表示鬧鐘執行時間,第三個參數表示鬧鐘響應動做。
(2)setRepeating(int type,long startTime,long intervalTime,PendingIntent pi);
該方法用於設置重複鬧鐘,第一個參數表示鬧鐘類型,第二個參數表示鬧鐘首次執行時間,第三個參數表示鬧鐘兩次執行的間隔時間,第三個參數表示鬧鐘響應動做。
(3)setInexactRepeating(int type,long startTime,long intervalTime,PendingIntent pi);
該方法也用於設置重複鬧鐘,與第二個方法類似,不過其兩個鬧鐘執行的間隔時間不是固定的而已。
三、三個方法各個參數詳悉:
(1)int type: 鬧鐘的類型,經常使用的有5個值:AlarmManager.ELAPSED_REALTIME、 AlarmManager.ELAPSED_REALTIME_WAKEUP、AlarmManager.RTC、 AlarmManager.RTC_WAKEUP、AlarmManager.POWER_OFF_WAKEUP。
AlarmManager.ELAPSED_REALTIME表示鬧鐘在手機睡眠狀態下不可用,該狀態下鬧鐘使用相對時間(相對於系統啓動開始),狀態值爲3;
AlarmManager.ELAPSED_REALTIME_WAKEUP表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘也使用相對時間,狀態值爲2;
AlarmManager.RTC表示鬧鐘在睡眠狀態下不可用,該狀態下鬧鐘使用絕對時間,即當前系統時間,狀態值爲1;
AlarmManager.RTC_WAKEUP表示鬧鐘在睡眠狀態下會喚醒系統並執行提示功能,該狀態下鬧鐘使用絕對時間,狀態值爲0;
AlarmManager.POWER_OFF_WAKEUP表示鬧鐘在手機關機狀態下也能正常進行提示功能,因此是5個狀態中用的最多的狀態之一,該狀態下鬧鐘也是用絕對時間,狀態值爲4;不過本狀態好像受SDK版本影響,某些版本並不支持;
(2)long startTime: 鬧鐘的第一次執行時間,以毫秒爲單位,能夠自定義時間,不過通常使用當前時間。須要注意的是,本屬性與第一個屬性(type)密切相關,若是第一個參數對 應的鬧鐘使用的是相對時間(ELAPSED_REALTIME和ELAPSED_REALTIME_WAKEUP),那麼本屬性就得使用相對時間(相對於 系統啓動時間來講),好比當前時間就表示爲:SystemClock.elapsedRealtime();若是第一個參數對應的鬧鐘使用的是絕對時間 (RTC、RTC_WAKEUP、POWER_OFF_WAKEUP),那麼本屬性就得使用絕對時間,好比當前時間就表示 爲:System.currentTimeMillis()。
(3)long intervalTime:對於後兩個方法來講,存在本屬性,表示兩次鬧鐘執行的間隔時間,也是以毫秒爲單位。
(4)PendingIntent pi: 綁定了鬧鐘的執行動做,好比發送一個廣播、給出提示等等。PendingIntent是Intent的封裝類。須要注意的是,若是是經過啓動服務來實現鬧鐘提 示的話,PendingIntent對象的獲取就應該採用Pending.getService(Context c,int i,Intent intent,int j)方法;若是是經過廣播來實現鬧鐘提示的話,PendingIntent對象的獲取就應該採用 PendingIntent.getBroadcast(Context c,int i,Intent intent,int j)方法;若是是採用Activity的方式來實現鬧鐘提示的話,PendingIntent對象的獲取就應該採用 PendingIntent.getActivity(Context c,int i,Intent intent,int j)方法。若是這三種方法錯用了的話,雖然不會報錯,可是看不到鬧鐘提示效果。
AlarmManager具體用法:Calendar.getInstance():
pendingIntent:
PendingIntent的getActivity方法,第一個參數是上下文,沒啥好說的,第二個參數 requestCode,這個後面說,第三個參數是 Intent,用來存儲信息,第四個參數是對參數的操做標識,經常使用的就是FLAG_CANCEL_CURRENT和FLAG_UPDATE_CURRENT。當使用FLAG_UPDATE_CURRENT時:
PendingIntent.getActivity(context, 0, notificationIntent,PendingIntent.FLAG_CANCEL_CURRENT時);
FLAG_UPDATE_CURRENT會更新以前PendingIntent的消息,好比,你推送了消息1,並在其中的Intent中putExtra了一個值「ABC」,在未點擊該消息前,繼續推送第二條消息,並在其中的Intent中putExtra了一個值「CBA」,好了,這時候,若是你單擊消息1或者消息2,你會發現,他倆個的Intent中讀取過來的信息都是「CBA」,就是說,第二個替換了第一個的內容
當使用FLAG_CANCEL_CURRENT時:
依然是上面的操做步驟,這時候會發現,點擊消息1時,沒反應,第二條能夠點擊。
致使上面兩個問題的緣由就在於第二個參數requestCode,當requestCode值同樣時,後面的就會對以前的消息起做用,因此爲了不影響以前的消息,requestCode每次要設置不一樣的內容。git

第50章 內容提供者

1)ContentProvider簡介
當應用繼承ContentProvider類,並重寫該類用於提供數據和存儲數據的方法,就能夠向其餘應用共享其數據。雖然使用其餘方法也能夠對外共享數據,但數據訪問方式會因數據存儲的方式而不一樣,如:採用文件方式對外共享數據,須要進行文件操做讀寫數據;採用sharedpreferences共享數據,須要使用sharedpreferences API讀寫數據。而使用ContentProvider共享數據的好處是統一了數據訪問方式。
2)Uri類簡介
Uri uri = Uri.parse("content://com.changcheng.provider.contactprovider/contact")
在Content Provider中使用的查詢字符串有別於標準的SQL查詢。不少諸如select, add, delete, modify等操做咱們都使用一種特殊的URI來進行,這種URI由3個部分組成, 「content://」, 表明數據的路徑,和一個可選的標識數據的ID。如下是一些示例URI:
content://media/internal/images 這個URI將返回設備上存儲的全部圖片
content://contacts/people/ 這個URI將返回設備上的全部聯繫人信息
content://contacts/people/45 這個URI返回單個結果(聯繫人信息中ID爲45的聯繫人記錄)
儘管這種查詢字符串格式很常見,可是它看起來仍是有點使人迷惑。爲此,Android提供一系列的幫助類(在android.provider包下),裏面包含了不少以類變量形式給出的查詢字符串,這種方式更容易讓咱們理解一點,所以,如上面content://contacts/people/45這個URI就能夠寫成以下形式:
  Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);
而後執行數據查詢:
Cursor cur = managedQuery(person, null, null, null);
2 建立一個內容提供者
ContentProvider爲不一樣的軟件之間數據共享,提供統一的接口。並且ContentProvider是以相似數據庫中表的方式將數據暴露,也就是說ContentProvider就像一個「數據庫」。那麼外界獲取其提供的數據,也就應該與從數據庫中獲取數據的操做基本同樣,只不過是採用URI來表示外界須要訪問的「數據庫」。至於如何從URI中識別出外界須要的是哪一個「數據庫」這就是Android底層須要作的事情了,也就是說,若是咱們想讓其餘的應用使用咱們本身程序內的數據,就可使用ContentProvider定義一個對外開放的接口,從而使得其餘的應用可使用咱們本身應用中的文件、數據庫內存儲的信息。
內容提供者是android應用程序的基本構建塊之一,它們封裝數據並將封裝的數據經過單一的ContentResolver接口提供給應用程序。當你須要在多個應用之間共享數據的時候就須要用到內容提供者。例如,手機中的聯繫人數據會被多個應用所用到因此必需要用內容提供者存儲起來。若是你不須要在多個應用之間共享數據,你可使用一個數據庫,直接經過SQLite數據庫。 當經過content resolver發送一個請求時,系統會檢查給定的URI並把請求傳給有註冊受權的Contentprovider。 UriMatcher類有助於解析uri。
須要實現的主要方法是:
public boolean onCreate() 在建立ContentProvider時調用
public Cursor query(Uri, String[], String, String[], String) 用於查詢指定Uri的ContentProvider,返回一個Cursor
public Uri insert(Uri, ContentValues) 用於添加數據到指定Uri的ContentProvider中,(外部應用向ContentProvider中添加數據)
public int update(Uri, ContentValues, String, String[]) 用於更新指定Uri的ContentProvider中的數據
public int delete(Uri, String, String[]) 用於從指定Uri的ContentProvider中刪除數據
public String getType(Uri) 用於返回指定的Uri中的數據的MIME類型
數據訪問的方法(如:insert(Uri, ContentValues) and update(Uri, ContentValues, String, String[]))可能被多個線程同時調用,此時必須是線程安全的。其餘方法(如: onCreate())只能被應用的主線程調用,它應當避免冗長的操做。ContentResolver(內容解析者)請求被自動轉發到合適的內容提供者實例,因此子類不須要擔憂跨進程調用的細節。
3 消費內容提供者
ContentResolver能夠與任意內容提供者進行會話,與其合做來對全部相關交互通信進行管理。當外部應用須要對ContentProvider中的數據進行添加、刪除、修改和查詢操做時,可使用ContentResolver類來完成,要獲取ContentResolver對象,可使用Context提供的getContentResolver()方法。ContentResolver cr = getContentResolver();在上面咱們提到ContentProvider能夠向其餘應用程序提供數據,與之對應的ContentResolver則負責獲取ContentProvider提供的數據,修改、添加、刪除更新數據等;
ContentResolver 類也提供了與ContentProvider類相對應的四個方法:
public Uri insert(Uri uri, ContentValues values) 該方法用於往ContentProvider添加數據。
public int delete(Uri uri, String selection, String[] selectionArgs) 該方法用於從ContentProvider刪除數據。
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) 該方法用於更新ContentProvider中的數據。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) 該方法用於從ContentProvider中獲取數據。
這些方法的第一個參數爲Uri,表明要操做的是哪一個ContentProvider和對其中的什麼數據進行操做,假設給定的是 Uri.parse(「content://com.qstingda.provider.personprovider/contact/15」),那麼將會對主機名爲com.qstingda.provider.personprovider的ContentProvider進行操做,path爲contact/15的數據,看到這若是你以前沒有接觸過ContentProvider確定一頭霧水,沒有關係,這很正常,等咱們把理論知識講完後會有實例,相信你看過實例後就會很明白了。數據庫

項目實踐

andoid開發學習之android定位
使用百度Android定位SDK必須註冊GPS和網絡使用權限。定位SDK採用GPS、基站、Wi-Fi信號進行定位。當應用程序向定位SDK發起定位請求時,定位SDK會根據應用的定位因素(GPS、基站、Wi-Fi信號)的實際狀況(如是否開啓GPS、是否鏈接網絡、是否有信號等)來生成相應定位依據進行定位。
用戶能夠設置知足自身需求的定位依據:
若用戶設置GPS優先,則優先使用GPS進行定位,若是GPS定位未打開或者沒有可用位置信息,且網絡鏈接正常,定位SDK則會返回網絡定位(即Wi-Fi與基站)的最優結果。爲了使得到的網絡定位結果更加精確,請打開手機的Wi-Fi開關。
導入庫文件
在使用百度定位SDKv4.0以前,咱們要下載最新的庫文件,下載地址:點擊下載相關庫文件,將liblocSDK4.so文件拷貝到libs/armeabi目錄下。將locSDK4.0.jar文件拷貝到工程的libs
LocationClient 定位SDK的核心類,LocationClient類必須在主線程中聲明。須要Context類型的參數。Context須要時全進程有效的context,推薦用getApplicationConext獲取全進程有效的context,咱們調用registerLocationListener(BDLocationListener)方法來註冊定位監聽接口,BDLocationListener裏面有兩個方法,onReceiveLocation()(接收異步返回的定位結果),onReceivePoi()(接收異步返回的POI查詢結果,POI是「Point of Interest」的縮寫,能夠翻譯成「信息點」,每一個POI包含四方面信息,名稱、類別、經度、緯度、附近的酒店、飯店,商鋪等信息。咱們能夠叫它爲「導航地圖信息」,導航地圖數據是整個導航產業的基石),咱們這裏只須要重寫onReceiveLocation就好了
BDLocation 封裝了定位SDK的定位結果,在BDLocationListener的onReceive方法中獲取。經過該類用戶能夠獲取error code,位置的座標,精度半徑,地址等信息,對於其getLocType ()方法獲取的error code一些狀況api

package com.example.baidumapdemo;  
  
import android.app.Activity;  
import android.graphics.Bitmap;  
import android.os.Bundle;  
import android.util.Log;  
import android.view.LayoutInflater;  
import android.view.View;  
import android.view.View.MeasureSpec;  
import android.view.View.OnClickListener;  
import android.widget.Button;  
import android.widget.TextView;  
import android.widget.Toast;  
  
import com.baidu.location.BDLocation;  
import com.baidu.location.BDLocationListener;  
import com.baidu.location.LocationClient;  
import com.baidu.location.LocationClientOption;  
import com.baidu.mapapi.BMapManager;  
import com.baidu.mapapi.MKGeneralListener;  
import com.baidu.mapapi.map.LocationData;  
import com.baidu.mapapi.map.MKEvent;  
import com.baidu.mapapi.map.MapController;  
import com.baidu.mapapi.map.MapView;  
import com.baidu.mapapi.map.MyLocationOverlay;  
import com.baidu.mapapi.map.PopupClickListener;  
import com.baidu.mapapi.map.PopupOverlay;  
import com.baidu.platform.comapi.basestruct.GeoPoint;  
  
public class MainActivity extends Activity {  
    private Toast mToast;  
    private BMapManager mBMapManager;  
    private MapView mMapView = null;  
    private MapController mMapController = null;  
      
    /** 
     * 定位SDK的核心類 
     */  
    private LocationClient mLocClient;  
    /** 
     * 用戶位置信息  
     */  
    private LocationData mLocData;  
    /** 
     * 個人位置圖層 
     */  
    private LocationOverlay myLocationOverlay = null;  
    /** 
     * 彈出窗口圖層 
     */  
    private PopupOverlay mPopupOverlay  = null;  
      
    private boolean isRequest = false;//是否手動觸發請求定位  
    private boolean isFirstLoc = true;//是否首次定位  
      
    /** 
     * 彈出窗口圖層的View 
     */  
    private View mPopupView;  
    private BDLocation location;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        //使用地圖sdk前需先初始化BMapManager,這個必須在setContentView()先初始化  
        mBMapManager = new BMapManager(this);  
          
        //第一個參數是API key,  
        //第二個參數是經常使用事件監聽,用來處理一般的網絡錯誤,受權驗證錯誤等,你也能夠不添加這個回調接口  
        mBMapManager.init("7ae13368159d6a513eaa7a17b9413b4b", new MKGeneralListenerImpl());  
        setContentView(R.layout.activity_main);  
          
        //點擊按鈕手動請求定位  
        ((Button) findViewById(R.id.request)).setOnClickListener(new OnClickListener() {  
              
            @Override  
            public void onClick(View v) {  
                requestLocation();  
            }  
        });  
          
        mMapView = (MapView) findViewById(R.id.bmapView); //獲取百度地圖控件實例  
        mMapController = mMapView.getController(); //獲取地圖控制器  
        mMapController.enableClick(true);   //設置地圖是否響應點擊事件  
        mMapController.setZoom(14);   //設置地圖縮放級別  
        mMapView.setBuiltInZoomControls(true);   //顯示內置縮放控件  
          
        mMapView.setTraffic(true);  //設置交通訊息圖  
//        mMapView.setSatellite(true);  //設置衛星圖  
//        mMapController.setOverlooking(-45);  //設置地圖俯視角度 ,範圍:0~ -45  
          
          
        mPopupView = LayoutInflater.from(this).inflate(R.layout.pop_layout, null);  
          
        //實例化彈出窗口圖層  
        mPopupOverlay = new PopupOverlay(mMapView ,new PopupClickListener() {  
              
            /** 
             * 點擊彈出窗口圖層回調的方法 
             */  
            @Override  
            public void onClickedPopup(int arg0) {  
                //隱藏彈出窗口圖層  
                mPopupOverlay.hidePop();  
            }  
        });  
          
          
        //實例化定位服務,LocationClient類必須在主線程中聲明  
        mLocClient = new LocationClient(getApplicationContext());  
        mLocClient.registerLocationListener(new BDLocationListenerImpl());//註冊定位監聽接口  
          
        /** 
         * LocationClientOption 該類用來設置定位SDK的定位方式。 
         */  
        LocationClientOption option = new LocationClientOption();  
        option.setOpenGps(true); //打開GPRS  
        option.setAddrType("all");//返回的定位結果包含地址信息  
        option.setCoorType("bd09ll");//返回的定位結果是百度經緯度,默認值gcj02  
        option.setPriority(LocationClientOption.GpsFirst); // 設置GPS優先  
        option.setScanSpan(5000); //設置發起定位請求的間隔時間爲5000ms  
        option.disableCache(false);//禁止啓用緩存定位  
//      option.setPoiNumber(5);    //最多返回POI個數     
//      option.setPoiDistance(1000); //poi查詢距離          
//      option.setPoiExtraInfo(true);  //是否須要POI的電話和地址等詳細信息          
        mLocClient.setLocOption(option);  //設置定位參數  
          
          
        mLocClient.start();  // 調用此方法開始定位  
          
        //定位圖層初始化  
        myLocationOverlay = new LocationOverlay(mMapView);  
          
          
        //實例化定位數據,並設置在個人位置圖層  
        mLocData = new LocationData();  
        myLocationOverlay.setData(mLocData);  
          
        //添加定位圖層  
        mMapView.getOverlays().add(myLocationOverlay);  
          
        //修改定位數據後刷新圖層生效  
        mMapView.refresh();  
          
          
    }  
      
      
    /** 
     * 定位接口,須要實現兩個方法 
     * @author xiaanming 
     * 
     */  
    public class BDLocationListenerImpl implements BDLocationListener {  
  
        /** 
         * 接收異步返回的定位結果,參數是BDLocation類型參數 
         */  
        @Override  
        public void onReceiveLocation(BDLocation location) {  
            if (location == null) {  
                return;  
            }  
              
            StringBuffer sb = new StringBuffer(256);  
              sb.append("time : ");  
              sb.append(location.getTime());  
              sb.append("\nerror code : ");  
              sb.append(location.getLocType());  
              sb.append("\nlatitude : ");  
              sb.append(location.getLatitude());  
              sb.append("\nlontitude : ");  
              sb.append(location.getLongitude());  
              sb.append("\nradius : ");  
              sb.append(location.getRadius());  
              if (location.getLocType() == BDLocation.TypeGpsLocation){  
                   sb.append("\nspeed : ");  
                   sb.append(location.getSpeed());  
                   sb.append("\nsatellite : ");  
                   sb.append(location.getSatelliteNumber());  
                   } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){  
                   sb.append("\naddr : ");  
                   sb.append(location.getAddrStr());  
                }   
           
              Log.e("log", sb.toString());  
              
              
            MainActivity.this.location = location;  
              
            mLocData.latitude = location.getLatitude();  
            mLocData.longitude = location.getLongitude();  
            //若是不顯示定位精度圈,將accuracy賦值爲0便可  
            mLocData.accuracy = location.getRadius();  
            mLocData.direction = location.getDerect();  
              
            //將定位數據設置到定位圖層裏  
            myLocationOverlay.setData(mLocData);  
            //更新圖層數據執行刷新後生效  
            mMapView.refresh();  
              
              
            if(isFirstLoc || isRequest){  
                //將給定的位置點以動畫形式移動至地圖中心  
                mMapController.animateTo(new GeoPoint(  
                        (int) (location.getLatitude() * 1e6), (int) (location  
                                .getLongitude() * 1e6)));  
                showPopupOverlay(location);  
                isRequest = false;  
            }  
            isFirstLoc = false;  
              
        }  
  
        /** 
         * 接收異步返回的POI查詢結果,參數是BDLocation類型參數 
         */  
        @Override  
        public void onReceivePoi(BDLocation poiLocation) {  
              
        }  
  
    }  
      
      
  
    //繼承MyLocationOverlay重寫dispatchTap方法  
    private class LocationOverlay extends MyLocationOverlay{  
  
        public LocationOverlay(MapView arg0) {  
            super(arg0);  
        }  
  
          
        /** 
         * 在「個人位置」座標上處理點擊事件。 
         */  
        @Override  
        protected boolean dispatchTap() {  
            //點擊個人位置顯示PopupOverlay  
            showPopupOverlay(location);  
            return super.dispatchTap();  
        }  
          
    }  
      
      
    /** 
     * 顯示彈出窗口圖層PopupOverlay 
     * @param location 
     */  
    private void showPopupOverlay(BDLocation location){  
         TextView popText = ((TextView)mPopupView.findViewById(R.id.location_tips));  
         popText.setText("[個人位置]\n" + location.getAddrStr());  
         mPopupOverlay.showPopup(getBitmapFromView(popText),  
                    new GeoPoint((int)(location.getLatitude()*1e6), (int)(location.getLongitude()*1e6)),  
                    15);  
           
    }  
      
      
    /** 
     * 手動請求定位的方法 
     */  
    public void requestLocation() {  
        isRequest = true;  
          
        if(mLocClient != null && mLocClient.isStarted()){  
            showToast("正在定位......");  
            mLocClient.requestLocation();  
        }else{  
            Log.d("log", "locClient is null or not started");  
        }  
    }  
      
      
      
     /**  
     * 顯示Toast消息  
     * @param msg  
     */    
    private void showToast(String msg){    
        if(mToast == null){    
            mToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT);    
        }else{    
            mToast.setText(msg);    
            mToast.setDuration(Toast.LENGTH_SHORT);  
        }    
        mToast.show();    
    }   
      
    /** 
     * 將View轉換成Bitmap的方法 
     * @param view 
     * @return 
     */  
    public static Bitmap getBitmapFromView(View view) {  
        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));  
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());  
        view.buildDrawingCache();  
        Bitmap bitmap = view.getDrawingCache();  
        return bitmap;  
    }  
      
      
      
      
      
    /** 
     * 經常使用事件監聽,用來處理一般的網絡錯誤,受權驗證錯誤等 
     * @author xiaanming 
     * 
     */  
    public class MKGeneralListenerImpl implements MKGeneralListener{  
  
        /** 
         * 一些網絡狀態的錯誤處理回調函數 
         */  
        @Override  
        public void onGetNetworkState(int iError) {  
            if (iError == MKEvent.ERROR_NETWORK_CONNECT) {  
                showToast("您的網絡出錯啦!");  
            }  
        }  
  
        /** 
         * 受權錯誤的時候調用的回調函數 
         */  
        @Override  
        public void onGetPermissionState(int iError) {  
            if (iError ==  MKEvent.ERROR_PERMISSION_DENIED) {  
                showToast("API KEY錯誤, 請檢查!");  
            }  
        }  
          
    }  
      
    @Override  
    protected void onResume() {  
        //MapView的生命週期與Activity同步,當activity掛起時需調用MapView.onPause()  
        mMapView.onResume();  
        super.onResume();  
    }  
  
  
  
    @Override  
    protected void onPause() {  
        //MapView的生命週期與Activity同步,當activity掛起時需調用MapView.onPause()  
        mMapView.onPause();  
        super.onPause();  
    }  
  
    @Override  
    protected void onDestroy() {  
        //MapView的生命週期與Activity同步,當activity銷燬時需調用MapView.destroy()  
        mMapView.destroy();  
          
        //退出應用調用BMapManager的destroy()方法  
        if(mBMapManager != null){  
            mBMapManager.destroy();  
            mBMapManager = null;  
        }  
          
        //退出時銷燬定位  
        if (mLocClient != null){  
            mLocClient.stop();  
        }  
          
        super.onDestroy();  
    }  
  
      
      
}

LocationClientOption 用來設置定位SDK的定位方式,好比設置打開GPS,設置是否須要地址信息,設置發起定位請求的間隔時間等等,參數設置完後調用LocationClient 的setLocOption方法
LocationOverlay MyLocationOverlay的子類,重寫裏面的dispatchTap()方法,顯示彈出窗口圖層PopupOverlay,調用mMapView.getOverlays().add(myLocationOverlay)就將個人位置圖層添加到地圖裏面
PopupOverlay 彈出圖層,這個類仍是比較簡單,裏面只有三個方法,hidePop() (隱藏彈出圖層)showPopup(Bitmap pop, GeoPoint point, int yOffset) (顯示彈出圖層)和showPopup顯示多張圖片的重載方法,因爲showPopup方法只接受Bitmap對象,因此咱們必須將咱們的彈出圖層View對象轉換成Bitmap對象,咱們調用getBitmapFromView方法就實現這一轉換
BDLocationListener接口的onReceiveLocation(BDLocation location) 方法我還要重點講解下,咱們會發現onReceiveLocation方法會反覆執行,他執行的間隔跟LocationClientOption類的setScanSpan()方法設定的值有關,咱們設定的是5000毫秒,則onReceiveLocation方法每隔5秒執行一次,注意,當咱們設定的值大於1000(ms),定位SDK內部使用定時定位模式。調用requestLocation( )後,每隔設定的時間,定位SDK就會進行一次定位。若是定位SDK根據定位依據發現位置沒有發生變化,就不會發起網絡請求,返回上一次定位的結果;若是發現位置改變,就進行網絡請求進行定位,獲得新的定位結果。若是你只須要定位一次的話,這個設置小於1000,或者不用設置就能夠了,定時定位時,調用一次requestLocation,會定時監聽到定位結果緩存

參考資料

Android中的AlarmManager的使用安全

相關文章
相關標籤/搜索