android– 如何创建一个持续监控应用程序使用信息的服务?

android– 如何创建一个持续监控应用程序使用信息的服务?,第1张

概述手头的问题:我必须创建一个持续运行的服务.这项服务监控5个应用程序说你的手机上安装了5个安卓游戏.该服务需要获取以下信息: 1.游戏开启和运行了多少次? 2.每场比赛的运行​​时间.例如:说如果我在我的应用程序中安装了此服务.我让它运行了一个月.我需要在应用程序的屏幕上显示此

手头的问题:
我必须创建一个持续运行的服务.这项服务监控5个应用程序说你的手机上安装了5个安卓游戏.该服务需要获取以下信息:
 1.游戏开启和运行了多少次?
 2.每场比赛的运行​​时间.

例如:说如果我在我的应用程序中安装了此服务.我让它运行了一个月.我需要在应用程序的屏幕上显示此类信息:

游戏游戏运行次数游戏持续时间

第1场比赛共20次,共15小时

游戏2共16次,总共玩25小时

..

..

第5场比赛共10次,共12小时

可能的方法:
当应用程序加载时,它会进入内存.注意到系统在应用程序启动时计时.当应用程序结束或放在后台注意时间再次.

所以说如果一个应用程序在晚上9点被带到内存并且在晚上9:30退出到后台,这给了我们30分钟的游戏时间.下次播放应用程序时,持续时间将从存储在某种变量中的上一个播放添加到30,依此类推.
每次将应用程序带入内存时,正在播放的计数器应该增加1.因此,给我们一个应用程序播放的次数.

编码:
我不知道Android中的服务,因为我从未真正使用过它们.任何与我手头的问题相关的教程都会非常有用.
其次,如果还有另一种方法可以做到这一点.我也想知道.我真的可以使用一些代码片段来启动这个项目.

解决方法:

正如您所写,任务是关于监控第三方应用程序,除了定期读取进程列表和检测前台进程之外,没有其他解决方案.你需要一个服务.不幸的是,AndroID没有为前台进程更改提供广播事件等方法.

该任务实际上需要大量代码,至少比普通答案所能包含的多得多.我在这里发布了它的一部分,但你应该解决幕后留下的许多细微差别,例如同步和发布之间的持久信息.这只是一个骨架.

首先,让代码编写一个应用程序对象,这是一个注册所有实例相关内容的好地方.

MonitorApp

public class MonitorApp extends Application{  // actual store of statistics  private final ArrayList<HashMap<String,Object>> processList = new ArrayList<HashMap<String,Object>>();  // fast-access index by package name (used for lookup)  private ArrayList<String> packages = new ArrayList<String>();  public ArrayList<HashMap<String,Object>> getProcessList()  {    return processList;  }  public ArrayList<String> getPackages()  {    return packages;  }  // Todo: you need to save and load the instance data  // Todo: you need to address synchronization issues}

然后让我们起草一项活动.

MonitorActivity

import static ProcessList.ColUMN_PROCESS_name;import static ProcessList.ColUMN_PROCESS_PROP;import static ProcessList.ColUMN_PROCESS_COUNT;import static ProcessList.ColUMN_PROCESS_TIME;public class MonitorActivity extends Activity implements MonitorService.ServiceCallback{  private ArrayList<HashMap<String,Object>> processList;  private MonitorService backgroundService;  private MyCustomAdapter adapter = null;  private ListVIEw ListVIEw = null;  @OverrIDe  public voID onCreate(Bundle savedInstanceState)  {    super.onCreate(savedInstanceState);    setContentVIEw(R.layout.main); // Todo: provIDe your layout    ListVIEw = (ListVIEw)findVIEwByID(R.ID.ID_process_ListvIEw);    createAdapter();    this.bindService(      new Intent(this, MonitorService.class),      serviceConnection,      Context.BIND_auto_CREATE);  }  private voID createAdapter()  {    processList = ((MonitorApp)getApplication()).getProcessList();    adapter = new MyCustomAdapter(this, processList, R.layout.complex_List_item,    new String[]    {      ColUMN_PROCESS_name,      ColUMN_PROCESS_PROP, // Todo: you may calculate and pre-fill this fIEld                           // from ColUMN_PROCESS_COUNT and ColUMN_PROCESS_TIME                           // so eliminating the need to use the custom adapter    },    new int[]    {      androID.R.ID.text1,      androID.R.ID.text2    });    ListVIEw.setAdapter(adapter);  }  // callback method invoked by the service when foreground process changed  @OverrIDe  public voID sendResults(int resultCode, Bundle b)  {    adapter.notifyDataSetChanged();  }  private class MyCustomAdapter extends SimpleAdapter  {    MyCustomAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)    {      super(context, data, resource, from, to);    }    @OverrIDe    public VIEw getVIEw (int position, VIEw convertVIEw, VIEwGroup parent)    {      VIEw result = super.getVIEw(position, convertVIEw, parent);      // Todo: customize process statistics display      int count = (Integer)(processList.get(position).get(ColUMN_PROCESS_COUNT));      int seconds = (Integer)(processList.get(position).get(ColUMN_PROCESS_TIME));      return result;    }  }  private ServiceConnection serviceConnection = new ServiceConnection()  {    @OverrIDe    public voID onServiceConnected(Componentname classname, IBinder service)    {      LocalBinder binder = (LocalBinder)service;      backgroundService = binder.getService();      backgroundService.setCallback(MonitorActivity.this);      backgroundService.start();    }    @OverrIDe    public voID onServicedisconnected(Componentname classname)    {      backgroundService = null;    }  };  @OverrIDe  public voID onResume()  {    super.onResume();    if(backgroundService != null)    {      backgroundService.setCallback(this);    }  }  @OverrIDe  public voID onPause()  {    super.onPause();    if(backgroundService != null)    {      backgroundService.setCallback(null);    }  }}

该活动启动后台工作服务,该服务实际上监视进程.您可以将服务注册从活动移动到应用程序实例中.服务本身就是这样的:

MonitorService

public class MonitorService extends Service{  private boolean initialized = false;  private final IBinder mBinder = new LocalBinder();  private ServiceCallback callback = null;  private Timer timer = null;  private final Handler mHandler = new Handler();  private String foreground = null;  private ArrayList<HashMap<String,Object>> processList;  private ArrayList<String> packages;  private Date split = null;  public static int SERVICE_PERIOD = 5000; // Todo: customize (this is for scan every 5 seconds)  private final ProcessList pl = new ProcessList(this)  {    @OverrIDe    protected boolean isFilteredByname(String pack)    {      // Todo: filter processes by names, return true to skip the process      // always return false (by default) to monitor all processes      return false;    }  };  public interface ServiceCallback  {    voID sendResults(int resultCode, Bundle b);  }  public class LocalBinder extends Binder  {    MonitorService getService()    {      // Return this instance of the service so clIEnts can call public methods      return MonitorService.this;    }  }  @OverrIDe  public voID onCreate()  {    super.onCreate();    initialized = true;    processList = ((MonitorApp)getApplication()).getProcessList();    packages = ((MonitorApp)getApplication()).getPackages();  }  @OverrIDe  public IBinder onBind(Intent intent)  {    if(initialized)    {      return mBinder;    }    return null;  }  public voID setCallback(ServiceCallback callback)  {    this.callback = callback;  }  private boolean addToStatistics(String target)  {    boolean changed = false;    Date Now = new Date();    if(!TextUtils.isEmpty(target))    {      if(!target.equals(foreground))      {        int i;        if(foreground != null && split != null)        {          // Todo: calculate time difference from current moment          // to the moment when prevIoUs foreground process was activated          i = packages.indexOf(foreground);          long delta = (Now.getTime() - split.getTime()) / 1000;          Long time = (Long)processList.get(i).get(ColUMN_PROCESS_TIME);          if(time != null)          {             // Todo: add the delta to statistics of 'foreground'             time += delta;          }          else          {            time = new Long(delta);          }          processList.get(i).put(ColUMN_PROCESS_TIME, time);        }        // update count of process activation for new 'target'        i = packages.indexOf(target);        Integer count = (Integer)processList.get(i).get(ColUMN_PROCESS_COUNT);        if(count != null) count++;        else        {          count = new Integer(1);        }        processList.get(i).put(ColUMN_PROCESS_COUNT, count);        foreground = target;        split = Now;        changed = true;      }    }    return changed;   }  public voID start()  {    if(timer == null)    {      timer = new Timer();      timer.schedule(new MonitoringTimerTask(), 500, SERVICE_PERIOD);    }    // Todo: startForeground(srvcID, createNotification(null));  }  public voID stop()  {    timer.cancel();    timer.purge();    timer = null;  }  private class MonitoringTimerTask extends TimerTask  {    @OverrIDe    public voID run()    {      fillProcessList();      ActivityManager activityManager = (ActivityManager)MonitorService.this.getSystemService(ACTIVITY_SERVICE);      List<RunningTaskInfo> taskInfo = activityManager.getRunningTasks(1);      String current = taskInfo.get(0).topActivity.getPackagename();      // check if current process changed      if(addToStatistics(current) && callback != null)      {        final Bundle b = new Bundle();        // Todo: pass necessary info to UI via bundle        mHandler.post(new Runnable()        {          public voID run()          {            callback.sendResults(1, b);          }        });      }    }  }  private voID fillProcessList()  {    pl.fillProcessList(processList, packages);  }}

该服务使用帮助程序类来构建进程列表.

ProcessList中

public abstract class ProcessList{  // process package name  public static final String ColUMN_PROCESS_name = "process";  // Todo: arbitrary property (can be user-fIEndly name)  public static final String ColUMN_PROCESS_PROP = "property";  // number of times a process has been activated  public static final String ColUMN_PROCESS_COUNT = "count";  // number of seconds a process was in foreground  public static final String ColUMN_PROCESS_TIME = "time";  private Contextwrapper context;  ProcessList(Contextwrapper context)  {    this.context = context;  }  protected abstract boolean isFilteredByname(String pack);  public voID fillProcessList(ArrayList<HashMap<String,Object>> processList, ArrayList<String> packages)  {    ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);    List<RunningAppProcessInfo> procInfo = activityManager.getRunningAppProcesses();    HashMap<String, Object> hm;    final PackageManager pm = context.getApplicationContext().getPackageManager();    for(int i = 0; i < procInfo.size(); i++)    {      String process = procInfo.get(i).processname;      String packageList = Arrays.toString(procInfo.get(i).pkgList);      if(!packageList.contains(process))      {        process = procInfo.get(i).pkgList[0];      }      if(!packages.contains(process) && !isFilteredByname(process))      {        ApplicationInfo ai;        String applicationname = "";        for(int k = 0; k < procInfo.get(i).pkgList.length; k++)        {          String thisPackage = procInfo.get(i).pkgList[k];          try          {            ai = pm.getApplicationInfo(thisPackage, 0);          }          catch(final nameNotFoundException e)          {            ai = null;          }          if(k > 0) applicationname += " / ";          applicationname += (String)(ai != null ? pm.getApplicationLabel(ai) : "(unkNown)");        }        packages.add(process);        hm = new HashMap<String, Object>();        hm.put(ColUMN_PROCESS_name, process);        hm.put(ColUMN_PROCESS_PROP, applicationname);        processList.add(hm);      }    }    // optional sorting    Comparator<HashMap<String, Object>> comparator = new Comparator<HashMap<String, Object>>()    {      public int compare(HashMap<String, Object> object1, HashMap<String, Object> object2)       {               return ((String)object1.get(ColUMN_PROCESS_name)).comparetoIgnoreCase((String)object2.get(ColUMN_PROCESS_name));      }    };    Collections.sort(processList, comparator);    packages.clear();    for(HashMap<String, Object> e : processList)    {      packages.add((String)e.get(ColUMN_PROCESS_name));    }  }}

最后,清单.

AndroIDManifest.xml中

<?xml version="1.0" enCoding="utf-8"?><manifest xmlns:androID="http://schemas.androID.com/apk/res/androID"    package="com.yourpackage"    androID:versionCode="1"    androID:versionname="1.0" >    <uses-sdk androID:minSdkVersion="8" androID:targetSdkVersion="18" />    <uses-permission androID:name="androID.permission.GET_TASKS" />    <application        androID:icon="@drawable/ic_launcher"        androID:label="@string/app_name" >        <activity            androID:name=".MonitorActivity"            androID:label="@string/app_name"            androID:configChanges="orIEntation|keyboardHIDden" >            <intent-filter>                <action androID:name="androID.intent.action.MAIN" />                <category androID:name="androID.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <service androID:name=".MonitorService" />    </application></manifest>

正如您所看到的,它已经是很多代码了.它部分地从一个正在运行的应用程序中提取,但我根据您的需求进行了快速更改,因此可能存在拼写错误,所有导入都被跳过等等.不过,我希望这会有所帮助.

ADDENDUM:Lollipop

注意:最新的AndroID版本打破了上述方法.以下是官方文档中关于getRunningTasks方法和其他方法的说明:

As of LolliPOP, this method is no longer available to third party applications: the introduction of document-centric recents means it can leak person information to the caller. For backwards compatibility, it will still retu rn a small subset of its data: at least the caller’s own tasks, and possibly some other tasks such as home that are kNown to not be sensitive.

我认为这是一种矫枉过正,可以更有选择性和方便的方式完成.更值得一提的是,考虑到Google的许多内置功能存在隐私问题,这似乎太戏剧化了.无论如何,我们无能为力.

唯一的解决方法是实现AndroID辅助功能服务(更多信息here和here),并拦截所有 *** 作,应用程序从那里获得和失去焦点.用户应手动启用该服务!您的应用程序应该以某种方式指导用户这样做.

总结

以上是内存溢出为你收集整理的android – 如何创建一个持续监控应用程序使用信息的服务?全部内容,希望文章能够帮你解决android – 如何创建一个持续监控应用程序使用信息的服务?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1102691.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-28
下一篇 2022-05-28

发表评论

登录后才能评论

评论列表(0条)

保存