• 20169221 2016-2017-2 《移动平台应用开发实践》


    第十四周作业

    第48章 广播接收器

    广播接收器是应用程序组件,监听特定意图广播。根据android.content.Internet类中的定义,可以针对其编写一个接收器。要创建一个接收器,必须扩展android.content.BroadcastReceiver类或者其一个子类。 在类中必须提供OnReceive的方法的实现。
    1 基于时钟的广播接收器
    android自带有能够显示时钟的接收器。基于ACTION_TIME_TICK广播的时钟微件。意图动作是每分钟广播的,很适合适中。下面是一个广播接收器和一个活动的简单程勋。

    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的用户定义意图操作。

    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:
    1、AlarmManager,顾名思义,就是“提醒”,是Android中常用的一种系统级别的提示服务,在特定的时刻为我们广播一个指定的Intent。简单的说就是我们设定一个时间,然后在该时间到来时,AlarmManager为我们广播一个我们设定的Intent,通常我们使用 PendingIntent,PendingIntent可以理解为Intent的封装包,简单的说就是在Intent上在加个指定的动作。在使用Intent的时候,我们还需要在执行startActivity、startService或sendBroadcast才能使Intent有用。而PendingIntent的话就是将这个动作包含在内了。
    定义一个PendingIntent对象。
    PendingIntent pi = PendingIntent.getBroadcast(this,0,intent,0);
    2、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);
    该方法也用于设置重复闹钟,与第二个方法相似,不过其两个闹钟执行的间隔时间不是固定的而已。
    3、三个方法各个参数详悉:
    (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每次要设置不同的内容。

    第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一些情况

    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("
    error code : ");  
                  sb.append(location.getLocType());  
                  sb.append("
    latitude : ");  
                  sb.append(location.getLatitude());  
                  sb.append("
    lontitude : ");  
                  sb.append(location.getLongitude());  
                  sb.append("
    radius : ");  
                  sb.append(location.getRadius());  
                  if (location.getLocType() == BDLocation.TypeGpsLocation){  
                       sb.append("
    speed : ");  
                       sb.append(location.getSpeed());  
                       sb.append("
    satellite : ");  
                       sb.append(location.getSatelliteNumber());  
                       } else if (location.getLocType() == BDLocation.TypeNetWorkLocation){  
                       sb.append("
    addr : ");  
                       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("[我的位置]
    " + 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的使用

  • 相关阅读:
    QQ群友在线/离线,如何测试?
    QQ好友在线/离线,怎么测试?
    用户体验测试一样很重要
    BUG,带给我的思考
    chrome DevTools
    HTTP、HTTPS
    Knockout双向绑定
    微信小程序
    git fetch 更新远程代码到本地仓库
    Git 同步远程仓库
  • 原文地址:https://www.cnblogs.com/sunxing/p/6929333.html
Copyright © 2020-2023  润新知