Android 应用程序通过服务 运行 在后台检查服务器(排球)中显示通知,即使该应用程序已关闭
Show notification by an Android app through service running in background checking server (volley) even when the app is closed
如问题中所述,我想要一个 background process 到 运行 的应用程序(每天 21:30),它向服务器发出截击请求并根据需要显示通知根据结果。单击通知后,将打开特定的 link(由应用程序处理)。
来自 class 的服务器请求和响应(通过 async Volley)工作正常。 link-处理程序也已设置。
我进行了研究,对 class 的使用感到困惑。看来,我可以用:
- Service 或
- BroadcastReceiver(AlarmManager)
使用 AlarmManager(清单中添加了 receiver
标签),我设置了以下在 MainActivity.java 的 onCreate 中调用的方法:
private void setAlarms()
{
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, NewNewsNotification.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, i, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * 60 * 60, alarmIntent);
if (alarmMgr!= null) {
alarmMgr.cancel(alarmIntent);
}
}
NewNewsNotification.java
@Override
public void onReceive(Context context, Intent intent) {
rCtx= context;
fetch_last_update();
}
public void fetch_last_update()
{
VolleyCallback();
VolleyService = new AsyncJsonFetch(ResultCallback, rCtx);
try {
JSONObject sendObj = new JSONObject();
mVolleyService.postDataVolley("POSTCALL", "news", sendObj);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void VolleyCallback()
{
pResultCallback = new AsyncJsonData() {
@Override
public void notifySuccess(String requestType, JSONObject response) throws JSONException {
int stat = (int) response.get("status");
if (stat == 1) {
JSONObject msgJSON = (JSONObject) response.get("msg");
Log.d(TAG, "msgJSON: "+msgJSON);
/*The above log is working correctly. PROCESS THE JSON HERE AND GENERATE THE NOTIFICATION*/
}
}
@Override
public void notifyError(String requestType, VolleyError error) {
Log.d(TAG, "Volley requester " + requestType);
Log.d(TAG, "Volley JSON post" + "That didn't work!");
}
};
}
正确的方法是什么,如何实施?如何启动可点击通知?
Android 有更新更好的解决方案,完全符合您的需要
The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs
你可以在这里查看官方主题:work manager
感谢 @Farid 提供解决方案。
帮助链接:
这里只是最后一段代码:
在build.gradle(app)中添加依赖:
dependencies {
...
def work_version = "2.4.0"
implementation "androidx.work:work-runtime:$work_version"
implementation "androidx.work:work-rxjava2:$work_version"
androidTestImplementation "androidx.work:work-testing:$work_version"
}
写工人(NewNewsNotification.java)
public class NewNewsNotification extends Worker {
private static final String TAG="NewNewsNotification";
private static Context rCtx;
private RequestQueue reQueue;
private String NEWS_TYPE= "post";
private static final int EXEC_MIN= 15;
AsyncJsonFetch mVolleyService;
AsyncJsonData pResultCallback = null;
//Context rCtx;
public NewNewsNotification(
@NonNull Context context,
@NonNull WorkerParameters params) {
super(context, params);
rCtx= context;
}
public static void scheduleReminder() {
Log.d(TAG, "queueing req");
//WorkRequest notificationWork = new PeriodicWorkRequest.Builder(NewNewsNotification.class, 24, TimeUnit.HOURS).build();
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresStorageNotLow(true)
.build();
PeriodicWorkRequest notificationWork = new PeriodicWorkRequest.Builder(NewNewsNotification.class, EXEC_MIN, TimeUnit.MINUTES).addTag(TAG).setConstraints(constraints).build();
WorkManager instance = WorkManager.getInstance(rCtx);
instance.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, notificationWork);
}
@NonNull
@Override
public Result doWork() {
try {
Log.d(TAG, "fetch_last_update called");
fetch_last_update();
return Result.success();
}catch (Throwable e) {
e.printStackTrace();
Log.e(TAG, "Error fetching data", e);
return Result.failure();
}
}
public void fetch_last_update()
{
postDetVolleyCallback();
mVolleyService = new AsyncJsonFetch(pResultCallback, rCtx);
try {
JSONObject sendObj = new JSONObject();
sendObj.put("lastdate", 1);
sendObj.put("NEWS_TYPE", NEWS_TYPE);
mVolleyService.newsDataVolley("POSTCALL", "news", sendObj);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void postDetVolleyCallback()
{
pResultCallback = new AsyncJsonData() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void notifySuccess(String requestType, JSONObject response) throws JSONException {
int stat = (int) response.get("status");
if (stat == 1) {
/***********************************************************/
JSONObject msgJSON = (JSONObject) response.get("msg");
int ldate= Integer.parseInt(msgJSON.get("date").toString());
JSONArray tparray= (JSONArray) msgJSON.get("news");
JSONObject tnews= (JSONObject) tparray.get(0);
String title= tnews.get("news_title").toString();
String excerpt= tnews.get("news_excerpt").toString();
int id= Integer.parseInt(tnews.get("ID").toString());
sendNotification(title, excerpt, id);
}
}
@Override
public void notifyError(String requestType, VolleyError error) {
Log.d(TAG, "Volley requester " + requestType);
Log.d(TAG, "Volley JSON post" + "That didn't work!");
}
};
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void sendNotification(String title, String text, int id) {
String cl_url= rCtx.getString(R.string.client_link);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(cl_url+"?p="+id));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("default", "Default", NotificationManager.IMPORTANCE_DEFAULT);
Objects.requireNonNull(notificationManager).createNotificationChannel(channel);
}
NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "default")
.setContentTitle(title)
.setContentText(text)
.setContentIntent(pendingIntent)
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true);
Objects.requireNonNull(notificationManager).notify(id, notification.build());
}
}
在MainActivity.java
的onCreate中调用Worker init
NewPostNotification.scheduleReminder();
就是这样。
你有两个选择:
使用上述答案中所述的 WorkManager,但如果您希望在非常准确的时间完成任务,它们可能不太好。在某些设备中,它们运行良好,但在具有电池优化功能的自定义 OS 设备中,它们无法像您期望的那样工作。
如果您想在特定时间执行一项任务,请使用警报管理器+广播接收器+意图服务,请记住您必须将服务作为前台服务启动。
如问题中所述,我想要一个 background process 到 运行 的应用程序(每天 21:30),它向服务器发出截击请求并根据需要显示通知根据结果。单击通知后,将打开特定的 link(由应用程序处理)。
来自 class 的服务器请求和响应(通过 async Volley)工作正常。 link-处理程序也已设置。
我进行了研究,对 class 的使用感到困惑。看来,我可以用:
- Service 或
- BroadcastReceiver(AlarmManager)
使用 AlarmManager(清单中添加了 receiver
标签),我设置了以下在 MainActivity.java 的 onCreate 中调用的方法:
private void setAlarms()
{
AlarmManager alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(this, NewNewsNotification.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, i, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 8);
calendar.set(Calendar.MINUTE, 30);
alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),
1000 * 60 * 60, alarmIntent);
if (alarmMgr!= null) {
alarmMgr.cancel(alarmIntent);
}
}
NewNewsNotification.java
@Override
public void onReceive(Context context, Intent intent) {
rCtx= context;
fetch_last_update();
}
public void fetch_last_update()
{
VolleyCallback();
VolleyService = new AsyncJsonFetch(ResultCallback, rCtx);
try {
JSONObject sendObj = new JSONObject();
mVolleyService.postDataVolley("POSTCALL", "news", sendObj);
} catch (JSONException e) {
e.printStackTrace();
}
}
public void VolleyCallback()
{
pResultCallback = new AsyncJsonData() {
@Override
public void notifySuccess(String requestType, JSONObject response) throws JSONException {
int stat = (int) response.get("status");
if (stat == 1) {
JSONObject msgJSON = (JSONObject) response.get("msg");
Log.d(TAG, "msgJSON: "+msgJSON);
/*The above log is working correctly. PROCESS THE JSON HERE AND GENERATE THE NOTIFICATION*/
}
}
@Override
public void notifyError(String requestType, VolleyError error) {
Log.d(TAG, "Volley requester " + requestType);
Log.d(TAG, "Volley JSON post" + "That didn't work!");
}
};
}
正确的方法是什么,如何实施?如何启动可点击通知?
Android 有更新更好的解决方案,完全符合您的需要
The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs
你可以在这里查看官方主题:work manager
感谢 @Farid 提供解决方案。
帮助链接:
这里只是最后一段代码:
在build.gradle(app)中添加依赖:
dependencies { ... def work_version = "2.4.0" implementation "androidx.work:work-runtime:$work_version" implementation "androidx.work:work-rxjava2:$work_version" androidTestImplementation "androidx.work:work-testing:$work_version" }
写工人(NewNewsNotification.java)
public class NewNewsNotification extends Worker { private static final String TAG="NewNewsNotification"; private static Context rCtx; private RequestQueue reQueue; private String NEWS_TYPE= "post"; private static final int EXEC_MIN= 15; AsyncJsonFetch mVolleyService; AsyncJsonData pResultCallback = null; //Context rCtx; public NewNewsNotification( @NonNull Context context, @NonNull WorkerParameters params) { super(context, params); rCtx= context; } public static void scheduleReminder() { Log.d(TAG, "queueing req"); //WorkRequest notificationWork = new PeriodicWorkRequest.Builder(NewNewsNotification.class, 24, TimeUnit.HOURS).build(); Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .setRequiresStorageNotLow(true) .build(); PeriodicWorkRequest notificationWork = new PeriodicWorkRequest.Builder(NewNewsNotification.class, EXEC_MIN, TimeUnit.MINUTES).addTag(TAG).setConstraints(constraints).build(); WorkManager instance = WorkManager.getInstance(rCtx); instance.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, notificationWork); } @NonNull @Override public Result doWork() { try { Log.d(TAG, "fetch_last_update called"); fetch_last_update(); return Result.success(); }catch (Throwable e) { e.printStackTrace(); Log.e(TAG, "Error fetching data", e); return Result.failure(); } } public void fetch_last_update() { postDetVolleyCallback(); mVolleyService = new AsyncJsonFetch(pResultCallback, rCtx); try { JSONObject sendObj = new JSONObject(); sendObj.put("lastdate", 1); sendObj.put("NEWS_TYPE", NEWS_TYPE); mVolleyService.newsDataVolley("POSTCALL", "news", sendObj); } catch (JSONException e) { e.printStackTrace(); } } public void postDetVolleyCallback() { pResultCallback = new AsyncJsonData() { @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void notifySuccess(String requestType, JSONObject response) throws JSONException { int stat = (int) response.get("status"); if (stat == 1) { /***********************************************************/ JSONObject msgJSON = (JSONObject) response.get("msg"); int ldate= Integer.parseInt(msgJSON.get("date").toString()); JSONArray tparray= (JSONArray) msgJSON.get("news"); JSONObject tnews= (JSONObject) tparray.get(0); String title= tnews.get("news_title").toString(); String excerpt= tnews.get("news_excerpt").toString(); int id= Integer.parseInt(tnews.get("ID").toString()); sendNotification(title, excerpt, id); } } @Override public void notifyError(String requestType, VolleyError error) { Log.d(TAG, "Volley requester " + requestType); Log.d(TAG, "Volley JSON post" + "That didn't work!"); } }; } @RequiresApi(api = Build.VERSION_CODES.KITKAT) private void sendNotification(String title, String text, int id) { String cl_url= rCtx.getString(R.string.client_link); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(cl_url+"?p="+id)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); NotificationManager notificationManager = (NotificationManager)getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("default", "Default", NotificationManager.IMPORTANCE_DEFAULT); Objects.requireNonNull(notificationManager).createNotificationChannel(channel); } NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "default") .setContentTitle(title) .setContentText(text) .setContentIntent(pendingIntent) .setSmallIcon(R.mipmap.ic_launcher) .setAutoCancel(true); Objects.requireNonNull(notificationManager).notify(id, notification.build()); }
}
在MainActivity.java
的onCreate中调用Worker initNewPostNotification.scheduleReminder();
就是这样。
你有两个选择:
使用上述答案中所述的 WorkManager,但如果您希望在非常准确的时间完成任务,它们可能不太好。在某些设备中,它们运行良好,但在具有电池优化功能的自定义 OS 设备中,它们无法像您期望的那样工作。
如果您想在特定时间执行一项任务,请使用警报管理器+广播接收器+意图服务,请记住您必须将服务作为前台服务启动。