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 的使用感到困惑。看来,我可以用:

使用 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 提供解决方案。

帮助链接:

  1. Getting started
  2. WorkManager Periodicity

这里只是最后一段代码:

  1. 在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"
     }
    
  2. 写工人(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());
     }
    

    }

  3. 在MainActivity.java

    的onCreate中调用Worker init
     NewPostNotification.scheduleReminder();
    

就是这样。

你有两个选择:

  1. 使用上述答案中所述的 WorkManager,但如果您希望在非常准确的时间完成任务,它们可能不太好。在某些设备中,它们运行良好,但在具有电池优化功能的自定义 OS 设备中,它们无法像您期望的那样工作。

  2. 如果您想在特定时间执行一项任务,请使用警报管理器+广播接收器+意图服务,请记住您必须将服务作为前台服务启动。