2015-01-15 11 views
0

Android 앱에서 여러 가지 다른 작업을 실행하는 작업이 있습니다. 각 작업은 오래 실행되며 네트워크, 데이터베이스 및 파일 시스템을 많이 만듭니다. 각 작업은 사용자가 수동으로 실행하거나 AlarmManager로 예약 할 수 있습니다. 각 작업이 끝날 때까지 실행되므로 사용자가 앱을 떠난 후에도 계속 실행해야하거나 사용자가 앱을 전혀 열지 않아도 계속 실행해야합니다. 잡에는 다음과 같은 ID 속성이 있습니다.Android의 작업 관리자

class Job { 
    int id; 
} 

작업을 받고 ID로 정렬하려면 가상의 JobManager가 필요합니다. id = 1 인 작업이 이미 실행 중이면이 작업이 완료 될 때까지 JobManager는 id = 1 인 모든 후속 작업을 건너 뜁니다. 그러나 작업이 id = 2로 제출되면, 그 작업은 받아 들여지고 첫 번째 작업과 병행하여 실행될 수 있습니다.

작업은 CommonsWare의 WakefulIntentService에서 수행되는 것처럼 완료 될 때까지 절전 모드를 유지해야합니다.

나는 어떻게 이것을 구현하는 몇 가지 아이디어를 가지고 있지만, 모두가 자신의 단점이 있습니다 백그라운드에서 항상 실행하고 어떤 이유로 사망 할 때 자동으로 다시 시작됩니다 서비스 클래스의

  1. 서브 클래스를. 단점 : 아무 것도 실행하지 않더라도 리소스를 소비하므로 UI ​​스레드에서 실행되므로 시스템에서 평상시처럼 종료 될 수있는 스레드를 관리해야하므로 각 클라이언트는 서비스를 시작해야하며 아무도 언제 중지할지 알 수 없습니다.
  2. CommonsWare의 WakefulIntentService. 단점 : IntentService이기 때문에 순차적으로 만 실행되므로 기존 실행중인 작업을 확인할 수 없습니다.
  3. 각 작업에 대해 데이터베이스에서 부울 "running"플래그. 우리가 일을하고 싶을 때마다 그것을 확인하십시오. 단점 : db에 대한 요청이 너무 많으며 제대로 구현하기 어렵고 때로는 2 개의 동일한 작업이 병렬로 실행될 수 있으며 예기치 않은 오류가 발생해도 플래그가 "true"로 유지되지 않을 수 있습니다.
  4. 기존 라이브러리가이 용도로 사용되지 않습니다. 지금 CWAC-깨어 제외에 관해서는 내가 발견 :

    하지만 여전히 나도 몰라,이 라이브러리를 사용하는 방법을 정확하게 실행 다른 Activity, Service, BroadcastReceiver, AlarmManager 등에서 작업을 받아 들일 수있는 하나의 중앙 집중식 서비스는 ID로 정렬하고 병렬로 실행합니다.

이 경우 어떤 해결책을 사용할 수 있는지 알려주십시오.

업데이트 : 내 솔루션을 아래에서 확인하십시오. 모든 가능한 경우에 작동하는지 확실하지 않습니다. 이 문제로 인해 발생할 수있는 문제에 대해 알고 계신다면 의견을 말하십시오.

답변

2

이것은 Lollipop의 새로운 JobScheduler API에 적합하다고 판단되는데,이 경우에는 sdk 구현에없는 모든 기능을 구현하기 위해 래퍼를 만들어야합니다.

Lollipop 아래 버전에서이 기능을 구현해야하는 경우 라이브러리가 compat입니다.

1

누군가가 동일한 문제에 직면하면, 여기 나와있는 해결책이 있습니다.Robospice lib는 서비스에서 일부 작업을 실행하고 결과를 활동과 동기화하는 가장 강력한 방법이기 때문에 사용했습니다. WakeLocks에서이 lib를 사용하는 방법을 찾지 못했기 때문에 SpiceManager와 SpiceRequest라는 두 클래스를 확장했습니다. 새로운 클래스 인 WakefulSpiceManager와 WakefulSpiceRequest는 실제로 WakeLocks에 대한 CommonsWare의 아이디어를 빌려주고 구현은 매우 유사합니다.

WakefulSpiceManager :

public class WakefulSpiceManager extends SpiceManager { 
    private static final String NAME = "WakefulSpiceManager"; 
    private static volatile PowerManager.WakeLock wakeLock; 
    private Context context; 

    public WakefulSpiceManager(Context context, Class<? extends SpiceService> spiceServiceClass) { 
     super(spiceServiceClass); 
     this.context = context; 
     start(context); 
    } 

    private static synchronized PowerManager.WakeLock getLock(Context context) { 
     if (wakeLock == null) { 
      PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 

      wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, NAME); 
      wakeLock.setReferenceCounted(true); 
     } 

     return wakeLock; 
    } 

    public <T> void execute(WakefulSpiceRequest<T> request, RequestListener<T> requestListener) { 
     PowerManager.WakeLock lock = getLock(context); 
     lock.acquire(); 
     request.setLock(lock); 

     // explicitly avoid caching 
     super.execute(new CachedSpiceRequest<T>(request, null, ALWAYS_EXPIRED), requestListener); 
    } 
} 

WakefulSpiceRequest :

public abstract class WakefulSpiceRequest<R> extends SpiceRequest<R> { 
    private PowerManager.WakeLock lock; 

    public WakefulSpiceRequest(Class<R> clazz) { 
     super(clazz); 
    } 

    public void setLock(PowerManager.WakeLock lock) { 
     this.lock = lock; 
    } 

    @Override 
    public final R loadDataFromNetwork() throws Exception { 
     try { 
      return execute(); 
     } finally { 
      if (lock.isHeld()) { 
       lock.release(); 
      } 
     } 
    } 

    public abstract R execute() throws Exception; 
} 

그래서 기본적으로 여기에 우리가 잠금 우리가 WakefulSpiceManager에서 요청을 보내려고 할 때마다 획득. 그 후 잠금은 WakefulSpiceRequest에 전달됩니다. 요청이 작업을 완료하면 release() 메소드를 사용하여 잠금을 지 웁니다. WakefulSpiceManager가있는 활동이 이미 삭제 된 경우에도이 작업이 수행됩니다.

WakefulSpiceManager manager = new WakefulSpiceManager(context, MyService.class); 
    manager.execute(new WakefulSpiceRequest<MyResult>(MyResult.class) { 
     @Override 
     public MyResult execute() throws Exception { 
      return ... 
     } 
    }, new RequestListener<MyResult>() { 
     @Override 
     public void onRequestFailure(SpiceException e) { 
      ... 
     } 

     @Override 
     public void onRequestSuccess(MyResult result) { 
      ... 
     } 
    }); 
:

이제 우리는 우리가 WakefulSpiceManager에서 실행 만 WakefulSpiceRequests을 통과하는 데 필요한 유일한 예외로 평소 Robospice의 방식으로 그 클래스를 사용