记一次课程设计(顺便复习一下android service和七牛云 android sdk)

一学期的课程设计又开始了,虽然以后不搞安卓,但是课设还是想好好完成的,因为之前做过地图开发,所以选了一个跟

这个相关的题目,其实有一个校车系统也可以选,但是之前做过一个相似度接近80%的东西,不想混混过关,就算了,这是题目

实现思路并不难,孩子端启动一个后台服务,每隔3分钟向后台服务器发送一次位置信息,后端保存,家长端通过时间段来获得孩子位置,实际上就是根据时间戳

来了,然后标注在家长端地图上,至于打电话什么的,调系统API就可以,从星期二到今天,将孩子端完成,后端完成,父亲端也差不多了,现在还有一个

难点就是最后的要求15分钟没有信息汇报就需要警告,还没搞清楚怎么实现...明天要考六级,今天得知软考挂了伤心死了,就差那么几分啊,要

是没看错最后的那个大题就过了

整个课设的技术包括:前端:安卓,七牛云SDK,Volley网络框架,百度地图SDK

后台:SpringBoot+Mybatis+mysql

现在记录一下每个三分钟发布一次信息的实现和上传头像的实现(之前还没弄过安卓上传文件所以想试试)

都知道安卓四大组件,其中service就是一个重要的东西,这里我说的是非绑定的service,它是不停的运行的,所以我们可以利用它来给我们的应用添加一些有趣的功能

比如我们退出软件仍旧下载东西就是用这个实现的,但是对于本题来讲,光是有服务是行不通的,我们还需要一个定时器,而且,还需要是稳定的,而不是那种退出APP就

停止的,综合考虑,当然是用AlarmManager了,他是安卓的系统服务,所以不会随着应用退出而停止,闹钟就是用这个来实现的.,AlarmManager如果参照网上的一些demo

基本都会遇到坑,因为谷歌官方更新了这个,用错了会有很大误差,这里推荐看一下这个博客:我也是看了他的

https://www.cnblogs.com/leipDao/p/8203684.html

从这个博客里了解到AlarmManager在安卓高版本里会有误差,但还好谷歌有新的API来对付误差,但定时的功能就不好实现了,那么这里采用的办法就是在调用一次之后在重新

发送,就达到了计时的目的

首先是一个工具类,负责实例化AlarmManager对象,唤醒闹钟

import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

import software.com.safelocatechild.BroadcastReceiver.LocateInfoReceiver;

/**
 * Created by 31786 on 2018/12/11.
 * 计时器,用于隔断时间发送自己的位置
 */
public class AlarmManagerUtils {

    private static final long TIME_INTERVAL = 15 * 1000;//闹钟执行任务的时间间隔
    private Context context;
    public static AlarmManager am;
    public static PendingIntent pendingIntent;

    private AlarmManagerUtils(Context aContext) {
        this.context = aContext;
    }

    private static AlarmManagerUtils instance = null;

    public static AlarmManagerUtils getInstance(Context aContext) {
        if (instance == null) {
            synchronized (AlarmManagerUtils.class) {
                if (instance == null) {
                    Log.d("Alarm","实例化");
                    instance = new AlarmManagerUtils(aContext);
                }
            }
        }
        return instance;
    }

    public void createGetUpAlarmManager() {
        Log.d("Alarm","创建");
        am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, LocateInfoReceiver.class);
        intent.putExtra("msg", "测试");
        pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);//每隔5秒发送一次广播
    }

    @SuppressLint("NewApi")
    public void getUpAlarmManagerStartWork() {
        //版本适配
        Log.d("Alarm","开始工作");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0及以上
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), pendingIntent);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 4.4及以上
            am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
                    pendingIntent);
        } else {
            am.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), TIME_INTERVAL, pendingIntent);
        }
    }

    @SuppressLint("NewApi")
    public void getUpAlarmManagerWorkOnReceiver() {
        //高版本重复设置闹钟达到低版本中setRepeating相同效果
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0及以上
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis() + TIME_INTERVAL, pendingIntent);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {// 4.4及以上
            am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
                    + TIME_INTERVAL, pendingIntent);
        }
    }
}

  

在这时候,就是在服务里启动它,并且在一次计时过后重新开启一次计时,从而达到不断计时的目的

下面是个服务,负责发送广播,好像这样不太好,但我对这个不熟,先这样再说吧...

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import software.com.safelocatechild.activity.Welcome;
import software.com.safelocatechild.util.AlarmManagerUtils;

public class LocateService extends Service {
    public LocateService() {
    }

    @Override
    public void onCreate(){
        Log.d("-------","服务创建");
        super.onCreate();
    }
    @Override
    public int onStartCommand(Intent intent,int flagId,int startId){
        Log.d("-------","服务运行");
       // onStartCommand(intent,flagId,startId);
        testAlarm();
        return super.onStartCommand(intent,flagId,startId);
    }
    @Override
    public void onDestroy(){
        //发送结束信息,告知parent
        super.onDestroy();
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
    public void testAlarm(){
        AlarmManagerUtils alarmManagerUtils = AlarmManagerUtils.getInstance(getApplicationContext());
        alarmManagerUtils.createGetUpAlarmManager();
        alarmManagerUtils.getUpAlarmManagerStartWork();
    }
}

  

广播接收:

package software.com.safelocatechild.BroadcastReceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
import android.widget.Toast;

import com.android.volley.AuthFailureError;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.mapapi.map.BaiduMap;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import software.com.safelocatechild.R;
import software.com.safelocatechild.activity.Child;
import software.com.safelocatechild.activity.Login;
import software.com.safelocatechild.listener.LocationListener;
import software.com.safelocatechild.util.AlarmManagerUtils;
import software.com.safelocatechild.util.Const;

public class LocateInfoReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        // TODO: This method is called when the BroadcastReceiver is receiving
        String extra = intent.getStringExtra("msg");
        Log.d("---------------", "extra = " + extra);
        Log.d("-------","接收到了");
        LocationClient client = new LocationClient(context);
        client.registerLocationListener(new LocationListener(){
            /*
             * 通过GPS定位起点
             * */
            @Override
            public void onReceiveLocation(BDLocation location){
                System.out.print("LocationClient----");
                if (location!=null){
                    //定时发送经纬度,写接口
                    String childid = Const.context.getSharedPreferences("Setting",Context.MODE_MULTI_PROCESS).
                            getString("childid","");
                    Log.d("childid = ",childid);
                    Log.d("Send longitude",location.getLongitude()+"");
                    Toast.makeText(Const.context,childid+location.getLongitude()+"-"+location.getLatitude(),Toast.LENGTH_SHORT).show();
                    //Log.d("Send latitude",location.getLatitude()+"");
                    sendLocation(childid,location.getLatitude(),location.getLongitude());
                    //再次启动闹钟
                    AlarmManagerUtils.getInstance(context).getUpAlarmManagerWorkOnReceiver();
                }else {
                    Log.d("location = ","null");
                }

            }
        });
        client.start();

    }
    //发送位置
    public boolean sendLocation(final String childid,final Double latitude, final Double longitude){
        //请求地址,需要换接口
        String url = Const.context.getResources().getString(R.string.insertLocation);
        String tag = "Login";
        //取得请求队列
        RequestQueue requestQueue = Volley.newRequestQueue(Const.context);
        //防止重复请求,所以先取消tag标识的请求队列
        requestQueue.cancelAll(tag);
        //创建StringRequest,定义字符串请求的请求方式为POST(省略第一个参数会默认为GET方式)
        StringRequest request = new StringRequest(Request.Method.POST, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        try {
                            JSONObject jsonObject = new JSONObject(response);
                            if(jsonObject.getBoolean("canInsert")){
                                //等待接口
                                Log.d("发送位置成功","  ");
                            }else{
                                Log.d("发送位置失败","  ");
                            }
                        } catch (JSONException e) {
                            //做自己的请求异常操作,如Toast提示(“无网络连接”等)
                            Log.d("LocateInfoReceiver","JsonException");
                        }
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                //做自己的响应错误操作,如Toast提示(“请稍后重试”等)
                Log.d("LocateInfoReceiver","VolleyError");
            }
        }) {
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                Map<String,String> params = new HashMap<>();
                params.put("childid",childid);
                params.put("longitude",String.valueOf(longitude));  //注⑥
                params.put("latitude",String.valueOf(latitude));
                params.put("time",System.currentTimeMillis()+"");
                Log.d("位置发送时间",System.currentTimeMillis()+"");
                return params;
            }

        };

        //设置Tag标签
        request.setTag(tag);
        request.setRetryPolicy(new DefaultRetryPolicy(20*1000,1,1.0f));
        //将请求添加到队列中
        requestQueue.add(request);
        return true;
    }
}

  

好了,从数据库里的结果来看,效果还行,但因为中途有时间损耗,肯定还是有一点影响的

之后再说上传图片,七牛云的使用就不多说了,官方有文档,我的做法是用TakePhoto框架得到图片,然后将图片化成能上传的格式

TakePhoto的使用我之前的博客里有讲:https://www.cnblogs.com/Yintianhao/p/9327191.html

重点的三个函数:一个上传,也就是里面有七牛云的上传和回调,还有一个将Bitmap图片转为byte数组,另一个就是获得一个随机名字

名字直接关系到取图片的链接,同时在我这个题目中也是存在用户信息表里面的

//上传图片
public void uploadImage(final Bitmap bitmap, String fileName) {
        //定义数据上传结束后的处理动作
        final UpCompletionHandler upCompletionHandler = new UpCompletionHandler() {
            @Override
            public void complete(String key, ResponseInfo info, JSONObject response) {
                headSculpture.setImageBitmap(bitmap);
            }
        };
        final UploadOptions uploadOptions = new UploadOptions(null, null, false, new UpProgressHandler() {
            @Override
            public void progress(String key, final double percent) {
                //百分数格式化
                NumberFormat fmt = NumberFormat.getPercentInstance();
                fmt.setMaximumFractionDigits(2);//最多两位百分小数,如25.23%
            }
        }, new UpCancellationSignal() {
            @Override
            public boolean isCancelled() {
                return false;
            }
        });
        try {
            //上传图片
            QiNiuInitialize.getSingleton().put(getByte(bitmap), fileName, getUpToken(), upCompletionHandler, uploadOptions);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //通过UUID获得一个随机的文件名
    public String getRandomName(){
        String randomName = UUID.randomUUID().toString().replaceAll("-","")+".jpeg";
        return randomName;
    }

    //获取图片的byte数组
    public byte[] getByte(Bitmap bm) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, 80, baos);
        return baos.toByteArray();
    }

  

好了,上传到这里,那么我们如何根据图片的链接来获取图片并显示在控件里呢,看这里:

 //根据URL获取图片,path即url
    public Bitmap getBitmap(String path) throws IOException {//严格模式否则会出错,具体作用可以查
        StrictMode.setThreadPolicy(new
                StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
        StrictMode.setVmPolicy(
                new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        Log.d("path","="+path);
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setRequestMethod("GET");
            if (conn.getResponseCode() == 200) {
                InputStream inputStream = conn.getInputStream();
                Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                return bitmap;
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

 

好了,先写到这了,听听听力准备明天的六级去了!!

原文地址:https://www.cnblogs.com/Yintianhao/p/10121715.html

时间: 2024-08-29 13:25:27

记一次课程设计(顺便复习一下android service和七牛云 android sdk)的相关文章

java课程设计

程序设计实训报告 题目:计算数学表达式程序 1.课设目的 (1)复习巩固java语言的基础知识,进一步加深对java语言的理解和掌握 (2)课设为大家提供一个即动手又动脑,独立实践的机会.提高我们适应实际,编程的能力 (3)培养我们在项目开发中创新意识及能力,通过亲身实践,利用所学编写简单的面向对象程序,提高对面向对象及java语言的解释 2.设计题目分析 (1)由用户输入一个简单的四则运算表达式,求出其计算结果后显示 (2)允许在表达式中出现常用的数学函数,如取整.三角函数.倒数.平方根.平方

《对象程序设计》课程 课程设计、考试安排 及 教师建议

通知 (1)课程设计时间 第18周周一-周五上午,软件一室.(有兴趣的同学下午也可以在里面,电脑很多,下午是网络131班课程设计时间) 课程设计题目,老师将于下周(16周)发给大家(公布在CSDN博客 及 通知学委黎文),请大家提前准备. (2)考试时间 第18周周三下午(计划),请大家好好复习,开卷考试,主要考察大家对基础的掌握程度.杜绝作弊(老师从这个学期开始会严抓考试纪律,发现第一个作弊的同学将没收考卷,第二个报送到教务处,请大家理解). (3)老师工作时间 老师已经在湛江,除短暂外出学习

数据库课程设计--“茶咖啡”销售管理系统总结

为期一周的数据库课程设计终于完工, 总结一些经验和教训.发现基础的知识还是要时刻记在心中,知识不基础,何谈去开发?因为做什么东西都首先要一定的目标,计划,以及做到东西要做到那个程度,这方面一点要先在脑子里有一个印象,然后才能用所学的知识点去发挥, 因此知识点一点要掌握牢固,自己在设计课程设计的过程中,发现写好的数据库语言一点运行,就会出现这个那个的问题.然后从头去寻找问题的源头,才发现表的主键和外键设置出了问题.然后琢磨半天,突然意识到到底是什么主键和外键? 两个的定义和作用到底是什么?,这才发

c++课程设计之菜单选择\\

a) 从键盘输入n个数,选择升序还是降序输出 b)创新了日历 c) 添加了射箭游戏 d)还加入了好玩的24点游戏     学生签名:  年  月   日   课程设计(论文)评阅意见 等 级 项    目 课程设计态度评价 出勤情况评价 设计中创新性评价 论文书写规范化评价 综合评定等级 优秀 好 好 6补充 好   良好 好 好 4补充 好   中等 好 好 2补充 好   及格 好 好 无补充 好   不及格 不好 不好 无补充 不好   评阅人  王更生  职称  教 授 2017年  6

计算机组成原理 课程设计报告

        计算机组成原理 课程设计报告      成员:许恺   2014011329          胡强勇  2014011315     时间:2016.12.20                 一.简要总结计算机组成原理实验 计算机组成原理实验总共五个实验,首先我们熟悉了教学机的使用方法,后面的实验我们分为运算器.存储器.控制器,控制器分为两次实验.紧接的第二次实验我们就进行了运算器的实验,对运算器的内部构造极其原理进行了验证理解,在这里我们学习了运算器ALU的8种运算功能,以

单片机课程设计——《基于AT89S52单片机和DS1302时钟芯片的电子时钟(可蓝牙校准)》

引言 本设计以AT89S52单片机为控制核心,时钟芯片DS1302提供时钟源,配合LCD1602液晶显示模块,组成基本硬件系统,同时利用HC-05嵌入式蓝牙串口通讯模块,可在手机端进行日期.时间的校准.具有走时精确,功耗低,显示直观,调整简单方便等优点. 功能描述 基本显示: 第一行为日期,依次为:年-月-日-星期 第二行为时间,依次为:时:分:秒 说明: 每月的天数,闰年的天数可自动调整 蓝牙校准日期: 命令d+年月日星期+#,如设置2016年12月8日星期四,手机发送命令:d16120804

Java实验-课程设计报告一:个人银行账户管理系统SavingAccountManageSystem-具体文档+源码

课程设计报告一:个人银行账户管理系统 此文档及源码仅供参考 不得直接复制使用 author: [xxxxxxxxx xx xxxx] date: "2019-04-12" 作 者:31415926535x 出 处:https://www.cnblogs.com/31415926535x/p/10697659.html 版权声明:署名 - 非商业性使用 - 禁止演绎,协议普通文本 | 协议法律文本. 不建议直接复制文档.源码,没意义,这东西还是自己手敲一下才能涨经验 项目所有的内容都已上

数据结构-课程设计-职工管理系统

职工管理管理系统--课程设计 本次课程设计,我还挺幸运的,抽到一道这么简单的题,思路很简单,但拓展很强,相比其他同学的,我这个简直是...,真是运气太好了, 代码写了1500多行吧,做课程设计中,我也学到了很多东西,代码太多,就放到了github上了 下面是一个总体概述,和一个README.md 其中README中以前分开写过,这次把他都写到了一起,所以就有点多~~~ 先来一个总体概述: 1.fstream的使用 字符串使用 3.排序的实现 排序使用的选择排序,采用的存储方式为链式结构,根据对象

南京邮电大学课程设计——加速度检测应用

2周的课程设计花了3天(其实真相是花了2个小时就写好了,只是老师一会让我改这一会让我改那而已)..这个时间可能有点长了,况且读者们看以下的的题目或许就要开始嘲笑我了,"这么简单的一个东西居然还要用那么久"...哈哈,不喜勿吐槽.... 题目3.压力监测应用 (1) 检测压力是否超过阈值 (2) 若超过压力阈值,则通过一条短信通知联系人,短信内容需包含当前压力. (3) 可设置联系人名称和联系手机号码 (4) 可设置压力阈值 (5) 记录告警信息到数据库,方便查询 以下开始直接贴代码: