Android数据统计



数据统计


今天我们来学习安卓5.0中的数据统计。数据统计是用于统计用户的使用行为。包括他使用了什么APP?使用了多长?在什么时候打开的?我们可以在后台进行收集这些信息,来分析它的爱好、兴趣等等。听到这里,大家会不会觉得,这是不是侵犯了用户的隐私呢?是的,所以说在安卓5.0中,数据统计,它必须是要经过用户同意,或者说你是要是系统的应用,才可以。
那要使用数据统计,那就需要一个权限。大家注意啊!在申明的时候,我需要在这个ManiFest里面去申明这个权限。


0.png


安卓给我们提供的数据统计的功能,可以按年、按月、按日来进行统计。使用方法呢!也非常简单。



实例


首先我们需要获取一个数据统计的列。


package com.murraycole.appusagesample;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
 
/**
 * Created by User on 3/2/15.
 */
public class UStats {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("M-d-yyyy HH:mm:ss");
    public static final String TAG = UStats.class.getSimpleName();
    @SuppressWarnings("ResourceType")
    public static void getStats(Context context){
        UsageStatsManager usm = (UsageStatsManager) context.getSystemService("usagestats");
        int interval = UsageStatsManager.INTERVAL_YEARLY;
        Calendar calendar = Calendar.getInstance();
        long endTime = calendar.getTimeInMillis();
        calendar.add(Calendar.YEAR, -1);
        long startTime = calendar.getTimeInMillis();
        Log.d(TAG, "Range start:" + dateFormat.format(startTime) );
        Log.d(TAG, "Range end:" + dateFormat.format(endTime));
        UsageEvents uEvents = usm.queryEvents(startTime,endTime);
        while (uEvents.hasNextEvent()){
            UsageEvents.Event e = new UsageEvents.Event();
            uEvents.getNextEvent(e);
            if (e != null){
                Log.d(TAG, "Event: " + e.getPackageName() +"\t" + e.getEventType()+ "\t" +  e.getTimeStamp());
            }
        }
    }
    public static List<UsageStats> getUsageStatsList(Context context){
        UsageStatsManager usm = getUsageStatsManager(context);
        Calendar calendar = Calendar.getInstance();
        long endTime = calendar.getTimeInMillis();
        calendar.add(Calendar.MONTH, -1);
        long startTime = calendar.getTimeInMillis();
        Log.d(TAG, "Range start:" + dateFormat.format(startTime) );
        Log.d(TAG, "Range end:" + dateFormat.format(endTime));
        List<UsageStats> usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,startTime,endTime);
        printUsageStats(usageStatsList);
        Log.d(TAG,"+++++++++++++++++++++++INTERVAL_MONTHLY");
        usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_MONTHLY,startTime,endTime);
        printUsageStats(usageStatsList);
        Log.d(TAG,"+++++++++++++++++++++++INTERVAL_WEEKLY");
        usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_WEEKLY,startTime,endTime);
        printUsageStats(usageStatsList);
        Log.d(TAG,"+++++++++++++++++++++++INTERVAL_BEST");
        usageStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_BEST,startTime,endTime);
        printUsageStats(usageStatsList);
        return usageStatsList;
    }
    public static void printUsageStats(List<UsageStats> usageStatsList){
        for (UsageStats u : usageStatsList){
            Log.d(TAG, "Pkg: " + u.getPackageName() +  "\t" + "ForegroundTime: "
                    + u.getTotalTimeInForeground()) ;
        }
    }
    public static void printCurrentUsageStatus(Context context){
        printUsageStats(getUsageStatsList(context));
    }
    @SuppressWarnings("ResourceType")
    private static UsageStatsManager getUsageStatsManager(Context context){
        UsageStatsManager usm = (UsageStatsManager) context.getSystemService("usagestats");
        return usm;
    }
}


如果要用到数据统计,我们首先需要获取一个这个类的对象:


1.png



通过什么方式获取这个类的对象呢?我们可以通过得到系统服务的方式来获取。


2.png



这里要注意的是,前面我们也说到,因为这是和用户隐私相关的,所以谷歌是不推荐第三方使用的。因此它这个API,其实是隐藏的。


3.png



我们可以看到这个Context这个类,虽然在这里面定义了这个常亮,但是它的API是隐藏的。


4.png



获取了UsageStatsManager之后,接下来,我们要告诉系统,从哪个日期到哪个日期范围。


5.png



我们只需要调用UsageStatsManager的queryUsageStats这个方法:这个方法,大家要注意哈!有三个参数:第一个参数是:你统计的时间间隔。第二个参数是:这是要统计的开始时间。第三个参数是结束时间。


6.png



我们来看UsageStats包含哪些信息,就可以知道,我们可以统计哪些数据。


7.png



点击进来之后,大家可以看到如下源码:


/**
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy
 * of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package android.app.usage;
import android.os.Parcel;
import android.os.Parcelable;
/**
 * Contains usage statistics for an app package for a specific
 * time range.
 */
public final class UsageStats implements Parcelable {
    /**
     * {@hide}
     */
    public String mPackageName;
    /**
     * {@hide}
     */
    public long mBeginTimeStamp;
    /**
     * {@hide}
     */
    public long mEndTimeStamp;
    /**
     * {@hide}
     */
    public long mLastTimeUsed;
    /**
     * {@hide}
     */
    public long mTotalTimeInForeground;
    /**
     * {@hide}
     */
    public int mLaunchCount;
    /**
     * {@hide}
     */
    public int mLastEvent;
    /**
     * {@hide}
     */
    public UsageStats() {
    }
    public UsageStats(UsageStats stats) {
        mPackageName = stats.mPackageName;
        mBeginTimeStamp = stats.mBeginTimeStamp;
        mEndTimeStamp = stats.mEndTimeStamp;
        mLastTimeUsed = stats.mLastTimeUsed;
        mTotalTimeInForeground = stats.mTotalTimeInForeground;
        mLaunchCount = stats.mLaunchCount;
        mLastEvent = stats.mLastEvent;
    }
    public String getPackageName() {
        return mPackageName;
    }
    /**
     * Get the beginning of the time range this {@link android.app.usage.UsageStats} represents,
     * measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getFirstTimeStamp() {
        return mBeginTimeStamp;
    }
    /**
     * Get the end of the time range this {@link android.app.usage.UsageStats} represents,
     * measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getLastTimeStamp() {
        return mEndTimeStamp;
    }
    /**
     * Get the last time this package was used, measured in milliseconds since the epoch.
     * <p/>
     * See {@link System#currentTimeMillis()}.
     */
    public long getLastTimeUsed() {
        return mLastTimeUsed;
    }
    /**
     * Get the total time this package spent in the foreground, measured in milliseconds.
     */
    public long getTotalTimeInForeground() {
        return mTotalTimeInForeground;
    }
    /**
     * Add the statistics from the right {@link UsageStats} to the left. The package name for
     * both {@link UsageStats} objects must be the same.
     * @param right The {@link UsageStats} object to merge into this one.
     * @throws java.lang.IllegalArgumentException if the package names of the two
     *         {@link UsageStats} objects are different.
     */
    public void add(UsageStats right) {
        if (!mPackageName.equals(right.mPackageName)) {
            throw new IllegalArgumentException("Can't merge UsageStats for package '" +
                    mPackageName + "' with UsageStats for package '" + right.mPackageName + "'.");
        }
        if (right.mEndTimeStamp > mEndTimeStamp) {
            mLastEvent = right.mLastEvent;
            mEndTimeStamp = right.mEndTimeStamp;
            mLastTimeUsed = right.mLastTimeUsed;
        }
        mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
        mTotalTimeInForeground += right.mTotalTimeInForeground;
        mLaunchCount += right.mLaunchCount;
    }
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mPackageName);
        dest.writeLong(mBeginTimeStamp);
        dest.writeLong(mEndTimeStamp);
        dest.writeLong(mLastTimeUsed);
        dest.writeLong(mTotalTimeInForeground);
        dest.writeInt(mLaunchCount);
        dest.writeInt(mLastEvent);
    }
    public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
        @Override
        public UsageStats createFromParcel(Parcel in) {
            UsageStats stats = new UsageStats();
            stats.mPackageName = in.readString();
            stats.mBeginTimeStamp = in.readLong();
            stats.mEndTimeStamp = in.readLong();
            stats.mLastTimeUsed = in.readLong();
            stats.mTotalTimeInForeground = in.readLong();
            stats.mLaunchCount = in.readInt();
            stats.mLastEvent = in.readInt();
            return stats;
        }
        @Override
        public UsageStats[] newArray(int size) {
            return new UsageStats[size];
        }
    };
}


第一个是我们的应用程序的包名,也就是说,它可以知道某个应用程序的信息。然后是,这是开始统计时间。然后是结束统计时间。


8.png



这个是最近一个使用的时间:


9.png



这个是这个程序所有的前台使用的时间:


90.png



然后,这个是它的启动次数:


91.png



以及上一个事件,上一个事件是指,它是启动还是关闭等:


92.png



通过返回的List,我们就可以知道它的一些信息。这里我只是做了一个log,把它打印出来:


93.png



这是一方面。然后,还有一种统计方式,是统计事件。统计事件,大家可以看到,这里有一个方法:queryEvent,它的参数相对比较简单,就是开始事件和结束时间。然后它会取到这么一个Event。


94.png



我们可以看一下这个Event:


95.png



它包含哪些事件呢?


第一个是没有事件:


/**
 * No event type.
 */
public static final int NONE = 0;


第二个是从后台移到前台时的事件:


/**
 * An event type denoting that a component moved to the foreground.
 */
public static final int MOVE_TO_FOREGROUND = 1;


然后,是从前台移到后台的事件:


/** * An event type denoting that a component moved to the background. */public static final int MOVE_TO_BACKGROUND = 2;


然后,这是一天结束的事件:


/**
 * An event type denoting that a component was in the foreground when the stats
 * rolled-over. This is effectively treated as a {@link #MOVE_TO_BACKGROUND}.
 * {@hide}
 */
public static final int END_OF_DAY = 3;


然后,这是继续昨天的事件:


/** * An event type denoting that a component was in the foreground the previous day. * This is effectively treated as a {@link #MOVE_TO_FOREGROUND}. * {@hide} */public static final int CONTINUE_PREVIOUS_DAY = 4;


以及这个是配置改变的事件:


/**
 * An event type denoting that the device configuration has changed.
 */
public static final int CONFIGURATION_CHANGE = 5;


通过这几个事件,我们就可以知道这个应用程序的一些行为。好,我们运行一下我们的程序。这是我们启动的程序:


96.png



然后,我们点击程序界面中的按钮,然后我们再看看打印出来的日志:


97.png



先是打印了一个时间的范围。然后,这里是一个按天算的使用时间。


98.png



然后,这是按月算的使用时间:


99.png



对应用程序的使用时间的统计,那还有一个更详细的,前面说到了:事件的统计。们改一下代码,把这个事件的统计打印出来:


990.png



然后,我们再次运行程序,点击按钮,打印出了日志:这里,前面是包名,1是代表打开,2是代表关闭。


991.png



然后,我们可以从这个Event事件这里可以看到:1是move到前台;2是到后台,相当于是关闭。


/**
 * An event type denoting that a component moved to the foreground.
 */
public static final int MOVE_TO_FOREGROUND = 1;
/**
 * An event type denoting that a component moved to the background.
 */
public static final int MOVE_TO_BACKGROUND = 2;


这里要说到的是,我们之前也提到了:普通的应用程序默认的情况下,它是没有统计权限的,那我们需要在设置里面:


992.png



然后我们找到设置里面有一个安全选项:


993.png



在安全选项的下方,有一个应用程序的数据的访问:


994.png



点到这里,用户必须是要打开它之后,你才能够统计到,或者说你本身就是带有系统签名的。


995.png



一般情况下,我们都需要在启动的时候判断一下,如果你需要统计,让用户知道,你需要跳转到这个界面,跳转到界面的Intent是这样写的:


//Check if permission enabled
if (UStats.getUsageStatsList(this).isEmpty()){
    Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
    startActivity(intent);
}


我这里这个setting里面写到了,点击它就可以跳转到这个页面:


996.png



跳转成功:


997.png



整个程序是非常简单,这里演示了一下统计数据的使用方式。



【本文由麦子学院独家原创,转载请注明出处并保留原文链接】

logo
© 2012-2016 www.maiziedu.com
蜀ICP备13014270号-4 Version 5.0.0 release20160127

免费领取价值1888元求职宝典!

客服热线 400-862-8862

回到顶部