精华内容
下载资源
问答
  • 安卓Android后台保活服务Demo,多厂商免杀,适配各大手机品牌的内存清理白名单。多进程互相唤醒保活。
  • 安卓后台下载 功能代码 安卓后台下载 代码安卓后台下载 代码
  • Android安卓后台运行白名单实现优雅保活 1.保活现状 随着谷歌的不断升级改造我们知道,Android 系统会存在杀后台进程的情况,并且随着系统版本的更新,杀进程的力度还有越来越大的趋势。系统这种做法本身...

    Android安卓后台运行白名单实现优雅保活

    1.保活现状
    随着谷歌的不断升级改造我们知道,Android 系统会存在杀后台进程的情况,并且随着系统版本的更新,杀进程的力度还有越来越大的趋势。系统这种做法本身出发点是好的,因为可以节省内存,降低功耗,也避免了一些流氓行为。为此作为开发者的我们被老板们逼着炒碎啦心,各种办法尝试,今天为各位大佬带来一篇优雅的保活模式,那就是后台运行白名单。 下次被产品说「莫某某软件都可以保活,为什么我们不行!」的时候,你就知道怎么怼回去了。大厂通过和手机厂商的合作,将自己的应用默认加入到白名单中。如果你在一个能谈成这种合作的大厂,也就不用往下看了。
    2.优雅保活?
    为了做到保活,出现了不少骚操作,比如 1 个像素的 Activity,播放无声音频,双进程互相守护等。这些做法可以说是很流氓了,甚至破坏了Android 的生态,好在随着 Android 系统版本的更新,这些非常规的保活手段很多都已失效了。对于那些确实需要在后台运行的应用,我们如何做到优雅的保活呢?
    3.后台运行白名单
    还好系统没有完全抛弃我们,运行我们申请的方式进入白名单,配置如下:
    • 1.在 AndroidManifest.xml 文件中加入一下权限:
      <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
    • 2.将以下代码复制在你的代码中:
    
    public class FcfrtAppBhUtils {
        /**
         * 判断我们的应用是否在白名单中
         * @param context
         * @return
         */
        @RequiresApi(api = Build.VERSION_CODES.M)
        public static boolean isIgnoringBatteryOptimizations(Context context) {
            boolean isIgnoring = false;
            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
            if (powerManager != null) {
                isIgnoring = powerManager.isIgnoringBatteryOptimizations(getPackageName());
            }
            return isIgnoring;
        }
    
        /**
         * 申请加入白名单
         * @param context
         */
        @RequiresApi(api = Build.VERSION_CODES.M)
        public static void requestIgnoreBatteryOptimizations(Context context) {
            try {
                Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + getPackageName()));
                context.startActivity(intent);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 跳转到指定应用的首页
         */
        private static void showActivity(Context context,@NonNull String packageName) {
            Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
            context.startActivity(intent);
        }
    
        /**
         * 跳转到指定应用的指定页面
         */
        private static void showActivity(Context context,@NonNull String packageName, @NonNull String activityDir) {
            Intent intent = new Intent();
            intent.setComponent(new ComponentName(packageName, activityDir));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    
        /**
         * 华为厂商判断
         * @return
         */
        public boolean isHuawei() {
            if (Build.BRAND == null) {
                return false;
            } else {
                return Build.BRAND.toLowerCase().equals("huawei") || Build.BRAND.toLowerCase().equals("honor");
            }
        }
    
        /**
         * 小米厂商判断
         * @return
         */
        public static boolean isXiaomi() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("xiaomi");
        }
        /**
         * OPPO厂商判断
         * @return
         */
        public static boolean isOPPO() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("oppo");
        }
        /**
         * VIVO厂商判断
         * @return
         */
        public static boolean isVIVO() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("vivo");
        }
    
        public static boolean isMeizu() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("meizu");
        }
        public static boolean isSamsung() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("samsung");
        }
        public static boolean isLeTV() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("letv");
        }
        public static boolean isSmartisan() {
            return Build.BRAND != null && Build.BRAND.toLowerCase().equals("smartisan");
        }
    
        /**
         * 跳转华为手机管家的启动管理页
         * 操作步骤:应用启动管理 -> 关闭应用开关 -> 打开允许自启动
         * @param context
         */
        public static void goHuaweiSetting(Context context) {
            try {
                showActivity(context,"com.huawei.systemmanager",
                        "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");
            } catch (Exception e) {
                showActivity(context,"com.huawei.systemmanager",
                        "com.huawei.systemmanager.optimize.bootstart.BootStartActivity");
            }
        }
    
        /**
         * 跳转小米安全中心的自启动管理页面
         * 操作步骤:授权管理 -> 自启动管理 -> 允许应用自启动
         * @param context
         */
        public static void goXiaomiSetting(Context context) {
            showActivity(context,"com.miui.securitycenter",
                    "com.miui.permcenter.autostart.AutoStartManagementActivity");
        }
    
        /**
         * 跳转 OPPO 手机管家
         * 操作步骤:权限隐私 -> 自启动管理 -> 允许应用自启动
         * @param context
         */
        public static void goOPPOSetting(Context context) {
            try {
                showActivity(context,"com.coloros.phonemanager");
            } catch (Exception e1) {
                try {
                    showActivity(context,"com.oppo.safe");
                } catch (Exception e2) {
                    try {
                        showActivity(context,"com.coloros.oppoguardelf");
                    } catch (Exception e3) {
                        showActivity(context,"com.coloros.safecenter");
                    }
                }
            }
        }
    
        /**
         * 跳转 VIVO 手机管家
         * 操作步骤:权限管理 -> 自启动 -> 允许应用自启动
         * @param context
         */
        public static void goVIVOSetting(Context context) {
            showActivity(context,"com.iqoo.secure");
        }
    
        /**
         * 跳转魅族手机管家
         * 操作步骤:权限管理 -> 后台管理 -> 点击应用 -> 允许后台运行
         * @param context
         */
        public static void goMeizuSetting(Context context) {
            showActivity(context,"com.meizu.safe");
        }
    
        /**
         * 跳转三星智能管理器
         * 操作步骤:自动运行应用程序 -> 打开应用开关 -> 电池管理 -> 未监视的应用程序 -> 添加应用
         * @param context
         */
        public static void goSamsungSetting(Context context) {
            try {
                showActivity(context,"com.samsung.android.sm_cn");
            } catch (Exception e) {
                showActivity(context,"com.samsung.android.sm");
            }
        }
    
        /**
         *跳转乐视手机管家
         * 操作步骤:自启动管理 -> 允许应用自启动
         * @param context
         */
        public static void goLetvSetting(Context context) {
            showActivity(context,"com.letv.android.letvsafe",
                    "com.letv.android.letvsafe.AutobootManageActivity");
        }
    
        public static void goSmartisanSetting(Context context) {
            showActivity(context,"com.smartisanos.security");
        }
    
    }
    
    • 使用方式
    if (!FcfrtAppBhUtils.isIgnoringBatteryOptimizations(this)){
                FcfrtAppBhUtils.requestIgnoreBatteryOptimizations(this)
            }
    
    • 申请时,应用上会出现这样一个窗口:
      在这里插入图片描述

    可以看到,这个系统弹窗会有影响电池续航的提醒,所以如果想让用户点允许,必须要有相关的说明。
    如果要判断用户是否点击了允许,可以在申请的时候调用 startActivityForResult,在 onActivityResult 里再判断一次是否在白名单中。

    展开全文
  • Android 后台 接口 json 数据 Java JavaEE Android后台通信 servlet doget dopost

    前言:

    作为一名android开发人员,网络数据都是web开发人员提供,每次让他们写一个接口都跟求神拜佛一样,与其求别人还不如自己动手,经过将近一天的研究,参考了很多的资料。总算研究出来了,写下来有的人可能会用到。也算是自己做个笔记。文章有些长。请细心看完。
    先看一下效果图:
    json数据接口:

    这里写图片描述
    把json数据格式化一下,看一下还行,凑合。
    这里写图片描述
    写一个Android 小demo试试。效果图:
    这里写图片描述

    接下来说教程:
    一、环境搭建
    我用的是Eclipsefor JavaEE+Tomcat7.0,暂时没有用到数据库,后续加上。
    先说一下Tomcat的环境搭建:
    一、安装JDK 1.7

    1、添加环境变量:在 我的电脑->属性->高级->环境变量
    
    2、新建系统变量,变量名:JAVA_HOME  变量值:C:\Program Files\Java\jdk1.7.0 (JDK的安装目录)
    
    3、在原有的系统变量 Path后面加上英文分号,
    

    再添加%JAVA_HOME%\bin;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\jre\bin;

    不要删除原来的。看清楚,它们之间的分号,是英文的分号。

    4、重启电脑生效(因为添加的是系统变量,如果你的系统是win7,则不需要重启)。
    
    4、测试JDK是否安装成功,运行->cmd ->D:  进入D盘,输入javac  看能否出来很多命令,出来则说明JDK配置成功。
    

    二、Tomcat 7.0的安装配置

    1、Tomcat 7.0 的免安装版的配置(假如将Tomcat 解压到C:\Program Files目录,
    

    目录结构为:C:\Program Files\apache-tomcat-7.0.11

           1、添加环境变量:在 我的电脑->属性->高级->环境变量
    
           2、新建系统变量,变量名:CATALINA_HOME  变量值:C:\Program Files\apache-tomcat-7.0.11 (Tomcat 解压到的目录)。
    
           3、在系统变量  Path的最后面添加
    

    %CATALINA_HOME%\lib;%CATALINA_HOME%\lib\servlet-api.jar;%CATALINA_HOME%\lib\jsp-api.jar

    注意它们之间的分号,一定是英文的分号。

           4、Tomcat 7.0的管理员的配置,进入C:\Program Files\apache-tomcat-7.0.11(Tomcat目录)下的conf目录,
    

    编辑tomcat-users.xml,找到最后的:

     <role rolename="tomcat"/>
    <role rolename="role1"/>
    <user username="tomcat" password="tomcat" roles="tomcat"/>
    <user username="both" password="tomcat" roles="tomcat,role1"/>
    <user username="role1" password="tomcat" roles="role1"/>

    在上面这段后面 添加上:

    <role rolename="manager-gui"/>
     <role rolename="admin-gui"/>
     <user username="admin" password="admin888" roles="admin-gui"/>
     <user username="tomcat" password="tomcat" roles="manager-gui"/>

    红色为添加部分。 到这应该知道我们添加的管理员的用户名和密码是多少了吧!

    5、进入Tomcat 目录下的bin目录,双击startup.bat 启动Tomcat 在命令行窗口会出来英文提示。

    6、浏览器输入:http://localhost:8080 可以看到Tomcat的欢迎页面就说明配置成功了,点击右上角上manager连接,输入上面配置的用户名和密码,就可以进入管理页面。如图所示

    这里写图片描述

    2.EclipseforJavaEE下载以及配置Tamcat服务
    EclipseforJavaEE 下载地址:
    http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/keplersr1
    这里写图片描述

    根据自己电脑的配置选择相应的eclipse下载即可。
    3.接下来说一下在Eclipse里配置service
    1.打开Eclipse后如图所示:

    这里写图片描述
    2.选择Window–>Perferences–>Service–>Runtim…选项
    这里写图片描述
    3.新建一个Service
    这里写图片描述

    按照步骤来就好

    这里写图片描述

    这里写图片描述

    点击finish即可。
    5。再点击Window–>showView–>Service选项把service窗口显示出来
    这里写图片描述
    6。查看底部工具栏,点击启动服务便可。
    这里写图片描述

    至此配置完成,接下来到代码部分:
    1.先新建一个web工程,选择File–>NewProject–>Web–>Dynamic..选项:
    这里写图片描述

    2。输入工程名,下一步

    这里写图片描述

    3。略过 ,下一步
    这里写图片描述

    4。在这一步,这个对勾一定要打上,否则后面会很受罪,亲身感受。。。。
    这里写图片描述

    5。点击Finish 完成
    6。在WebContent文件夹下面新建img文件夹,在img文件夹里放上图片。这里写图片描述
    7。在Webcontent文件夹下新建一个jsp文件,文件名暂时取为index,
    8。打开WEB-INF–>下的web.xml 文件如图所示:
    这里写图片描述
    9。修改web.xml文件,web.xml代码如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="2.4" 
        xmlns="http://java.sun.com/xml/ns/j2ee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      <servlet>
        <description>This is the description of my J2EE component</description>
        <display-name>This is the display name of my J2EE component</display-name>
        <servlet-name>GetDataServlet</servlet-name>
        <servlet-class>com.dfwy.servlet.GetDataServlet</servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>GetDataServlet</servlet-name>
        <url-pattern>/servlet/GetDataServlet</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
        <welcome-file>index1.jsp</welcome-file>
        <welcome-file>test.jsp</welcome-file>
      </welcome-file-list>
    </web-app>

    10。打开java Resources文件下的src,在src文件夹下新建两个包,名字自定义就好,如图
    这里写图片描述
    11。在domain包下新建一个Girl类,在类里定义几个属性,在获取set,get方法,toString方法
    代码如下:

    package com.dfwy.domain;
    
    public class Girl {
        private int id;
        private String name;
        private String image;
        /**
         *set和get方法
         */
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getImage() {
            return image;
        }
        public void setImage(String image) {
            this.image = image;
        }
        @Override
        public String toString() {
            return "People [id=" + id + ", image=" + image + ", name=" + name + "]";
        }
    
    }
    

    12。下载gson,和servlet-api 两个jar包,粘贴到WEB-INF下的lib文件夹下。
    这里写图片描述
    13。选中这两个jar包,右击选择buildPath–>add..选项
    这里写图片描述
    14。在servlet包下新建GetDataServlet类,这是核心代码。代码如下

    package com.dfwy.servlet;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.logging.Logger;
    
    import javax.servlet.RequestDispatcher;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.xml.ws.Response;
    
    import com.dfwy.domain.Girl;
    import com.google.gson.Gson;
    
    public class GetDataServlet extends HttpServlet{
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //获得gson对象
            Gson gson = new Gson();
            //模拟从数据库获得数据
            List<Girl>girls = new ArrayList<>();
            for(int i = 1;i<=9;i++){
                Girl girl = new Girl();
                girl.setId(i);
                girl.setName("大美女girl"+i);
                 /* 
                 * request.getContextPath()获得该项目的根路径 即 “/HouTai” 获得图片的路径 
                 * 即相当于“/HouTai/img/girl.jpg”循环读取图片的路径 
                 * request.getContextPath()+"/img/girl"+i+".jpg" 
                 */ 
                girl.setImage(req.getContextPath()+"/img/girl"+i+".jpg");
                girls.add(girl);
            }
              // 调用gson.toJson()传入一个对象,返回为该对象转换为json格式的字符串  
            String string = gson.toJson(girls);
            req.setAttribute("data","{\"data\":" + string + "}");
            //跳转到index.jsp页面进行显示
            RequestDispatcher rd = req.getRequestDispatcher("/test.jsp");
            try{
                rd.forward(req, resp);
                return;
            }catch(Exception e){
                System.out.println("eeeee");
            }
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // TODO Auto-generated method stub
        }   
    
    }
    
    

    然后右击GetDataServelt.java选择RunAsServerce就看到了想要的界面,把local host改成你电脑的IP地址,在统一局域往下就可以访问了。:
    这里写图片描述
    二、Android 端展示:
    Android 端就比较简单了,在这里就不详细介绍了,简单说一下思路便可
    新建一个异步在异步里获取接口数据,获得到json数据,新键一个BaseAdapter 在里面处理列表数据便可。有需要可以评论交流哦。
    至此完成。

    展开全文
  • Android后台开启服务默默拍照http://blog.csdn.net/yangzl2008/article/details/9262505
  • 安卓后台保活服务service,自动重启APP
  • android 后台监听按键事件方法及demoandroid 后台监听按键事件方法及demo
  • android后台服务定位

    热门讨论 2013-07-19 10:24:21
    android后台服务定位 设置为开机自动启动
  • 主要介绍了Android 后台运行白名单实现保活,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 主要介绍了Android后台定时提醒功能,针对Service,AlarmManager的使用进行详细阐述,感兴趣的小伙伴们可以参考一下
  • Android 后台Service 实现录像,无页面
  • android后台服务自启动

    2014-08-01 09:52:09
    android后台服务自启动
  • 本文主要内容: 1、Android 后台耗电指标及优化建议; 2、后台耗电分析开源工具battery_analyze; 3、后台耗电常见监控方案及示例;

    原文见: 在路上的blog

    主要参考资料:

    开源后台耗电分析工具: battery_alalyze
    在这里插入图片描述

    一、什么是耗电优化?

    在实践中,如果我们的应用需要播放视频、获取GPS信息、需要拍照,这些耗电看起来是无法避免的。
    如果发现某个应用没怎么使用(前台时间很少),但是耗电却非常多。这种情况会跟用户的预期差别很大,这种情况就需要优化。

    二、耗电优化第一个方向:优化后台耗电

    根据Android Vitals定义,影响后台耗电的动作如下:

    • 唤醒锁定操作卡住
    • 唤醒锁定操作卡住(后台)
    • 唤醒次数过多
    • WLAN 扫描次数过多(后台)
    • 网络使用量过高(后台)

    1、唤醒锁定操作卡住(前台&后台)

    应用会通过调用带有 PARTIAL_WAKE_LOCK 标记的 acquire() 来获取部分唤醒锁定。当您的应用在后台运行时,如果部分唤醒锁定保持了较长时间,则会变为卡住状态(用户看不到应用的任何部分)。 它会阻止设备进入低功耗状态。部分唤醒锁定仅应在必要时使用,并且在不再需要时立即释放。

    Android Vitals 报告部分唤醒锁定卡住的条件是在以下任一时段内至少发生了一次时长达 1 小时的部分唤醒锁定:
    (1)所有情况下至少 0.70% 的电池工作时段

    (2)仅在后台运行时至少 0.10% 的电池工作时段

    唤醒锁定操作卡住的问题发现和修复建议

    2、唤醒次数过多

    唤醒是 AlarmManagerAPI 中的一种机制,可让开发者设置闹钟以在指定时间唤醒设备。为设置唤醒闹钟,您的应用会调用 AlarmManager 中某个带有 RTC_WAKEUPELAPSED_REALTIME_WAKEUP 标记的 set() 方法。当唤醒闹钟触发时,设备会在执行闹钟的 onReceive()onAlarm() 方法期间退出低功耗模式并保持部分唤醒锁定。如果唤醒闹钟触发次数过多,则可能会耗尽设备的电池电量。

    唤醒次数过多标准:用户遇到每小时 10 次以上唤醒的电池工作时段数百分比。

    • Vital 详细信息:
      • 受影响的工作时段数:用户遇到每小时 10 次以上唤醒的电池工作时段数百分比。电池会话是指设备在两次充满电之间的间隔时间。Google 仅会在设备未充电时收集这项数据。
      • 会话数:系统已记录的会话的大概数量。
      • 第 90/99 个百分位:10%/1% 的每日工作时段中用户每小时遇到唤醒次数高于显示的值。
        最低 25%:如果您的应用发生问题的工作时段比例等于或高于显示的阈值,则系统会将此应用归在这项指标的最低 25% 区间(依据为 Google Play 上前 1000 个热门应用,按安装量统计)。

    唤醒过多修复及建议

    3、WLAN扫描次数过多(后台)

    当应用在后台执行 WLAN 扫描时,它会唤醒 CPU,从而加快耗电速度。扫描次数过多时,设备的电池续航时间可能会明显缩短。如果某个应用处于 PROCESS_STATE_BACKGROUND 或 PROCESS_STATE_CACHED 状态,则会被视为在后台运行。

    WLAN 扫描次数过多的标准:在后台运行时,应用在 0.10% 的电池工作时段内每小时执行的扫描超过 4 次。

    建议:如果可能,您的应用执行 WLAN 扫描时应该是在前台运行。前台服务会自动显示通知;在前台执行 WLAN 扫描,从而让用户知道设备上发生 WLAN 扫描的原因和时间。

    扫描次数过多优化:如果您的应用无法避免在后台运行期间执行 WLAN 扫描,则可能适合采用偷懒至上策略。“偷懒至上”包含三种可用于消减 WLAN 扫描次数的方法:“减少”、“推迟”和“合并”。如需了解这些方法,请参阅针对电池续航时间进行优化

    4、后台移动网络使用量过高

    当应用在后台连接移动网络时,应用会唤醒 CPU 并开启无线装置。如果反复执行此操作,可能会耗尽设备的电池电量。如果某个应用处于 PROCESS_STATE_BACKGROUND 或 PROCESS_STATE_CACHED 状态,则会被视为在后台运行。

    后台网络使用量过高的标准:在后台运行时,应用在 0.10% 的电池工作时段内每小时发送和接收的数据合计达 50 MB。

    建议:可以将应用的移动网络使用量移至前台,提醒用户目前正在进行下载,并为他们提供暂停或停止下载的控件。为此,请调用 DownloadManager 并根据情况设置 setNotificationVisibility(int)

    三、耗电优化第二个方向:让系统认为是正常耗电

    如何让系统认为是正常耗电呢?当耗电指标低于规则时,系统也就认为是正常耗电了。

    (1)海外应用

    海外应用主要参考Google Vitals的规则。
    对于Google Vitals的后台耗电过多统计规则中的电池工作时段百分比,对于质量评估来看,较难把握。所以主要关注规则的具体指标,即相对更严格的质量要求:
    在这里插入图片描述

    (2)国内应用之华为后台资源红线标准

    在这里插入图片描述

    (3)经验性总结规则

    对于国内应用来说,目前还没有非常通用且权威的后台耗电规则,根据经验,我们将监控的内容抽象成规则。
    当然不同应用监控的事项或者参数都不太一样。由于每个应用的具体情况都不太一样。
    下面是一些可以用来参考的简单规则。
    在这里插入图片描述

    四、耗电监控

    那我们的耗电监控系统应该监控哪些内容,怎么样才能比 Android Vitals 做得更好呢?

    • 监控信息:简单来说系统关心什么,我们就监控什么,而且应该以后台耗电监控为主。类似 Alarm wakeup、WakeLock、WiFi scans、Network 都是必须的,其他的可以根据应用的实际情况。如果是地图应用,后台获取 GPS 是被允许的;如果是计步器应用,后台获取 Sensor 也没有太大问题。
    • 现场信息:监控系统希望可以获得完整的堆栈信息,比如哪一行代码发起了 WiFi scans、哪一行代码申请了 WakeLock 等。还有当时手机是否在充电、手机的电量水平、应用前台和后台时间、CPU 状态等一些信息也可以帮助我们排查某些问题。

    1、google vitals不适合

    缺点:

    • 耗电规则无法修改
    • 无法拿到堆栈和其他电池信息
    • 国内应用无法使用

    2、合适的耗电监控方式

    (1)解析bugreport

    通常大家可能会使用Battery Historian来分析后台耗电,但是不够灵活。比如需要人工查看各资源使用情况及是否达标。所以用python实现了一个简单的分析bugreport文件的小工具;
    核心代码是刚做测开半年左右写的,比较乱且水平有限,大家轻拍,也欢迎大家参与优化。

    • 实现逻辑:
      • 重置电池统计信息和历史记录(dumpsys batterystats --reset)
      • 打开详细的wakelock数据开关,日志量较大,一般可正常保存3个小时以内。
        • dumpsys batterystats --enable full-wake-history --启用
        • dumpsys batterystats --disable full-wake-history --关闭
      • 导出bugreport文件
        • Android 7.0 and higher: adb bugreport > bugreport.zip
        • Android 6.0 and lower: adb bugreport > bugreport.txt
      • 利用battery_analyze生成后台耗电报告
        在这里插入图片描述

    (2)Java Hook

    Hook 方案的好处在于使用者接入非常简单,不需要去修改自己的代码。下面我以几个比较常用的规则为例,看看如果使用 Java Hook 达到监控的目的。

    • WakeLock:WakeLock 用来阻止 CPU、屏幕甚至是键盘的休眠。类似 Alarm、JobService 也会申请 WakeLock 来完成后台 CPU 操作。WakeLock 的核心控制代码都在PowerManagerService中,实现的方法非常简单。
    
    // 代理 PowerManagerService
    ProxyHook().proxyHook(context.getSystemService(Context.POWER_SERVICE), "mService", this)@Override
    public void beforeInvoke(Method method, Object[] args) {
        // 申请 Wakelock
        if (method.getName().equals("acquireWakeLock")) {
            if (isAppBackground()) {
                // 应用后台逻辑,获取应用堆栈等等     
             } else {
                // 应用前台逻辑,获取应用堆栈等等
             }
        // 释放 Wakelock
        } else if (method.getName().equals("releaseWakeLock")) {
           // 释放的逻辑    
        }
    }
    
    // 代理 AlarmManagerService
    new ProxyHook().proxyHook(context.getSystemService
    (Context.ALARM_SERVICE), "mService", this)public void beforeInvoke(Method method, Object[] args) {
        // 设置 Alarm
        if (method.getName().equals("set")) {
            // 不同版本参数类型的适配,获取应用堆栈等等
        // 清除 Alarm
        } else if (method.getName().equals("remove")) {
            // 清除的逻辑
        }
    }
    
    • 其他:对于后台 CPU,我们可以使用卡顿监控相关的方法。对于后台网络,同样我们可以通过网络监控相关的方法。对于 GPS 监控,我们可以通过 Hook 代理LOCATION_SERVICE。对于 Sensor,我们通过 Hook SENSOR_SERVICE中的“mSensorListeners”,可以拿到部分信息。

    通过 Hook,我们可以在申请资源的时候将堆栈信息保存起来。当我们触发某个规则上报问题的时候,可以将收集到的堆栈信息、电池是否充电、CPU 信息、应用前后台时间等辅助信息也一起带上。

    (3)插桩

    虽然使用 Hook 非常简单,但是某些规则可能不太容易找到合适的 Hook 点。而且在 Android P 之后,很多的 Hook 点都不支持了。
    出于兼容性考虑,我首先想到的是写一个基础类,然后在统一的调用接口中增加监控逻辑。以 WakeLock 为例:

    public class WakelockMetrics {
        // Wakelock 申请
        public void acquire(PowerManager.WakeLock wakelock) {
            wakeLock.acquire();
            // 在这里增加 Wakelock 申请监控逻辑
        }
        // Wakelock 释放
        public void release(PowerManager.WakeLock wakelock, int flags) {
            wakelock.release();
            // 在这里增加 Wakelock 释放监控逻辑
        }
    }
    

    Facebook 也有一个耗电监控的开源库Battery-Metrics,它监控的数据非常全,包括 Alarm、WakeLock、Camera、CPU、Network 等,而且也有收集电量充电状态、电量水平等信息。
    Battery-Metrics 只是提供了一系列的基础类,在实际使用中,接入者可能需要修改大量的源码。但对于一些第三方 SDK 或者后续增加的代码,我们可能就不太能保证可以监控到了。这些场景也就无法监控了,所以 Facebook 内部是使用插桩来动态替换。
    遗憾的是,Facebook 并没有开源它们内部的插桩具体实现方案。大家可以自行搜索不同插桩方案的实现。
    插桩方案使用起来兼容性非常好,并且使用者也没有太大的接入成本。但是它并不是完美无缺的,对于系统的代码插桩方案是无法替换的,例如 JobService 申请 PARTIAL_WAKE_LOCK 的场景。

    五、名次解释

    • 电池工作时段:是指两次电池充满电的时间间隔。
    展开全文
  • 适合在 Delphi XE8一下 开发android后台服务例程
  • android后台截屏

    热门讨论 2014-05-08 08:48:28
    实现非root后台截屏,针对各种你想截屏的程序进行截屏,后台服务进行截屏.
  • android后台保持不死

    2017-10-13 14:22:13
    用本例子是不断保持后台唤醒的例子源码,这是修改之后的,安装之后就能不断的唤醒,实现后台service持续运行,并且唤醒之后进入自定义界面,4.2.2测试唤醒的时候程序可以直接绕过屏幕锁但是点一下还是会出现锁屏界面...
  • Android后台服务Service

    万次阅读 2018-03-27 00:16:57
    后台服务桌面应用程序:可见服务:不可见 长期在后台运行 帮助应用执行耗时的操作 安卓的服务:安卓四大组件之一 不可见 后台长期运行 界面与服务有时候要执行数据交互如何创建服务:1. 创建一个类 继承Service....

    后台服务

    桌面应用程序:可见

    服务:不可见  长期在后台运行 帮助应用执行耗时的操作

    安卓的服务:安卓四大组件之一  不可见   后台长期运行 界面与服务有时候要执行数据交互

    如何创建服务:

    1. 创建一个类 继承Service.


    package com.li.servce;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    
    public class MyService extends Service{
    	//Service启动时调用
    	@Override
    	public void onCreate() {
    		super.onCreate();
    		Log.v("wang", "OnCreate 服务启动时调用");
    		
    	}
    	@Override
    	public IBinder onBind(Intent intent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    	//服务被关闭时调用
    	@Override
    	public void onDestroy() {
    		super.onDestroy();
    		Log.v("wang", "onDestroy 服务关闭时");
    	}
    
    }

    四大组件多需要配置配置


     <service android:name="com.li.servce.MyService"></service> <!--绑定一个服务类-->

    调用服务器

    package com.li.servce;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    	}
    	public void createServiceClick(View v){
    		Intent intent = new Intent(this,MyService.class);
    		//启动servicce服务
    		startService(intent);
    	}
    	//虽然应用界面已经退出  但是服务还是存在的
    	//停止服务  可以通过按钮来关闭   可以通过代码关闭服务
    	public void clickStopService(View v){
    		Intent name= new Intent(this,MyService.class);
    		stopService(name);//name表示停止哪一个服务
    	}
    	
    }
    

    电话窃听器原理

    开发步骤:

    1. 创建一个后台运行的服务

    2. 启动应用的时候启动服务

    3. onCreate()调用的时候 创建一个系统的服务 并获取电话的状态

    TelephonyManagermanager=(TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

    //1. 注册监听器  2. 监听的事件

    代码:

    package com.li.callMyVoce;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.telephony.PhoneStateListener;
    import android.telephony.TelephonyManager;
    import android.util.Log;
    
    public class CallService extends Service{
    	@Override
    	public void onCreate() {
    		super.onCreate();
    		//开始时刻接听用户电话状态   休闲(没有接听电话)   邻响    接通    挂断
    		//如果自己去写代码接通用户状态  会很复杂 的操作  求系统
    		//系统服务getSystemService(name)   电话有关的服务      服务的后缀一般以service manager ...作为后缀
    		//TelephonyManager  他表示可以接听各种各样跟手机有关的很多服务  他表是一个大的概念
    		TelephonyManager manager=(TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    										 												//manager.listen(listener, events)
    		manager.listen(new PhoneStateListener(){										//listener表是接听手机的那个状态比如说接听电话的服务new PhoneStateListenter()//重写方法等等
    			@Override
    			public void onCallStateChanged(int state, String incomingNumber) {//incomingNumber表示电话号码   只有来点时才有值
    				switch (state) {
    				case TelephonyManager.CALL_STATE_IDLE:
    					Log.v("wang", "CALL_STATE_IDLE   休闲状态     挂断");
    					break;
    				case TelephonyManager.CALL_STATE_OFFHOOK:
    					Log.v("wang", "CALL_STATE_OFFHOOK  接通");
    					break;
    				case TelephonyManager.CALL_STATE_RINGING:
    					Log.v("wang", "CALL_STATE_RINGING    电话铃声响状态"+incomingNumber);
    					break;
    				}
    			}
    		}, PhoneStateListener.LISTEN_CALL_STATE);									
    																						// events  就是要指定对那些事件比较关心
    	}
    	@Override
    	public IBinder onBind(Intent intent) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    

    调用:

    package com.li.callMyVoce;
    
    import android.app.Activity;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    
    public class MainActivity extends Activity {
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    	//1.时时刻刻的接听用户当前的打电话状态  ----> Service
    	//2.当用户开启接听电话的时候  开始录音   用户挂断了电话停止录音--->录音功能
    	//3.当发现网络状态(广播  判断是否有网络)是开着的时候就应该发送录音到后台服务器
    	}
    	public void clickService(View v){
    		Intent intent = new Intent(this,CallService.class);
    		startService(intent);
    	}
    }
    

    配置文件里面的铭感操作

         <!-- 绑定服务器 -->
            <service android:name="com.li.callMyVoce.CallService"></service>
     <!-- 电话的铭感操作 -->
    	<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    服务和子线程的区别

    总结:

    * 服务是长期在后台运行的

    * 开启一个用真的死循环的子线程也是在后台长期运行

    *如果一个应用程序有后台的服务在运行,即使你杀掉进程,进程和服务还会自动的复活

    * 如果一个应用程序只有后台的子线程运行 杀掉进程进程和子线程都挂了

    * 如果你要保证一个后台的操作长期运行1.开启服务 2.在服务里面创建线程


    展开全文
  • Android后台拍照功能

    2016-02-22 14:52:35
    Android可在后台拍照功能Android可在后台拍照功能
  • Android后台开发流程

    2016-07-29 07:27:18
    最近想转行做Android后台开发,但不大清楚后台开发的流程,中间需要做什么准备,求详细介绍!!
  • 用java写安卓后台(简易版,适合新手),包括tomcat一些细节问题
  • Android后台任务

    2020-05-17 14:21:44
    每个 Android 应用都有一个主线程,负责处理界面(包括测量和绘制视图)、协调用户互动以及接收生命周期事件。如果有太多工作在主线程中进行,则应用可能会挂起或运行速度变慢,从而导致用户体验不佳。任何长时间...
  • android后台运行技巧

    2012-06-04 15:41:42
    教你如何在android实现后台运行,让你轻松掌握~
  • android后台进程

    千次阅读 2012-03-24 17:23:37
    Android 后台进程运行规则 回 复 收 藏 fid:65/tid:3155676 楼主:塞班巡警零零柒 等级: 2011年03月08日 19:03:21 android大多应用没有退出的设计其实是有道理的,这和系统对进程的调度...
  • Android后台保活套路分析

    千次阅读 2018-10-15 14:16:09
    Android后台保活套路分析 原文作者:D_clock爱吃葱花 链接:https://www.jianshu.com/p/63aafe3c12af 來源:简书 基于个人理解进行了部分删减补充 保活手段 当前业界的Android进程保活手段主要分为 黑、白...
  • androrid android studio 后台接口 后台 服务 数据库 前端交互 post
  • Android 后台截图

    千次阅读 2017-12-25 10:13:48
    系统是Android 2.3以上: adb shell screencap -p xxx.png 系统是Android 4.0以上: adb shell screenshot xxx.png 但有时候要看系统编译时有那个命定,我们产品系统是4.4和6.0,但只有screencap 查看有那个名单...
  • Android后台保活

    2021-04-12 08:36:39
    9.0以上设备,开启应用后台自启动功能,可以延长应用在后台的存活时间。不同厂商设置方式如下: 1、三星: 设置-》常规管理-》电池-》-》菜单(右上角三个点)-》自动运行应用程序-》民生魔方,开启自动应用 说明...
  • android 后台服务运行,保持不被干掉

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 216,397
精华内容 86,558
关键字:

安卓后台