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的最底层了。(该段文字来自网络)其方法很简单,基本用到的就三个addview,removeview,updateviewlayout。另:在设置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程序设计有所帮助。