【问题标题】:How can I periodically run a service/thread in background even when the screen is locked?即使屏幕被锁定,如何在后台定期运行服务/线程?
【发布时间】:2016-02-25 13:17:53
【问题描述】:

我正在开发一个可以每半小时检查一次网络数据的应用程序,我需要确保它在电源打开的情况下一直运行。 目前,我的应用程序的结构是这样的:

  1. main_activity:
    onCreate()中的AlarmManager
  2. 报警接收器:
    启动服务 获取服务的 partial_wl
  3. 服务:
    使用 StrictMode 获取网络数据 如果需要数据,则弹出 activity_2
  4. activity_2:
    振动 退出按钮(activity_2.this.finish())

但在测试中,我发现服务将在前 30 分钟后停止(被终止)。另外,如果我在服务中启动一个用于联网的线程而不是使用StrictMode,它会在屏幕锁定后5分钟内被杀死。

希望有人可以对此提出建议。真是令人不安。 非常感谢。

【问题讨论】:

  • 运行后台服务只是为了检查是否有新数据可用不是一个好主意。尝试使用 GCM 实现相同的功能。
  • 您不需要创建服务。 AlarmManager 每半小时重复一次不精确的警报就可以了。事实上,它就是为此目的而制作的。如果数据可用,我还建议通知,而不是自己显示活动。这样,用户就会收到通知,并可以在方便时打开已存在数据的活动。

标签: android multithreading service wakelock


【解决方案1】:

公共服务与活动无关。如果您希望它开始定期检查我的服务: https://bitbucket.org/kvrus/ocs-android/raw/036de7f0d3579b2a193bcb82309f7f82819508e6/app/src/main/java/koss/ru/oneclickrate/network/EcbEuropeService.java

/** * 定期从网络加载汇率 * 在广播消息中返回结果。 * 由 koss 于 16 年 2 月 19 日创建。 * */ 公共类 EcbEuropeService 扩展服务 {

public static final String ECB_URL = "http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml";
public static final int UPDATE_PERIOD = 30000;
public static final int UPDATE_TICK = 1000;

public static final String NOTIFICATION = "koss.ru.oneclickrate.receiver";
public static final String EXTRA_CURRENCIES_MAP = "extra_currencies_map";

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    getUrlData();
    return Service.START_NOT_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
    return null;
}

public Cubes getUrlData() {
    (new AsyncTask<Object, Object, Cubes>() {
        Map<CurrencyType, BigDecimal> result = new EnumMap<CurrencyType, BigDecimal>(CurrencyType.class);

        @Override
        protected Cubes doInBackground(Object... params) {
            Cubes cubes = new Cubes();
            InputStream is = null;
            HttpURLConnection urlConnection = null;
            try {
                URL url = new URL(ECB_URL);
                urlConnection = (HttpURLConnection) url.openConnection();
                is = urlConnection.getInputStream();
                cubes = EcbEuropeResponseParser.parse(is);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if(urlConnection!=null) IOUtils.close(urlConnection);
                if(is!=null) IOUtils.closeQuietly(is);
                return cubes;
            }
        }

        @Override
        protected void onPostExecute(Cubes map) {
            super.onPostExecute(map);
            sendBroadcastMessage(map);
            startTimer();
        }
    }).execute();
    return null;
}

/**
 * Restarts timer
 * */
public void startTimer() {
    cdt.cancel();
    cdt.start();
}

CountDownTimer cdt = new CountDownTimer(UPDATE_PERIOD, UPDATE_TICK) {
    @Override
    public void onTick(long millisUntilFinished) {

    }

    public void onFinish() {
        getUrlData();
    }
};

private void sendBroadcastMessage(Cubes currenciesMap) {
    Intent intent = new Intent(NOTIFICATION);
    intent.putExtra(EXTRA_CURRENCIES_MAP, currenciesMap);
    sendBroadcast(intent);
}

【讨论】:

    【解决方案2】:

    我改变了一些东西,现在效果很好。

    1.由于我的手机是4.4.2(api=19),alarmmanager.setrepeating 不准确。所以我转而使用 .setExact(.set() 的新方法)并在 Service 中的 AsyncTask(network) 结束时重新安排警报。

    2.将wakelock实例设为全局,在AlarmReceiver中获取并在AsyncTask结束时释放。我曾经将 .release() 放在 onDestroy() 中,它会在任务完成之前释放锁。

    3.我的手机有一个后台保护应用的设置,我没有打开。这可以让系统杀死应用程序并禁用警报管理器。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 2023-03-22
      • 1970-01-01
      • 2021-06-22
      相关资源
      最近更新 更多