我有一个时钟小部件Android应用程序,我现在正试图更新到API 26的要求。
到目前为止,我使用了一个后台服务,它在启动时在其onCreate
方法aBroadcastReceiver
中注册,以接收系统广播,例如android。意图行动屏幕打开,Android。意图行动关掉屏幕,Android。意图行动时间到了,Android。意图行动时区已更改
。然后,这项服务在屏幕关闭时暂停时钟,在屏幕重新打开时唤醒时钟,以节省电池。
在Oreo中,这类服务似乎不是一个选项,因为它必须在前台运行,并带有一个对用户没有意义的通知。此外,据我在文档中看到的,JobScheduler
也帮不上我的忙,因为我没有发现可以将作业安排到屏幕打开时。
我尝试在AppWidgetProvider
类中创建一个BroadcastRecencer
,并将其注册到AppWidgetProvider
的onUpdate
方法中以接收所述系统广播。这工作得很好,广播确实被接收到,但仅在屏幕关闭一段时间后;之后,应用程序似乎以某种方式被系统杀死,或者以其他方式停止工作而没有任何报告的错误或崩溃;但是如果我单击它,它会像往常一样打开配置活动。
我的问题是:
>
如果我不想运行前台服务,如何正确收听API 26上的屏幕开/关广播?
是否可以收听来自AppWidgetProvider
类本身的系统广播,方法是在其中注册BroadcastRecencer
,或者甚至注册AppWidgetProvider
本身来接收系统事件(无论如何AppWidgetProvider
是BroadcastRecencer
的扩展)。
为什么我的AppWidgetProvider
在一段睡眠时间后会突然停止接收广播的系统意图?
编辑:
我在Android留档中找到了以下内容,这似乎是我的问题2和3的答案。
注意:不能从BroadcastReceiver组件调用此方法;也就是说,来自应用程序清单中声明的BroadcastReceiver。但是,从另一个在运行时已向registerReceiver(BroadcastReceiver,IntentFilter)注册的BroadcastReceiver调用此方法是可以的,因为这样一个注册的BroadcastReceiver的生存期与注册它的对象相关联。
我的结论是,我在AppWidgetProvider
中使用和注册BroadcastRecencer
违反了本规范。
我将保留这篇文章,因为其他人可能会发现这些信息很有用,我的问题1仍然有效。
下面是我在Android API 26(Oreo)及以上版本中收听SCREEN_OFF和SCREEN_ON广播的步骤。这个答案与widget无关,但找到一些解决方法可能会有所帮助。
我正在使用作业调度器来注册和注销广播接收器,它可以监听屏幕关闭和屏幕打开操作。
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.PowerManager;
import android.support.annotation.NonNull;
import android.util.Log;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobManager;
import com.evernote.android.job.JobRequest;
import java.util.concurrent.TimeUnit;
public class LockScreenJob extends Job {
private static final String TAG = LockScreenJob.class.getSimpleName();
public static final String TAG_P = "periodic_job_tag";
public static final String TAG_I = "immediate_job_tag";
//Used static refrence of broadcast receiver for ensuring if it's already register or not NULL
// then first unregister it and set to null before registering it again.
public static UnlockReceiver aks_Receiver = null;
@Override
@NonNull
protected Result onRunJob(Params params) {
// run your job here
String jobTag = params.getTag();
if (BuildConfig.DEBUG) {
Log.i(TAG, "Job started! " + jobTag);
}
PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
boolean isInteractive = false;
// Here we check current status of device screen, If it's Interactive then device screen is ON.
if (Build.VERSION.SDK_INT >= 20) {
isInteractive = pm.isInteractive();
} else {
isInteractive = pm.isScreenOn();
}
try {
if (aks_Receiver != null) {
getContext().getApplicationContext().unregisterReceiver(aks_Receiver); //Use 'Application Context'.
}
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} finally {
aks_Receiver = null;
}
try {
//Register receiver for listen "SCREEN_OFF" and "SCREEN_ON" action.
IntentFilter filter = new IntentFilter("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
aks_Receiver = new UnlockReceiver();
getContext().getApplicationContext().registerReceiver(aks_Receiver, filter); //use 'Application context' for listen brodcast in background while app is not running, otherwise it may throw an exception.
} catch (Exception e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
if (isInteractive)
{
//TODO:: Can perform required action based on current status of screen.
}
return Result.SUCCESS;
}
/**
* scheduleJobPeriodic: Added a periodic Job scheduler which run on every 15 minute and register receiver if it's unregister. So by this hack broadcast receiver registered for almost every time w.o. running any foreground/ background service.
* @return
*/
public static int scheduleJobPeriodic() {
int jobId = new JobRequest.Builder(TAG_P)
.setPeriodic(TimeUnit.MINUTES.toMillis(15), TimeUnit.MINUTES.toMillis(5))
.setRequiredNetworkType(JobRequest.NetworkType.ANY)
.build()
.schedule();
return jobId;
}
/**
* runJobImmediately: run job scheduler immediately so that broadcasr receiver also register immediately
* @return
*/
public static int runJobImmediately() {
int jobId = new JobRequest.Builder(TAG_I)
.startNow()
.build()
.schedule();
return jobId;
}
/**
* cancelJob: used for cancel any running job by their jobId.
* @param jobId
*/
public static void cancelJob(int jobId) {
JobManager.instance().cancel(jobId);
}
}
我的JobCrator类LockScreenJobCreator是:
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.evernote.android.job.Job;
import com.evernote.android.job.JobCreator;
public class LockScreenJobCreator implements JobCreator {
@Override
@Nullable
public Job create(@NonNull String tag) {
switch (tag) {
case LockScreenJob.TAG_I:
return new LockScreenJob();
case LockScreenJob.TAG_P:
return new LockScreenJob();
default:
return null;
}
}
}
BroadcastRecencer类UnlockRecencer是:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class UnlockReceiver extends BroadcastReceiver {
private static final String TAG = UnlockReceiver.class.getSimpleName();
@Override
public void onReceive(Context appContext, Intent intent) {
if (BuildConfig.DEBUG) {
Log.i(TAG, "onReceive: " + intent.getAction());
}
if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_OFF))
{
//TODO:: perform action for SCREEN_OFF
} else if (intent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
//TODO:: perform action for SCREEN_ON
}
}
}
将JobCreator类添加到应用程序类中,如下所示:
public class AksApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new LockScreenJobCreator());
//TODO: remaing code
}
}
别忘了在AndroidManifest中定义应用程序类。xml
所有这些之后,我从我的活动中启动作业调度器,如下所示:
import android.support.v7.app.AppCompatActivity;
public class LockScreenActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
runJobScheduler();
//TODO: other code
}
@Override
protected void onStop() {
super.onStop();
cancelImmediateJobScheduler();
//TODO: other code
}
/**
* runJobScheduler(): start immidiate job scheduler and pending job schedulaer from
your main Activity.
*/
private void runJobScheduler() {
Set<JobRequest> jobSets_I = null, jobSets_P = null;
try {
jobSets_I = JobManager.instance().getAllJobRequestsForTag(LockScreenJob.TAG_I);
jobSets_P = JobManager.instance().getAllJobRequestsForTag(LockScreenJob.TAG_P);
if (jobSets_I == null || jobSets_I.isEmpty()) {
LockScreenJob.runJobImmediately();
}
if (jobSets_P == null || jobSets_P.isEmpty()) {
LockScreenJob.scheduleJobPeriodic();
}
//Cancel pending job scheduler if mutiple instance are running.
if (jobSets_P != null && jobSets_P.size() > 2) {
JobManager.instance().cancelAllForTag(LockScreenJob.TAG_P);
}
} catch (Exception e) {
if (Global_Var.isdebug) {
e.printStackTrace();
}
} finally {
if (jobSets_I != null) {
jobSets_I.clear();
}
if (jobSets_P != null) {
jobSets_P.clear();
}
jobSets_I = jobSets_P = null;
}
}
/**
* cancelImmediateJobScheduler: cancel all instance of running job scheduler by their
TAG name.
*/
private void cancelImmediateJobScheduler() {
JobManager.instance().cancelAllForTag(LockScreenJob.TAG_I);
}
}
通过运行这样的作业调度程序,我可以在不运行任何前台或后台服务的情况下,监听屏幕关闭和屏幕打开操作。我在API 26上测试了上述代码,它运行良好。
Laravel广播的想法很棒,但是很难弄清楚如何让它工作。即使在阅读文档多次,看了许多教程...也许我只是错过了一些小事。谁知道呢? 我在Homestead上的Laravel 5.4项目中运行以下代码: 广播的配置设置为Redis。我安装了Laravel回声服务器,并使用laravel-echo-server start运行此功能,并在控制台中看到类似于[11:15:16 AM]-v7y-5DsM
我想实现一个切换按钮,Android。小装置。开关(可从API v.14获得)。 但我不知道如何为按钮添加事件侦听器。它应该是一个“onClick”监听器吗?我怎么知道它是否被切换为“开”?
所以,我有一个项目在Flatter中,我试图建立一个卡片列表,其中的内容取决于我的OrderModel类,我试图使用Provider来实现这一点,但我得到了以下错误: ════════ 异常捕获调度程序库 ══════════════════════════ 尝试从小部件树外部侦听提供程序公开的值。 这很可能是由调用Provider.of的事件处理程序(如按钮的onP)引起的,该事件处理程序没有传
我目前正在使用mail-listener5软件包来断言电子邮件地址收件箱中的电子邮件数量。 我的测试框架是nightwatchjs。 目前,我的命令脚本从电子邮件地址收件箱(标题为getInboxEmails)中获取电子邮件的数量; 我的nightwatchjs测试脚本如下所示; 当我运行这个nightwatchjs脚本时,输出以下内容; 但是,浏览器不会关闭。 我有点期待这一点,因为在我的get
我有一个通过TestNG运行并行测试的selenium项目。当测试失败时,我有一个listener类来捕获屏幕截图。类如下 在我的测试中,我有一个AfterMethod来清理测试 如果逐个运行测试,则捕获正确的浏览器屏幕截图,但如果运行parrallel,testsit捕获错误的测试浏览器。我认为问题可能是以下之一 after方法已经退出浏览器(有时这是一种情况,因此我必须添加hasQuit布尔值
要运行Kafka,需要在文件。有两种设置我不理解。 有人可以解释侦听器和广告侦听器属性之间的区别吗? 留档说: 侦听器:套接字服务器侦听的地址。 和 advertised.listeners:主机名和端口代理将向生产者和消费者做广告。 我什么时候必须使用哪个设置?