2011-12-17 5 views
0

。それは長い間実行されます。最初は私がサービスにこのコードを持っていた:サービスschedulefutureやデータベースの競合

private final Handler handler = new Handler(); 
... 
... 
public int onStartCommand(... 
    handler.postDelayed(sendUpdatesToUI, 50); 
... 

    private Runnable sendUpdatesToUI = new Runnable() { 
     public void run() { 
      try { 
       DBAdapter DB = new DBAdapter(MyService.this); 
       DB.open(); 
       DB.insertData(System.currentTimeMillis(), "", 
        cronometro.tiempo_original, 0) ; 
       DB.close(); 
      } catch (Exception e) { 
       Toast.makeText(MyService.this, e.toString(),Toast.LENGTH_LONG).show(); 
      } 
      SendInfo(); 
      handler.postDelayed(this, 300000); 
    } 
    }; 

をしかし、上記のコードは、問題があります。ハンドラは、UIスレッドで実行されるので、UIの活動がメモリにない場合postdelayed機能は、作業としては動作しません。スレッドはもはやアクティブではありません。そこで、アクティビティ固有のスケジューラ(ハンドラ)の間でシステムスケジューラを使用するようにコードを変更しました。今のコードは次のようになります。

private final ScheduledExecutorService schedulerService = Executors.newScheduledThreadPool(1); 
private ScheduledFuture scheduleFuture; 
... 
... 
public int onStartCommand(... 
    scheduleFuture = schedulerService.schedule(sendUpdatesToUI,50, TimeUnit.MILLISECONDS); 
... 


    private Runnable sendUpdatesToUI = new Runnable() { 
     public void run() { 
      try { 
       DBAdapter DB = new DBAdapter(MyService.this); 
       DB.open(); 
       DB.insertData(System.currentTimeMillis(), "", 
        cronometro.tiempo_original, 0) ; 
       DB.close(); 
      } catch (Exception e) { 
       Toast.makeText(MyService.this, e.toString(),Toast.LENGTH_LONG).show(); 
      } 
      SendInfo(); 
      scheduleFuture = schedulerService.schedule(sendUpdatesToUI,300000,TimeUnit.MILLISECONDS); 
    } 
    }; 

この第二のコードは、活動が前であることを行っていない長いサービスのためにそれを行うための正しい方法です。 あなたがコードを見ることができるように同じことを行うが、それは、メインUIスレッドでdepentハンドラを使用しての問題を回避します。

私は両方のためのSQLコードをコメントしている場合、彼らは限り主な活動は、一番上にあると完璧に実行。しかし、私はコメントSQLコードをしない場合、2番目のサンプルがハングし、実行されません。 DatabaseHelperは有効なコンテキストを必要とし、executorはシステム・コンテキストなので実行されないため、sqlcodeで停止します。 getApplicationContext()、getBaseContext()、またはMyService.thisのようなDBAdapter(コンテキスト)に入れたコンテキストは機能しません。

誰もが2番目の例に有効なコンテキストを提供する方法を知っていますか?

答えて

2

しかし、上記のコードには問題があります。ハンドラはUIスレッドで実行されるため、UIアクティビティがメモリにない場合、動作中のスレッドはもはやアクティブではないため、ポスト遅延機能は動作しません。

サービスは、アクティビティと同じメインアプリケーションスレッド(「UIスレッド」)を共有します。 AFAIK、これはUIの状態にかかわらず "うまくいく"べきです。これは他の理由では実装が貧弱です(下記参照)。

この2番目のコードは、長いサービスのために、アクティビティが正面になることはない正しい方法です。

これは、最初の実装よりも段階的に優れています。どちらも貧しい。あなたのサービスが5分間何もしていない間は、ユーザーのリソースを無駄にしないように、AlarmManagerIntentServiceを使用してください。

DatabaseHelperが有効なコンテキストを必要とし、executorがシステム・コンテキストなので実行されないため、sqlcodeで停止します。

あなたの主張は意味がありません。あなたは限りServiceが実行されているとして、有効ContextあるServiceオブジェクトを使用しています。 ScheduledExecutorServiceは通常のJavaオブジェクトであり、Contextを提供することはできません。私はあなたが「システムコンテキスト」とは何を考えているのか分かりません。

DBAdapter(コンテキスト)(getApplicationContext()、getBaseContext()、MyService.thisなど)に設定したコンテキストは機能しません。

その後、あなたは、このようなデータベースにアクセスする複数のスレッドを持つ同期/デッドロックの問題など、いくつかの他の問題を、持っている、または多分あなたのServiceが破壊(と、それゆえ、あなたはこのような背景のスレッドをリークした)されています。

あなたがAlarmManagerを使用してIntentService、およびすべてのコンポーネント(このサービスとあなたの活動)の間で共有されSQLiteOpenHelperを使用して、onHandleIntent()でデータベースI/Oを行う場合、あなたはより良い結果を持っている必要があります。

+0

私はこの問題に完全に見当たらず、AlarManagerを使用するのは控えめでしたが、今は私がそれを行う方法であると分かっていて、予想以上に簡単です。また、サービスクラスをintentserviceにアップグレードしても、完璧に機能し、バッテリーの消費を抑えることができます。ありがとう。 – Tibor