Android 将 Notification 与 JobScheduler 结合使用时应用崩溃
Android app crashes when using Notification with JobScheduler
我最近一直在尝试让应用程序每 5 秒显示一次通知,即使它出于测试目的而关闭,所以我正在使用 JobService 来做到这一点:
public class Job1 extends JobService {
private boolean cancelled = false;
public static final String tag = "Job";
private int id = 0;
private void createChannel(String id, CharSequence name, int imp) {
NotificationChannel channel = new NotificationChannel(id, name , imp );
NotificationManager nm = getSystemService(NotificationManager.class);
nm.createNotificationChannel(channel);
}
private void display(int id , CharSequence channel_id, String content, String title , Context ctx){
createChannel((String)channel_id , channel_id , NotificationManager.IMPORTANCE_HIGH);
NotificationCompat.Builder nb = new NotificationCompat.Builder(ctx, (String) channel_id)
.setSmallIcon(R.drawable.ic_work_black_24dp)
.setContentText(content)
.setContentTitle(title)
.setPriority(NotificationCompat.PRIORITY_MAX);
NotificationManagerCompat nmc = NotificationManagerCompat.from(ctx);
nmc.notify(id , nb.build() );
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i(tag, "Job has been started");
Job(params);
return true;
}
private void Job(JobParameters params){
new Thread(new Runnable() {
@Override
public void run() {
while (true){
Log.i(tag, "Job is Running");
///////////////////////////////////////////////////
//the crash begin here.
display(id++ , "channel1" , "Description" , "title" , this);
////////////////////////////////////////////////////////////////
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//jobFinished(params , true);
}
@Override
public boolean onStopJob(JobParameters params) {
Log.i(tag, "Job has been cancelled");
cancelled = true;
return true;
}
}
调用作业的代码:
ComponentName cname = new ComponentName(this, Job1.class);
JobInfo jinfo = new JobInfo.Builder(1, cname)
.setRequiresCharging(false)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int result = scheduler.schedule(jinfo);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.i("job", "scheduled");
} else {
Log.i("job", "failed");
}
当然,我还添加了具有 AndroidManifest.xml
权限的服务名称
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service android:name=".Job1"
android:permission="android.permission.BIND_JOB_SERVICE" />
当我尝试单独使用通知功能时,它完美地工作,例如仅通过一个按钮使用它,当我删除 Job
中调用 display
函数的行时,工作正常,但是当我将通知与它一起使用时,它会使整个应用程序崩溃,所以可能是什么问题?
看了logcat,仔细阅读,终于找到了解决办法
主要问题出在 JobService
内部的线程本身,当我尝试发出新通知时,应用程序崩溃并显示以下信息:
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
解决方案是创建一个新线程 Class 并调用 Looper.prepare()
所以新的 Thread 代码将是这样的 class:
public class TestThread extends Thread{
private int id = 0;
private Context ctx;
public TestThread(Context ctx){
this.ctx = ctx;
}
public void run(){
//this line has solved the issue
Looper.prepare();
while(true){
Log.i("Thread" , "Thread is currently running in background :)");
// my notifciation class
(new Notifications()).displayNot(id++ , "channel6", "Content" , "title" , ctx);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
现在我们在作业中使用这个 class,在我的例子中是在 Job
函数中:
private void Job(JobParameters params){
Thread thread = new TestThread(this);
thread.start();
if(!thread.isAlive()){
jobFinished(params , true);
}
}
我最近一直在尝试让应用程序每 5 秒显示一次通知,即使它出于测试目的而关闭,所以我正在使用 JobService 来做到这一点:
public class Job1 extends JobService {
private boolean cancelled = false;
public static final String tag = "Job";
private int id = 0;
private void createChannel(String id, CharSequence name, int imp) {
NotificationChannel channel = new NotificationChannel(id, name , imp );
NotificationManager nm = getSystemService(NotificationManager.class);
nm.createNotificationChannel(channel);
}
private void display(int id , CharSequence channel_id, String content, String title , Context ctx){
createChannel((String)channel_id , channel_id , NotificationManager.IMPORTANCE_HIGH);
NotificationCompat.Builder nb = new NotificationCompat.Builder(ctx, (String) channel_id)
.setSmallIcon(R.drawable.ic_work_black_24dp)
.setContentText(content)
.setContentTitle(title)
.setPriority(NotificationCompat.PRIORITY_MAX);
NotificationManagerCompat nmc = NotificationManagerCompat.from(ctx);
nmc.notify(id , nb.build() );
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i(tag, "Job has been started");
Job(params);
return true;
}
private void Job(JobParameters params){
new Thread(new Runnable() {
@Override
public void run() {
while (true){
Log.i(tag, "Job is Running");
///////////////////////////////////////////////////
//the crash begin here.
display(id++ , "channel1" , "Description" , "title" , this);
////////////////////////////////////////////////////////////////
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
//jobFinished(params , true);
}
@Override
public boolean onStopJob(JobParameters params) {
Log.i(tag, "Job has been cancelled");
cancelled = true;
return true;
}
}
调用作业的代码:
ComponentName cname = new ComponentName(this, Job1.class);
JobInfo jinfo = new JobInfo.Builder(1, cname)
.setRequiresCharging(false)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setPersisted(true)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int result = scheduler.schedule(jinfo);
if (result == JobScheduler.RESULT_SUCCESS) {
Log.i("job", "scheduled");
} else {
Log.i("job", "failed");
}
当然,我还添加了具有 AndroidManifest.xml
权限的服务名称 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service android:name=".Job1"
android:permission="android.permission.BIND_JOB_SERVICE" />
当我尝试单独使用通知功能时,它完美地工作,例如仅通过一个按钮使用它,当我删除 Job
中调用 display
函数的行时,工作正常,但是当我将通知与它一起使用时,它会使整个应用程序崩溃,所以可能是什么问题?
看了logcat,仔细阅读,终于找到了解决办法
主要问题出在 JobService
内部的线程本身,当我尝试发出新通知时,应用程序崩溃并显示以下信息:
java.lang.RuntimeException: Can't create handler inside thread Thread[Thread-2,5,main] that has not called Looper.prepare()
解决方案是创建一个新线程 Class 并调用 Looper.prepare()
所以新的 Thread 代码将是这样的 class:
public class TestThread extends Thread{
private int id = 0;
private Context ctx;
public TestThread(Context ctx){
this.ctx = ctx;
}
public void run(){
//this line has solved the issue
Looper.prepare();
while(true){
Log.i("Thread" , "Thread is currently running in background :)");
// my notifciation class
(new Notifications()).displayNot(id++ , "channel6", "Content" , "title" , ctx);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
现在我们在作业中使用这个 class,在我的例子中是在 Job
函数中:
private void Job(JobParameters params){
Thread thread = new TestThread(this);
thread.start();
if(!thread.isAlive()){
jobFinished(params , true);
}
}