AlarmManager
Этот механизм позволяет нам не ждать
public class MyActivity extends Activity implements View.OnClickListener{ private ToggleButton mTb; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LinearLayout root = new LinearLayout(this); root.setGravity(Gravity.CENTER); mTb = new ToggleButton(this); mTb.setOnClickListener(this); mTb.setTextOff("Disabled"); mTb.setTextOn("Enabled"); root.addView(mTb, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); setContentView(root, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)); } @Override protected void onResume() { super.onResume(); mTb.setChecked(EternalService.isRunning(this)); } @Override public void onClick(View view) { if (EternalService.isRunning(this)) { EternalService.Alarm.cancelAlarm(this); stopService(new Intent(this, EternalService.class)); mTb.setChecked(false); } else { EternalService.Alarm.setAlarm(this); startService(new Intent(this, EternalService.class)); mTb.setChecked(true); } } }
Это пока только Activity c кнопкой-переключателем. Сам сервис:
public class EternalService extends Service { private static final String TAG = EternalService.class.getName(); @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.v(TAG, "Service started!"); // TODO: тут делаем всё что нам хочется... return super.onStartCommand(intent, flags, startId); } public static boolean isRunning(Context ctx) { ActivityManager manager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE); for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { if (EternalService.class.getName().equals(service.service.getClassName())) { return true; } } return false; } @Override public void onDestroy() { super.onDestroy(); Log.v(TAG, "Service stopped!"); } public static class Alarm extends BroadcastReceiver { public static final String ALARM_EVENT = "net.multipi.ALARM"; public static final int ALARM_INTERVAL_SEC = 5; @Override public void onReceive(Context context, Intent intent) { Log.v(TAG, "Alarm received: "+intent.getAction()); if (!isRunning(context)) { context.startService(new Intent(context, EternalService.class)); } else { Log.v(TAG, "don't start service: already running..."); } } public static void setAlarm(Context context) { AlarmManager am=(AlarmManager)context.getSystemService(Context.ALARM_SERVICE); PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ALARM_EVENT), 0); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 1000 * ALARM_INTERVAL_SEC, pi); } public static void cancelAlarm(Context context) { PendingIntent sender = PendingIntent.getBroadcast(context, 0, new Intent(ALARM_EVENT), 0); AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarmManager.cancel(sender); } } }
И не забываем добавить в AndroidManifest (в тег application) строки:
<receiver android:name=".EternalService$Alarm" android:exported="true"> <intent-filter> <action android:name="net.multipi.ALARM" /> </intent-filter> </receiver> <service android:name=".EternalService" />
Но, шутки в сторону
Во-первых, лучший способ помогать своим пользователям - не создавать им новых проблем. Если вы всё-таки решили висеть в памяти их смартфона, то хотя бы не держите открытыми сетевые соединения и (не дай бог) не слушайте спутники GPS. Посадите клиенту батарею и потеряете клиента.
Во-вторых, сервис всё-таки не вечный. Приложение, которое "убили" в настройках перестаёт получать Broadcast-ы а значит уже не оживёт, пока клиент не запустит его снова.
И да, не ставьте слишком короткий интервал вызова вашего сервиса. В большинстве случаев ваш сервис будет ещё жив и вы его проигнорируете, а для системы такие вызовы совсем не "бесплатны".
Гениально!
ОтветитьУдалитьИ как с помощью этого сервиса слушать хотя бы LocationManager.NETWORK_PROVIDER
ОтветитьУдалитьи как после вашего комментария понять хотя бы, что вы не зря занялись программированием.
Удалитьшедеврально.
ОтветитьУдалитьОтличный способ
ОтветитьУдалитья для своих целей вызывал сразу сервис поместив этот код в onStartCommand
Intent service_intent = new Intent(getApplicationContext(), getClass());
service_intent.setAction(ACTION);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getService(this, 1, service_intent, PendingIntent.FLAG_ONE_SHOT);
alarmManager.cancel(pendingIntent);
if(Build.VERSION.SDK_INT >= 19) {
alarmManager.setExact(AlarmManager.RTC, System.currentTimeMillis() + delay, pendingIntent);
} else{
alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + delay, pendingIntent);
}
метод setRepeating как то не совсем точно отрабатывает интервал, было даже что иногда вообще не сработал!
как по мне, точнее будет каждый раз новую задачу - alarmManager.setExact