使用悬浮框监听内存的使用状态 -- 附源码

源码下载地址:http://download.csdn.net/detail/hewence1/8176601
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">先看一下效果:  显示当前内存使用率55% ,每一秒都刷新一次</span>

实现原理,在Service中创建一个悬浮框就可,在service中每秒钟访问计算一次单曲使用了多少的内存,并更新对应的控件

实现步骤:

1 创建一个Activity,此Activty自启动service即可,当然也可以加上其他界面

Activity代码:

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		Intent show = new Intent(this, FloatService.class);
        startService(show);
	}

Xml代码就不贴了占篇幅,service代码现在也是空的也不贴了。

Manifest文件要注意:

加入权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<uses-permission android:name="android.permission.GET_TASKS"/>

跟service

<service android:name="com.example.testfloating.FloatService"></service>

2. 增加悬浮框

要增加的悬浮框跟上图一样要重写一个圆形的View 并且可以使阴影(现在是使用绿色)来表示百分百,如50% 那么绿色就只有一半。另一半显示背景色

先看这个View的代码:

	int width ;
	int height;
	int precent;
	Bitmap mBitmap ;
	int viewCorol = 0xff00ff00;

	public CircleView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// 先获得一个 bitmap吧  再
		super.onDraw(canvas);
		width = getMeasuredWidth();
		height = getMeasuredHeight();
		mBitmap = Bitmap.createBitmap(width, height,
                Config.ARGB_8888);
		Canvas mCanvas = new Canvas(mBitmap);
		Paint mPaint = new Paint();
        mPaint.setColor(viewCorol);
        mPaint.setAntiAlias(true);
        mCanvas.drawCircle(width / 2, height / 2, width / 2, mPaint);

		canvas.drawBitmap(mBitmap, new Rect(0, height * (100 - precent) / 100, width, height) ,
				new Rect(0, height * (100 - precent) / 100, width, height), null);
	}

	public void setPrecent(int precent) {
		this.precent = precent;
		invalidate();
	}

方法的实现请自己看代码, 不难理解

在setPrecent就是设计百分百比,这这里可以延伸一下的,

可以加入根据precent的大少来更改阴影的颜色,颜色的值要有一个递变的过程()

public void setPrecent(int precent) {
		this.precent = precent;
		if (precent >= 90){
			viewColor = .....
		}else if (precent >= 80){
			viewColor = .....
		}else if (precent >= 70){
			viewColor = .....

		}
		.precent........
		else{

		}
		invalidate();
	}
</pre><pre name="code" class="java">现在看布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/window"

     >
<!-- android:descendantFocusability="blocksDescendants" -->

    <RelativeLayout
        android:id="@+id/circle_layout"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@drawable/window_bg"
        android:orientation="vertical" >

        <com.example.textfloatingwindow.CircleView
            android:id="@+id/window_circle"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerInParent="true" >
        </com.example.textfloatingwindow.CircleView>

        <TextView
            android:id="@+id/precent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#ffffffff"
            android:textSize="20sp" />
    </RelativeLayout>

</RelativeLayout>

service代码:

	@Override
	public void onCreate() {
		super.onCreate();
		createFloatView();
		Log.i(TAG , "onCreate");
	}

	@Override
	public void onStart(Intent intent, int startId) {
		super.onStart(intent, startId);
		mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
		Log.i(TAG , "onStart");
	}

	@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_CHECK_ACTIVITY:
				if (!isAdded) {
					Log.i(TAG , "wm.addView(mainView, params);");
					wm.addView(mainView, params);
					isAdded = true;
				}
				mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
				break;
			}
		}
	};

	/**
	 * 创建悬浮窗
	 */
	private void createFloatView() {
		wm = (WindowManager) getApplicationContext().getSystemService(
				Context.WINDOW_SERVICE);
		params = new WindowManager.LayoutParams();

		// 设置window type
		params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
		/*
		 * 如果设置为params.type = WindowManager.LayoutParams.TYPE_PHONE; 那么优先级会降低一些,
		 * 即拉下通知栏不可见
		 */
		params.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明

		// 设置Window flag
		params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
				| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
		/*
		 * 下面的flags属性的效果形同“锁定”。 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
		 * wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL |
		 * LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE;
		 */

		// 设置悬浮窗的长得宽
		params.width = params.WRAP_CONTENT;
		params.height = params.WRAP_CONTENT;

		if (null == inflater){
			inflater = LayoutInflater.from(getApplicationContext());
			mainView = inflater.inflate(R.layout.window_view, null);
			precent = (TextView) mainView.findViewById(R.id.precent);
			circleView = (CircleView) mainView.findViewById(R.id.window_circle);
		}

	}

在onCreate里创建一个View ,但是没有加入到WindowManager中,在onStart中启动了Handler 每秒钟执行一次

if (!isAdded) {
					Log.i(TAG , "wm.addView(mainView, params);");
					wm.addView(mainView, params);
					isAdded = true;
				}

通过这个来增加到WindowManager来实现悬浮框。

先的效果如图:

现在悬浮框中啥都没有,只有一个背景,在这里 我只是使用一个shape当做背景,大家可以使用更pl的UI素材。现在的内存使用率是没有显示出来的是没有设置的!

3. 实时监控内存的变化

在Handler中增加这个更新得到的数据:

得到数据数据的方法如下:

 /**
     * 得到系统总内存 单位KB
     * @param context
     * @return
     */
    public  long getTotalMemory(Context context) {
        String str1 = "/proc/meminfo";// 系统内存信息文件
        String str2;
        String[] arrayOfString;
        long initial_memory = 0;

        try {
            FileReader localFileReader = new FileReader(str1);
            BufferedReader localBufferedReader = new BufferedReader(localFileReader, 8192);
            str2 = localBufferedReader.readLine();// 读取meminfo第一行,系统总内存大小

            arrayOfString = str2.split("\\s+");
         /*   for (String num : arrayOfString) {
                Log.i(str2, num + "\t");
            }*/

            initial_memory = Integer.valueOf(arrayOfString[1]).intValue() * 1024;// 获得系统总内存,单位是KB,乘以1024转换为Byte
            localBufferedReader.close();

        } catch (IOException e) {
        }
        return initial_memory;
    }

    public  long getAvailMemory(Context context) {// 获取android当前可用内存大小

        ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
        MemoryInfo mi = new MemoryInfo();
        am.getMemoryInfo(mi);
        return mi.availMem;
    }

    private int getPrecent(){
    	long totalSize = getTotalMemory(getApplicationContext());
    	long aliSize = getAvailMemory(getApplicationContext());

    	int precent = 100 - (int) (aliSize * 100  / (float)totalSize);

    	return precent;
    }
    Handler修改为:
<pre name="code" class="java">@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_CHECK_ACTIVITY:
				if (!isAdded) {
					Log.i(TAG , "wm.addView(mainView, params);");
					wm.addView(mainView, params);
					isAdded = true;
				}

			<span style="background-color: rgb(255, 153, 0);">	precent.setText(getPrecent() + "%");
				circleView.setPrecent(getPrecent());</span>
				mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
				break;
			}
		}
	};

现在效果就是:


机器的任何都是有它的存在的,所有就实现了实时监听

4. 可拖动到界面任何一个地方

现在的悬浮框中能在最中间,现在我们就把他推动到你要想的位置:

增加onTouch处理

// 设置悬浮窗的Touch监听
		mainView.setOnTouchListener(new OnTouchListener() {
			int lastX, lastY;
			int paramX, paramY;

			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					lastX = (int) event.getRawX();
					lastY = (int) event.getRawY();
					paramX = params.x;
					paramY = params.y;
					break;
				case MotionEvent.ACTION_MOVE:
					int dx = (int) event.getRawX() - lastX;
					int dy = (int) event.getRawY() - lastY;
					params.x = paramX + dx;
					params.y = paramY + dy;
					// 更新悬浮窗位置
					wm.updateViewLayout(mainView, params);
					break;
				}

				// return true的 click事件是没有反应的,至于为什么 大家去了解触摸事件分发与处理 就知道了
				return false;
			}
		});

5.只在主界面显示

现在的悬浮框在所有的界面都显示了,有些不合理,在桌面才显示这个悬浮框(这里可以设置一个设置项 是否只显示在主界面)

判断是否是在桌面的方法如下:

 /** 获得属于桌面的应用的应用包名称
	 *
	 * @return 返回包含所有包名的字符串列表
	 */
	private List<String> getHomes() {
		List<String> names = new ArrayList<String>();
		PackageManager packageManager = this.getPackageManager();
		// 属性
		Intent intent = new Intent(Intent.ACTION_MAIN);
		intent.addCategory(Intent.CATEGORY_HOME);
		List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(
				intent, PackageManager.MATCH_DEFAULT_ONLY);
		for (ResolveInfo ri : resolveInfo) {
			names.add(ri.activityInfo.packageName);
		}
		return names;
	}

	/**
	 * 判断当前界面是否是桌面
	 */
	public boolean isHome() {
		if (mActivityManager == null) {
			mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
		}
		List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
		return homeList.contains(rti.get(0).topActivity.getPackageName());
	}
    

@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case HANDLE_CHECK_ACTIVITY:
				if (isHome()){
					if (!isAdded) {
						Log.i(TAG , "wm.addView(mainView, params);");
						wm.addView(mainView, params);
						isAdded = true;
					}
					// 只有主界面才更新
					precent.setText(getPrecent() + "%");
					circleView.setPrecent(getPrecent());
				}else{
					if (isAdded){
						wm.removeView(mainView);
						isAdded = false;
					}
				}

				mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 1000);
				break;
			}
		}
	};
</pre><pre name="code" class="java">@Override
	public void onCreate() {
		super.onCreate();
		homeList = getHomes();
		createFloatView();
		Log.i(TAG , "onCreate");
	}

这样可以保证只有在桌面时才显示悬浮框

6.增加悬浮框的响应事件

现在的悬浮框点击是无效的,我们想要点击时 退出 或者跳转到应用,或者启动某个 Intent等

可以在点击悬浮框时弹出一个另外的一排按钮,来适应大家的要求,再次点击时移除这一排按钮

修改布局文件为:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/window"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <RelativeLayout
        android:id="@+id/circle_layout"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@drawable/window_bg"
        android:orientation="vertical" >

        <com.example.textfloatingwindow.CircleView
            android:id="@+id/window_circle"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_centerInParent="true" >
        </com.example.textfloatingwindow.CircleView>

        <TextView
            android:id="@+id/precent"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="#ffffffff"
            android:textSize="20sp" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/menu_layout"
        android:layout_width="80dp"
        android:layout_height="60dp"
        android:layout_toRightOf="@id/circle_layout"
        android:visibility="gone"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/menu0"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="打开应用" />

        <TextView
            android:id="@+id/menu1"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="返回" />

        <TextView
            android:id="@+id/menu2"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="退出悬浮框" />
    </LinearLayout>

</RelativeLayout>

增加代码:

menu0.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				Intent it = new Intent(FloatService.this , MainActivity.class);
				it.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
				startActivity(it);
			}
		});

		menu1.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				menu.setVisibility(View.GONE);
			}
		});

		menu2.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				isAdded  = false;
				wm.removeView(mainView);
				// 记得要移动掉handler  否则还是一秒运行一次
				mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
				stopSelf();
			}
		});

效果如下:

界面不怎么好看,这个请自己布局

点击都是有作用的!

时间: 2024-10-11 15:21:03

使用悬浮框监听内存的使用状态 -- 附源码的相关文章

Android中检查、监听电量和充电状态的方法

Android中检查.监听电量和充电状态的方法 这篇文章主要介绍了Android中检查.监听电量和充电状态的方法,如判断当前充电状态.监听充电状态的改变.判断当前剩余电量等,需要的朋友可以参考下 当你在更改后台更新频率来减少这些更新对电池寿命的影响时,检查当前电量和充电状态是一个好的开始. 电池寿命通过剩余电量和充电状态来影响应用更新的执行.当用交流电充电时,执行更新操作对设备的影响是微不足道的,所以在大多数案例里,你可以把更新频率调到最快.如果设备不在充电,降低更新频率可以帮助延长电池寿命.

监听Listview的滚动状态,是否滚动到了顶部或底部

/** * @author:Jack Tony * @description : 监听listview的滑动状态,如果到了顶部就刷新数据 * @date :2015年2月9日 */ private class ListViewListener implements OnScrollListener { @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int t

手机影音第三天,通过监听底部radiogroup按钮状态来切换中间FragmentLayout里的内容

主要是Fragment的使用,其切换fragment的步骤如下 1.获取FragmentManager 实例,但是需要MainActivity extends FragmentActivity才能去获取FragmentManager. 通过FragmentManager  fragmentManager=getSupportFragmentManager(); 2.开启事务  ,有点类似javaee里的hibernate 操作数据库 FragmentTranaction tranaction=

OC - 18.监听iPhone的网络状态

使用系统的方法来监听网络状态 系统的方法是通过通知机制来实现网络状态的监听 实现网络状态监听的步骤 定义Reachability类型的成员变量来保存网络的状态 @property (nonatomic, strong) Reachability *reachability; 注册为通知中心的的观察者 // 在通知中心注册观察者 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(getNetworkS

computed 和 watch 组合使用,监听数据全局数据状态

我要实现的就是,当接口返回数据时,我在任何组件中都能感知到到该数据的变化,然后根据业务逻辑进行处理.展示. 实现这个效果的方式很多,比如当接口返回数据后,就emit这数据,在另外组件中on接收渲染即可,但是我不想用这种, 所以就换了另外一种方式:当接口返回数据时,将数据commit到state,需要对其作出反应的组件中,使用computed将 计算属性将混入到 Vue 实例中.同时使用watch对其属性变化进行监听,且进行相关处理. 相关代码如下: 接口返回数据后,commit更新state中的

一种高效快速的内存池实现(附源码)

此算法灵感来自于apache内存池实现原理,不过读者如果没有看过apache内存池实现也无关系,因为本算法相对apache内存池算法更为简单而且易懂,个人认为某些场合也更为高效,或许真正到了apache服务器上性能不如,但是这套设计思想应该还是可以借鉴到更多场合的. 我们在调用malloc函数时,操作系统内部会查找一个所谓的空闲链表,当找到足够大的空闲空间时会将内存分割并返回一部分会用户,当然在很大的项目里面有可能会出现链表所有节点都找不到空闲空间的情形,此时操作系统便会不断搜索内存碎片,然后组

Linux简易APR内存池学习笔记(带源码和实例)

先给个内存池的实现代码,里面带有个应用小例子和画的流程图,方便了解运行原理,代码 GCC 编译可用.可以自己上网下APR源码,参考代码下载链接: http://pan.baidu.com/s/1hq6A20G 贴两个之前学习的时候参考的文章地址,大家可以参考: http://www.cnblogs.com/bangerlee/archive/2011/09/01/2161437.html http://blog.csdn.net/flyingfalcon/article/details/2627

监听iPhone的通话状态之---CoreTelephony.framework

近期在做一个网络电话会议,需要判断手机的通话状态,通过在网上查找资料找到一个苹果私有框架,下面简单介绍如何使用: 1,要在项目中添加CoreTelephony.framework这个框架,怎么添加如下图: 点击“+”,添加即可: 2,在你需要用到该功能的class中,导入如下两个头文件 #import <CoreTelephony/CTCallCenter.h>#import <CoreTelephony/CTCall.h> 3,使用代码如下: CTCallCenter *cent

用广播监听安卓设备电量状态

发送通知 这次邮件我们将会讨论怎么获取电量状态在安卓设备上,为了完成这个目标,我们将会使用到广播. What is BroadcastReceiver?A broadcast receiver is an Android component which allows you to register for system or application events. All registered receivers for an event are notified by the Android