Часть-2 постоянная служба Android на ForeGround, которая запускается с помощью пользовательского интерфейса, работает и в спящем режиме, а также при перезагрузке телефона
Status:
Очень благодарен всем, кто помогал и руководствовался здесь и в части-1! Я сделал код из исследований и предоставленной помощи и поместил этот рабочий код в EDIT-1. Критика приветствуется, чтобы сделать код лучше.
Scenario:
Я задал вопрос, упомянутый в части 1, но по какой-то причине я не могу постоянно разрабатывать и корректировать стратегию с помощью кода, который имеет истинную интеграцию и здравый смысл.
Это был длительный вопрос, и вопрос или ответ могли быть завершены или окончательно завершены только в одном эпизоде, поэтому я сделал эту вторую часть в качестве краткого изложения.
Может быть, я некомпетентен или просто обеспокоен чтением разрозненной документации и ответов на разные стратегии, или ответы имеют разные взгляды / стили кодирования.
Question:
Вот то, что я хотел и, наконец, пришел к выводу после наблюдения различных ответов:
Необходимо запускать код каждые 15 минут (даже когда телефон спит). Думаю, понадобятся ли замки от пробуждения?
//AT boot, check shared preferences to see boolean "serviceEnabled"?
//if true, set alarm manager to run a service every 15 minuts.
//if false, do nothing.
//On "enable" button clicked.
//make "serviceEnabled" boolean true in shared preferences.
//start alarm manager to run a service every 15 minuts.
//on "Disable" button clicked.
//make "serviceEnabled" boolean false in shared preferences.
//stop alarm manager and deregister it to run ever.
Может кто-нибудь всесторонне сказать... какой код я должен использовать...? Я смиренно благодарен за головную боль исследования.
Requests:
Пожалуйста, отвечайте, только если вы уверенно и с опытом знаете, что делаете.
EDIT-1-Start:
Вот что я сделал до сих пор. Пожалуйста, не стесняйтесь комментировать или критиковать.
Booter класс, который запускается при загрузке.
public class Booter extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.e("boot-status","BOOT_COMPLETED=================================================");
// SharedPreferences prefs = context.getSharedPreferences("$MYPACKAGE_preferences",0);
// if (prefs.getBoolean("startatboot",false)) {
if(true){
Intent updateIntent = new Intent();
updateIntent.setClass(context, TheService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, updateIntent, 0);
AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);
}
}
}
}
Сервисный класс
public class TheService extends Service{
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
PowerManager pm;
PowerManager.WakeLock wl;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
startForeground(1, new Notification());
////// will do all my stuff here on in the method onStart() or onCreat()?
Log.e("app-status","ping ====================================================");
new Thread(new Runnable() {
@Override
public void run() {
wl.release();
stopSelf();
}
}).start();
return START_STICKY;
}
@Override
public void onDestroy() {
stop();
}
public void stop(){
//if running
// stop
// make vars as false
// do some stopping stuff
stopForeground(true);
}
}
Графический интерфейс для запуска / остановки
public class SettingsActivity extends Activity {
// some code to initialize things
buttonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent updateIntent = new Intent();
updateIntent.setClass(SettingsActivity.this, TheService.class);
PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
//make sharepred boolean as false
}
});
buttonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent updateIntent = new Intent();
updateIntent.setClass(SettingsActivity.this, TheService.class);
PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, 0);
AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);
//make shared prefs boolean as true
}
});
Menifiest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> // irrelevent here
<uses-permission android:name="android.permission.INTERNET" /> // my app uses these though in service class.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:allowBackup="true"
android:debuggable="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.myapp.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.myapp.SettingsActivity"
android:label="@string/title_activity_settings" >
</activity>
<service android:name=".TheService" />
<receiver android:name=".Booter" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
</application>
</manifest>
EDIT-1-END.
1 ответ
Если вам нужно только запускать этот код каждые 15 минут. тогда вам действительно не нужно поддерживать сервис в режиме 24/7. На самом деле, не делай этого, это плохая идея. что вам нужно сделать, это:
Используйте AlarmManager для планирования будильника каждые 15 минут. этот сигнал тревоги затем перехватывается с помощью BroadcastReceiver. Этот сигнал тревоги ДОЛЖЕН БЫТЬ RTC_WAKE_UP, чтобы он разбудил телефон, если он находится в режиме глубокого сна, и должен работать в режиме реального времени, поскольку он будет использовать таймер глубокого сна.
Приемник вещания должен будет запустить службу. Теперь этот вызов в сервис должен быть выполнен так:
- 2.1 получить пробуждение в BroadcastReceiver и приобрести () его.
- 2.2 запустить IntenetService (этот тип услуг запускается и заканчивается после завершения работы)
- 2.3 выпустить wakelock в сервисе
Вот хороший пример того, как реализовать это здесь: WakefulIntentService от commonsware. Вам не нужно использовать его как есть, вы можете сделать свой собственный сервис и широковещательный приемник. Просто не забудьте захватить блокировку перед вызовом сервиса и разблокировать его, когда сервис будет выполнен, иначе сервис может не быть вызван.
- Ваша служба выполняет все, что вы хотите, каждые 15 минут. Затем вы можете перенести еще один звонок через 15 минут. Вы также можете проверить, включена ли служба с помощью общих настроек, перед выполнением и перепланированием.
Что касается вашей деятельности, контролирующей ваши услуги:
- Когда кнопка нажата, проверьте состояние общего предпочтения и сохраните обратное.
- Затем отправьте широковещательную рассылку на тот же приемник, который запускает ваш сервис, если они его включили (или запланируйте его на потом).
- Если он был отключен, то отмените все расписания для службы.
Что касается вашего требования загрузки:
- Объявите в своем манифесте, что тот же получатель, который запускает вашу службу, вызывается при вызове действия android.intent.action.BOOT_COMPLETED.
- Объявите разрешение: android.permission.RECEIVE_BOOT_COMPLETED
Пример манифеста:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.yourcompany.yourapp"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.yourcompany.yourapp.activities.HomeActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.yourcompany.yourapp.services.ActionHandlerService" />
<receiver android:name="com.yourcompany.yourapp.receivers.BootReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
</application>
</manifest>
Пример отмены и планирования сигналов тревоги:
public synchronized static void disableTimers(final Context context)
{
Log.i(TAG, "Canceling Alarms");
final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel(pi);
}
public synchronized static void enableTimer(final Context context)
{
Log.i(TAG, "Enabling Alarm");
final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + FIFTEEN_MINUTES, pi);
}
Пример запуска службы при загрузке:
@Override
public void onReceive(final Context context, final Intent intent)
{
final Intent in = new Intent(context, MyService.class);
in.setAction(Actions.BOOT_RECEIVER_ACTION);
Log.i(TAG, "Boot completed. Starting service.");
MyService.acquireLock();
context.startService(in);
}
А на сервисе снимаем блокировку
private static volatile WakeLock mStaticWakeLock = null;
private synchronized static WakeLock getLock(final Context context)
{
if (mStaticWakeLock == null)
{
final PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mStaticWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_PARAMETER);
mStaticWakeLock.setReferenceCounted(true);
}
return mStaticWakeLock;
}
@Override
protected final void onHandleIntent(final Intent intent)
{
try
{
run(intent);
}
finally
{
final WakeLock lock = getLock(getApplicationContext());
if (lock.isHeld())
{
lock.release();
Log.i(TAG, "Releasing WakeLock");
}
}
}
Вот и все.