目录结构:
[+]
- 如何监听屏幕锁屏
- 如何实现手机屏幕在锁屏后继续运行
最近笔者在做一个功能,就是实现Android程序在锁屏后可以继续运行,笔者在网上查了一些资料,现在整理出来,希望能够对你有所帮助。
1.如何监听屏幕锁屏
监听屏幕锁屏可以通过如下方式来实现,直接通过代码来判定,或通过监听器来实现
如何实现Android程序在手机锁屏后继续运行
1)通过代码来判定屏幕的锁屏状态
可以通过PowerManager的isScreenOn方法,代码如下:
PowerManager pm = (PowerManager)
context.getSystemService(Context.POWER_SERVICE);
//如果为true,则表示屏幕“亮”了,否则屏幕“暗”了。
boolean isScreenOn = pm.isScreenOn();
这里需要解释一下:
屏幕“亮”,表示有两种状态:a、未锁屏 b、目前正处于解锁状态 。这两种状态屏幕都是亮的;
屏幕“暗”,表示目前屏幕是黑的 。
通过KeyguardManager的inKeyguardRestrictedInputMode方法,也可以实现判断屏幕的锁屏状态
KeyguardManager mKeyguardManager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
boolean flag = mKeyguardManager.inKeyguardRestrictedInputMode();
对flag进行一下说明,经过试验,总结为:
如果flag为true,表示有两种状态:a、屏幕是黑的 b、目前正处于锁屏状态 。
如果flag为false,表示目前未锁屏
当然也可以通过反射的方式来调用上面的两种方法:
Method mReflectScreenState;
try {
mReflectScreenState = PowerManager.class.getMethod(isScreenOn, new Class[] {});
PowerManager pm = (PowerManager)
context.getSystemService(Activity.POWER_SERVICE);
boolean isScreenOn= (Boolean) mReflectScreenState.invoke(pm);
} catch (Exception e) {
e.printStackTrace()
2)通过监听器来判定屏幕的锁屏状态
当安卓系统锁屏或者屏幕亮起,或是屏幕解锁的时候,系统内部都会发送相应的广播,我们只需要对广播进行监听就可以了
注册广播的伪代码如下:
ScreenBroadcastReceiver mScreenReceiver;
class ScreenBroadcastReceiver extends BroadcastReceiver {
String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) {
// 开屏
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
// 锁屏
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
// 解锁
}
}
}
private void startScreenBroadcastReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
context.registerReceiver(mScreenReceiver, filter);
}
2.如何实现手机屏幕在锁屏后继续运行
在上面我们知道了如何监听屏幕的状态,接下要实现如何在屏幕关闭后程序不停止运行。关于这个功能,笔者在网上搜索了一些资料,Android的WakeLock机制就是其中一种,使用Android的service也可以。但是经过笔者的测试发现效果都不太理想,对于Android版本的兼容性不强,笔者的Android4.4可以支持,但是Android6.0经过测试发现却不支持。
下面笔者介绍一种万能方法,在这里感谢知乎给我提出的意见(听说是QQ锁屏的黑科技呢)。
就是在屏幕锁屏的时候,跳转到另一个界面,该界面只有一个像素点。
代码如下:
MainActivity.java
package org.screenlock.main;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import com.example.screenlocktest.R;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.PixelFormat;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
Context context = null;
Intent mintent=null;
static Activity mactivity=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.context = this;
mintent=new Intent(this,SinglePixelActivity.class);
startScreenBroadcastReceiver(new ScreenBroadcastReceiver());
Timer timer=new Timer();
TimerTask timerTask=new TimerTask() {
@Override
public void run() {
Log.i("info", new Date().toString());
}
};
timer.schedule(timerTask, 0,10* 1000);//每10秒钟运行一次,用于观察程序是否在运行
}
/**
* 注册屏幕广播
*/
private void startScreenBroadcastReceiver(ScreenBroadcastReceiver mScreenReceiver) {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
context.registerReceiver(mScreenReceiver, filter);
}
private class ScreenBroadcastReceiver extends BroadcastReceiver {
private String action = null;
@Override
public void onReceive(Context context, Intent intent) {
action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action)) {
// 开屏
Log.i("info", "开屏");
finishScreenActivity();
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
// 锁屏
Log.i("info", "锁屏");
startScreenActivity();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
// 解锁
Log.i("info", "解屏");
}
}
}
/**
* 关闭屏幕锁屏界面
*/
private void finishScreenActivity(){
if(mactivity!=null){
mactivity.finish();
}
}
/**
* 跳转到屏幕锁屏界面
*/
private void startScreenActivity(){
startActivity(mintent);
}
}
MainActivity.java
SinglePixelActivity.java
package org.screenlock.main;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class SinglePixelActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window= getWindow();
WindowManager.LayoutParams params=new WindowManager.LayoutParams();
params.x=0;
params.y=0;
params.width=1;
params.height=1;
window.setAttributes(params);
MainActivity.mactivity=this;
Log.i("info", "SinglePixelActivity onCreate");
}
@Override
protected void onStart() {
super.onStart();
Log.i("info", "SinglePixelActivity onStart");
}
@Override
protected void onResume() {
super.onResume();
Log.i("info", "SinglePixelActivity onResume");
}
@Override
protected void onPause() {
super.onPause();
Log.i("info", "SinglePixelActivity onPause");
}
@Override
protected void onStop() {
super.onStop();
Log.i("info", "SinglePixelActivity onStop");
}
@Override
protected void onRestart() {
super.onRestart();
Log.i("info", "SinglePixelActivity onRestart");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i("info", "SinglePixelActivity onDestroy");
}
}
SinglePixelActivity.java
AndroidManifest.xml中需要添加如下:
<activity
android:name="org.screenlock.main.SinglePixelActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
运行上面的程序,可以看到计时器在正常打印东西,说明程序并没有完全停止,还可以看到打印如下的日志:
info SinglePixelActivity onCreate
info SinglePixelActivity onStart
info SinglePixelActivity onResume
info SinglePixelActivity onPause
info SinglePixelActivity onStop
从日志中可以看出,当锁屏后,这个SinglePixelActivity立即进入了OnStop状态,在Onstop的状态的页面是很有可能被系统回收的。因此可以再配合上WakeLock机制,若WakeLock不合适的话,那么可以尝试播放无声音乐。保持系统不回收该App的资源。
需要注意,当锁屏后再次打开的跳转逻辑处理也是一个问题。