Android如何实现Android程序在手机锁屏后继续运行

Posted David Wu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android如何实现Android程序在手机锁屏后继续运行相关的知识,希望对你有一定的参考价值。

目录结构:

contents structure [+]

 

最近笔者在做一个功能,就是实现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的资源。

 需要注意,当锁屏后再次打开的跳转逻辑处理也是一个问题,可以参考  Android实现监听返回键,主键(HOME),菜单键

 

以上是关于Android如何实现Android程序在手机锁屏后继续运行的主要内容,如果未能解决你的问题,请参考以下文章

Android 系统锁屏实现固件升级动画

如何在android中制作我们自己的锁屏而不是默认锁屏[重复]

android2.2的锁屏界面,如何在开机时默认显示横屏

android如何通过代码设置锁屏壁纸

android锁屏开发难题,系统锁出现后如何自动取消的问题

Android应用程序保持后台唤醒(使用WakeLock实现)