安卓使用高德地图实现地理围栏(简述服务与广播及记录使用通知的坑)

一、前言

本次实现的功能是地理围栏,在地图上选一个区域作为危险区域,当使用者进入到此区域中时,触发我们的围栏机制,给手机发送通知尽快离开此区域。

在实现此功能前首先了解要服务与广播,服务与广播同属于安卓的四大组件,大半年没碰安卓开发的我显得有些生疏,查了些资料,这里对自己浅显的理解做一下记录。

1.1 Service(服务)

服务跟Activity一样具有生命周期,当他被第一次创建的时候执行 OnCreate() 方法,该方法只执行一次。

服务的启动方式有两种,第一种是bindService(), 该方法将服务与其他应用程序组件(如活动)绑定在一起,该服务随着调用的组件销毁而停止。通过该方法启动服务必须实现服务的 onBind() 方法。

另一种是 startService(),其他组件(如活动)通过调用来该方法启动服务时, 会调用服务的 onStartCommand() 方法,一旦使用这种方法启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。

本次功能实现用的是上述第二种启动方法,但是这里我的需求是在软件从后台销毁时服务仍然能运行,对用户进行实时定位保障用户安全,这里考虑的一种方案是,在Activity的OnDestory() 发送广播再次拉起应用程序,从而启动服务。

1.2 Broadcast(广播)

广播分为广播发送者与广播接收者(BroadcastReceiver),自定义广播接收器需要继承基类BroadcastReceivre,并实现抽象方法onReceive(context, intent)方法。广播接收器接收到相应广播后,会自动回到onReceive(…)方法,在onReceive中可以通过接收广播的类型实现相应的方法。
BroadcastReceiver总体上可以分为两种注册类型:静态注册和动态注册。静态注册直接在AndroidManifest.xml文件中进行注册。动态注册直接在代码中通过调用Context的registerReceiver函数。

1.3 Notification (通知)

这里不得不提的是我在使用通知栏的时候遇到的坑,由于Android的版本优化,没有设置channel通知渠道的话,就会导致通知无法展示,NotificationChannel是androd8.0新增的特性,指定 Channel 的 id、name 和通知的重要程度。
以下是我实现的通知栏。

二、代码实现

/**
*自定义服务类
*/
package com.example.campusprevention_app.service;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.amap.api.fence.GeoFence;
import com.amap.api.fence.GeoFenceClient;
import com.amap.api.fence.GeoFenceListener;
import com.amap.api.location.DPoint;
import com.example.campusprevention_app.R;
import java.util.List;


public class GeoFenceService extends Service {
    
    
    DPoint centerPoint;
    //定义接收广播的action字符串
    public static final String GEOFENCE_BROADCAST_ACTION = "com.location.apis.geofencedemo.broadcast";

    @Override
    public void onCreate() {
    
    
        super.onCreate ();
        //地理围栏的中心点
        centerPoint = new DPoint ();
        centerPoint.setLatitude (34.813956);
        centerPoint.setLongitude (113.539805);

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    
    

        //实例化地理围栏客户端
        GeoFenceClient mGeoFenceClient = new GeoFenceClient (getApplicationContext ());
        mGeoFenceClient.setActivateAction (GeoFenceClient.GEOFENCE_IN | GeoFenceClient.GEOFENCE_OUT);
        mGeoFenceClient.addGeoFence (centerPoint, 1000, "1");
        GeoFenceListener geoFenceListener = new GeoFenceListener () {
    
    
            @Override
            public void onGeoFenceCreateFinished(List<GeoFence> list, int i, String s) {
    
    
                if (i == GeoFence.ADDGEOFENCE_SUCCESS) {
    
    
                   // Toast.makeText (getApplicationContext (), "创建围栏成功", Toast.LENGTH_SHORT).show ();
                }
            }
        };
        mGeoFenceClient.setGeoFenceListener (geoFenceListener);
        //创建并设置PendingIntent
        mGeoFenceClient.createPendingIntent (GEOFENCE_BROADCAST_ACTION);
        IntentFilter filter = new IntentFilter ();
        filter.addAction (GEOFENCE_BROADCAST_ACTION);
        registerReceiver (mGeoFenceReceiver, filter);
        return super.onStartCommand (intent, flags, startId);
    }

    private BroadcastReceiver mGeoFenceReceiver = new BroadcastReceiver () {
    
    
        @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            //获取Bundle
            Bundle bundle = intent.getExtras ();
            int statu = bundle.getInt (GeoFence.BUNDLE_KEY_FENCESTATUS);
            if (statu == GeoFenceClient.GEOFENCE_IN) {
    
    
               // Toast.makeText (getApplicationContext (),"你已进入危险区域",Toast.LENGTH_SHORT).show ();
                showNotification (context,intent);
                Log.e ( "onReceive: ","进入" );
            }
            else {
    
    
                Log.e ( "onReceive: ","离开" );

               // Toast.makeText (getApplicationContext (),"你已离开危险区域",Toast.LENGTH_LONG).show ();

            }
        }
    };

  /**
   *显示通知栏
   */
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    private void showNotification(Context context,Intent intent){
    
    
        NotificationManager manager = (NotificationManager) getSystemService (NOTIFICATION_SERVICE);

        PendingIntent pendingIntent = PendingIntent.getActivity (context, 0, intent, 0);
        Notification notification;
        Notification.Builder builder;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            builder = new Notification.Builder (context, "5996773");
        } else {
    
    
            builder = new Notification.Builder (context);
        }
        //设置标题与内容
        builder.setContentTitle ("风险通知").setContentText ("您正在进入高风险区域,请尽快离开!");
        //设置状态栏显示的图标
        builder.setSmallIcon (R.mipmap.fence_notification_danger);
        // 设置通知灯光(LIGHTS)、铃声(SOUND)、震动(VIBRATE)、(ALL 表示都设置)
        builder.setDefaults (Notification.DEFAULT_ALL);
        //灯光三个参数,颜色(argb)、亮时间(毫秒)、暗时间(毫秒)
        builder.setLights (Color.RED, 200, 200);
        // 震动,传入一个 long 型数组,表示 停、震、停、震 ... (毫秒)
        builder.setVibrate (new long[]{
    
    0, 200, 200, 200, 200, 200});
        // 通知栏点击后自动消失
        builder.setAutoCancel (true);
        // 简单通知栏设置 Intent
        builder.setContentIntent (pendingIntent);
        builder.setPriority (Notification.PRIORITY_HIGH);
        //设置下拉之后显示的图片
        builder.setLargeIcon (BitmapFactory.decodeResource (getResources (), R.mipmap.fence_notification_danger));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            NotificationChannel channel = new NotificationChannel ("5996772", "安卓10a", NotificationManager.IMPORTANCE_DEFAULT);
            channel.enableLights (true);//是否在桌面icon右上角展示小红点
            channel.setLightColor (Color.RED);//小红点颜色
            channel.setShowBadge (true); //是否在久按桌面图标时显示此渠道的通知
            manager.createNotificationChannel (channel);
        }
        notification = builder.build ();
        manager.notify (1, notification);

    }
    @Override
    public void onDestroy() {
    
    
        super.onDestroy ();
    }

    @Override
    public IBinder onBind(Intent intent) {
    
    
        return null;
    }
}

//开启服务
  Intent intent = new Intent (getApplicationContext (), GeoFenceService.class);
        this.startService (intent);

三、总结

`以上就是本次记录的内容,虽说知识点很多,但是在这里我记录的内容是十分浅显的,自己也算是对这些知识点有了更加深入的了解吧。再次声明一下,在这里我记录的博客主要是供自己以后学习回顾,如果知识点有什么错误欢迎大家指正!

猜你喜欢

转载自blog.csdn.net/qq_44706002/article/details/110497596
今日推荐