欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android编程实现悬浮窗获取并显示当前内存使用量的方法

程序员文章站 2023-11-24 23:41:10
本文实例讲述了android编程实现悬浮窗获取并显示当前内存使用量的方法。分享给大家供大家参考,具体如下: 运行效果: 其中: 这一块就是悬浮窗,可以随意拖动...

本文实例讲述了android编程实现悬浮窗获取并显示当前内存使用量的方法。分享给大家供大家参考,具体如下:

运行效果:

Android编程实现悬浮窗获取并显示当前内存使用量的方法

其中:

Android编程实现悬浮窗获取并显示当前内存使用量的方法

这一块就是悬浮窗,可以随意拖动,动态显示当前内存使用量。

下面看一下代码是如何实现的:

悬浮窗的实现是用了一个service,为什么要用service呢?了解service特点的大体就会明白。下面看一下:

public class floatservice extends service {
  windowmanager wm = null;
  windowmanager.layoutparams wmparams = null;
  view view;
  private float mtouchstartx;
  private float mtouchstarty;
  private float x;
  private float y;
  int state;
  textview tx1;
  textview tx;
  imageview iv;
  private float startx;
  private float starty;
  int delaytime=1000;
  @override
  public void oncreate() {
    log.d("floatservice", "oncreate");
    super.oncreate();
    view = layoutinflater.from(this).inflate(r.layout.floating, null);
    tx = (textview) view.findviewbyid(r.id.memunused);
    tx1 = (textview) view.findviewbyid(r.id.memtotal);
    tx.settext("" + meminfo.getmem_unused(this) + "kb");
    tx1.settext("" + meminfo.getmem_tolal() + "kb");
    iv = (imageview) view.findviewbyid(r.id.img2);
    iv.setvisibility(view.gone);
    createview();
    handler.postdelayed(task, delaytime);
  }
  private void createview() {
    // 获取windowmanager
    wm = (windowmanager) getapplicationcontext().getsystemservice("window");
    // 设置layoutparams(全局变量)相关参数
    wmparams = new windowmanager.layoutparams();
    wmparams.type = 2002;
    wmparams.flags |= 8;
    wmparams.gravity = gravity.left | gravity.top; // 调整悬浮窗口至左上角
    // 以屏幕左上角为原点,设置x、y初始值
    wmparams.x = 0;
    wmparams.y = 0;
    // 设置悬浮窗口长宽数据
    wmparams.width = windowmanager.layoutparams.wrap_content;
    wmparams.height = windowmanager.layoutparams.wrap_content;
    wmparams.format = 1;
    wm.addview(view, wmparams);
    view.setontouchlistener(new ontouchlistener() {
      public boolean ontouch(view v, motionevent event) {
        // 获取相对屏幕的坐标,即以屏幕左上角为原点
        x = event.getrawx();
        y = event.getrawy() - 25; // 25是系统状态栏的高度
        log.i("currp", "currx" + x + "====curry" + y);// 调试信息
        switch (event.getaction()) {
        case motionevent.action_down:
          state = motionevent.action_down;
          startx = x;
          starty = y;
          // 获取相对view的坐标,即以此view左上角为原点
          mtouchstartx = event.getx();
          mtouchstarty = event.gety();
          log.i("startp", "startx" + mtouchstartx + "====starty"
              + mtouchstarty);// 调试信息
          break;
        case motionevent.action_move:
          state = motionevent.action_move;
          updateviewposition();
          break;
        case motionevent.action_up:
          state = motionevent.action_up;
          updateviewposition();
          showimg();
          mtouchstartx = mtouchstarty = 0;
          break;
        }
        return true;
      }
    });
    iv.setonclicklistener(new onclicklistener() {
      @override
      public void onclick(view v) {
        // todo auto-generated method stub
        intent servicestop = new intent();
        servicestop.setclass(floatservice.this, floatservice.class);
        stopservice(servicestop);
      }
    });
  }
  public void showimg() {
    if (math.abs(x - startx) < 1.5 && math.abs(y - starty) < 1.5
        && !iv.isshown()) {
      iv.setvisibility(view.visible);
    } else if (iv.isshown()) {
      iv.setvisibility(view.gone);
    }
  }
  private handler handler = new handler();
  private runnable task = new runnable() {
    public void run() {
      // todo auto-generated method stub
      datarefresh();
      handler.postdelayed(this, delaytime);
      wm.updateviewlayout(view, wmparams);
    }
  };
  public void datarefresh() {
    tx.settext("" + meminfo.getmem_unused(this) + "kb");
    tx1.settext("" + meminfo.getmem_tolal() + "kb");
  }
  private void updateviewposition() {
    // 更新浮动窗口位置参数
    wmparams.x = (int) (x - mtouchstartx);
    wmparams.y = (int) (y - mtouchstarty);
    wm.updateviewlayout(view, wmparams);
  }
  @override
  public void onstart(intent intent, int startid) {
    log.d("floatservice", "onstart");
    setforeground(true);
    super.onstart(intent, startid);
  }
  @override
  public void ondestroy() {
    handler.removecallbacks(task);
    log.d("floatservice", "ondestroy");
    wm.removeview(view);
    super.ondestroy();
  }
  @override
  public ibinder onbind(intent intent) {
    return null;
  }
}

其主要功能部分在creatview方法里:

private void createview() {
    // 获取windowmanager
    wm = (windowmanager) getapplicationcontext().getsystemservice("window");
    // 设置layoutparams(全局变量)相关参数
    wmparams = new windowmanager.layoutparams();
    wmparams.type = 2002;
    wmparams.flags |= 8;
    wmparams.gravity = gravity.left | gravity.top; // 调整悬浮窗口至左上角
    // 以屏幕左上角为原点,设置x、y初始值
    wmparams.x = 0;
    wmparams.y = 0;
    // 设置悬浮窗口长宽数据
    wmparams.width = windowmanager.layoutparams.wrap_content;
    wmparams.height = windowmanager.layoutparams.wrap_content;
    wmparams.format = 1;
    wm.addview(view, wmparams);
    view.setontouchlistener(new ontouchlistener() {
      public boolean ontouch(view v, motionevent event) {
        // 获取相对屏幕的坐标,即以屏幕左上角为原点
        x = event.getrawx();
        y = event.getrawy() - 25; // 25是系统状态栏的高度
        log.i("currp", "currx" + x + "====curry" + y);// 调试信息
        switch (event.getaction()) {
        case motionevent.action_down:
          state = motionevent.action_down;
          startx = x;
          starty = y;
          // 获取相对view的坐标,即以此view左上角为原点
          mtouchstartx = event.getx();
          mtouchstarty = event.gety();
          log.i("startp", "startx" + mtouchstartx + "====starty"
              + mtouchstarty);// 调试信息
          break;
        case motionevent.action_move:
          state = motionevent.action_move;
          updateviewposition();
          break;
        case motionevent.action_up:
          state = motionevent.action_up;
          updateviewposition();
          showimg();
          mtouchstartx = mtouchstarty = 0;
          break;
        }
        return true;
      }
    });
    iv.setonclicklistener(new onclicklistener() {
      @override
      public void onclick(view v) {
        // todo auto-generated method stub
        intent servicestop = new intent();
        servicestop.setclass(floatservice.this, floatservice.class);
        stopservice(servicestop);
      }
    });
}

首先,代码里面用到了 windowmanager借口,整 个android的窗口机制是基于一个叫做 windowmanager,这个接口可以添加view到屏幕,也可以从屏幕删除view。它面向的对象一端是屏幕,另一端就是view,直接忽略我们以 前的activity或者dialog之类的东东。其实我们的activity或者diolog底层的实现也是通过windowmanager,这个 windowmanager是全局的,整个系统就是这个唯一的东东。它是显示view的最底层了。(该段文字来自网络)其方法很简单,基本用到的就三个addviewremoveviewupdateviewlayout。另:在设置view高度和宽度的时候一 个错误,即在view的构造函数中获取getwidth()getheight(),当一个view对象创建时,android并不知道其大小,所以 getwidth()getheight()返回的结果是0,真正大小是在计算布局时才会计算,所以会发现一个有趣的事,即在ondraw()却能取得长宽的原因。使用一下方法即可:

width = activity.getwindowmanager().getdefaultdisplay().getwidth();
height = activity.getwindowmanager().getdefaultdisplay().getheight();

下面是layoutparams,设置他的属性:

在这里是设置成了所有应用程序之上,状态栏之下的形式,当移动的时候,会调用case motionevent.action_move:

下面的代码主要是:

private void updateviewposition() {
    // 更新浮动窗口位置参数
    wmparams.x = (int) (x - mtouchstartx);
    wmparams.y = (int) (y - mtouchstarty);
    wm.updateviewlayout(view, wmparams);
}

从新设置浮动栏的位置参数。这样就实现了拖动的功能。其内存数据是如何获取及及时更新的呢?

我们注意到了handler

handler.postdelayed(task, delaytime);
private runnable task = new runnable() {
    public void run() {
      // todo auto-generated method stub
      datarefresh();
      handler.postdelayed(this, delaytime);
      wm.updateviewlayout(view, wmparams);
    }
};

我们找到datarefresh方法,delaytime是设置的1000,也就是每一秒钟更新一次数据。

public void datarefresh() {
    tx.settext("" + meminfo.getmem_unused(this) + "kb");
    tx1.settext("" + meminfo.getmem_tolal() + "kb");
}

最后,看下meminfo的定义:

public class meminfo {
  public static long getmem_unused(context mcontext) {
    long mem_unused;
    activitymanager am = (activitymanager) mcontext
        .getsystemservice(context.activity_service);
    activitymanager.memoryinfo mi = new activitymanager.memoryinfo();
    am.getmemoryinfo(mi);
    mem_unused = mi.availmem / 1024;
    return mem_unused;
  }
  public static long getmem_tolal() {
    long mtotal;
    // 系统内存
    string path = "/proc/meminfo";
    // 存储器内容
    string content = null;
    bufferedreader br = null;
    try {
      br = new bufferedreader(new filereader(path), 8);
      string line;
      if ((line = br.readline()) != null) {
        // 采集内存信息
        content = line;
      }
    } catch (filenotfoundexception e) {
      e.printstacktrace();
    } catch (ioexception e) {
      e.printstacktrace();
    } finally {
      if (br != null) {
        try {
          br.close();
        } catch (ioexception e) {
          e.printstacktrace();
        }
      }
    }
    // beginindex
    int begin = content.indexof(':');
    // endindex
    int end = content.indexof('k');
    // 采集数量的内存
    content = content.substring(begin + 1, end).trim();
    // 转换为int型
    mtotal = integer.parseint(content);
    return mtotal;
  }
}

里面只定义了两个方法,获取总内存和使用内存。

更多关于android相关内容感兴趣的读者可查看本站专题:《android窗口相关操作技巧总结》、《android开发入门与进阶教程》、《android调试技巧与常见问题解决方法汇总》、《android基本组件用法总结》、《android视图view技巧总结》、《android布局layout技巧总结》及《android控件用法总结

希望本文所述对大家android程序设计有所帮助。