使用Service,TimerTask和BroadcastReceiver检查各种更新

时间:2011-10-12 07:48:27

标签: android android-service

我正在尝试创建一个执行以下操作的简单程序:

  1. 我的活动(UpdateServiceActivity)启动的服务(NewsService)检查新闻。
  2. 如果找到新闻(NewsService)将广播发送给接收者(NewsReceiver)。
  3. 收到广播后,接收方(NewsReceiver)应通知活动(UpdateServiceActivity)有新闻。
  4. 通知后,活动(UpdateServiceActivity)获取新闻并处理它们。
  5. 到目前为止,我只是在研究一个简单的例子。到目前为止,这是我的代码:

    UpdateServiceActivity

    public class UpdateServiceActivity extends Activity implements OnClickListener {
      private static final String TAG = "UpdateServiceActivity";
      Button buttonStart, buttonStop;
      BroadcastReceiver receiver;
    
      @Override
      public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.main );
    
        buttonStart = (Button) findViewById( R.id.buttonStart );
        buttonStop = (Button) findViewById( R.id.buttonStop );
    
        buttonStart.setOnClickListener( this );
        buttonStop.setOnClickListener( this );
    
        receiver = new NewsReceiver();
      }
    
      @Override
      protected void onPause() {
        super.onPause();
        unregisterReceiver( receiver );
      }
    
      @Override
      protected void onResume() {
        super.onResume();
        registerReceiver( receiver, new IntentFilter() );
      }
    
      public void onClick( View src ) {
        switch( src.getId() ) {
          case R.id.buttonStart:
            Log.e( TAG, "onClick: starting service" );
            startService( new Intent( this, NewsService.class ) );
            break;
          case R.id.buttonStop:
            Log.e( TAG, "onClick: stopping service" );
            stopService( new Intent( this, NewsService.class ) );
            break;
        }
      }
    }
    

    NewsService

    public class NewsService extends Service {
      public static final String NEWS_INTENT = "bs.kalender.news";
      private Timer timer = new Timer();
    
      @Override
      public IBinder onBind( Intent arg0 ) {
        return null;
      }
    
      @Override
      public void onStart( Intent intent, int startId ) {
        startService();
      }
    
      private void startService() {
        timer.scheduleAtFixedRate( new NewsChecker(), 0, 5000 );
      }
    
      private class NewsChecker extends TimerTask {
      @Override
      public void run() {
        Intent intent = new Intent( getApplicationContext(), NewsReceiver.class );
        sendBroadcast( intent );
      }
     }
    }
    

    NewsReceiver

    public class NewsReceiver extends BroadcastReceiver {
      @Override
      public void onReceive( Context context, Intent intent ) {
        Toast.makeText( context, "Broadcast recieved! There is news!", Toast.LENGTH_SHORT).show();
      } 
    }
    

    清单

    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="bs.update"
      android:versionCode="1"
      android:versionName="1.0">
      <uses-sdk android:minSdkVersion="7" />
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
      <application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
          <activity android:name=".UpdateServiceActivity"
                  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=".NewsService" />
          <receiver android:name=".NewsReceiver" />
      </application>
    </manifest>
    

    我遇到的问题是:

    • 当点击“Home”按钮(应用程序进入后台,并且暂停时被调用)时,NewsReceiver会继续发出警告。我的理解是,一旦我取消注册接收器,就不应该接收广播。
    • 即使按下按钮停止NewsService,TimerTask也会继续运行并发布广播。

    我做错了什么?广播/接收的工作方式是否普遍存在误解?我是否正在走上正轨,应该改变什么以实现我的目标?

2 个答案:

答案 0 :(得分:5)

  • 您正在创建和取消注册新的Receiver实例,但这对您在清单文件中注册的接收方没有任何影响。尝试从清单中删除它。
  • 你永远不会取消Timer这就是它继续射击的原因。停止服务不会自动停止您创建的线程(例如Timer使用的线程)

通常,您应该使用AlarmManagerIntentService来安排重复的后台任务。 Timer不可靠,与Android框架不太匹配。此外,如果手机处于睡眠状态,则Timer将无法执行。您可以通过AlarmManager唤醒手机以执行警报(对于新闻更新服务而言,这是另一个问题)。

答案 1 :(得分:1)

修改

这与Nikolay Elenkov关于使用ScheduledThreadPoolExecutor的建议相结合提供了一个非常好的解决方案。


我找到的解决方案比使用Service和BroadcastReceiver更符合我的目的。当应用程序未运行时,我无需检查新闻/更新,因此使用服务会过度使用并且只使用超出需要的数据。我发现使用Handler是可行的方法。以下是完美运行的实现:

<强>活性起着:

public class UpdateServiceActivity extends Activity implements OnClickListener {
   private Handler handlerTimer;
   private Runnable newsHandler;

   @Override
   public void onCreate( Bundle savedInstanceState ) {
      handlerTimer = new Handler();
      newsHandler = new NewsHandler( handlerTimer, this );
      handlerTimer.removeCallbacks( newsHandler );
   }

   @Override
   protected void onPause() {
      handlerTimer.removeCallbacks( newsHandler );
      super.onPause();
   }

   @Override
   protected void onResume() {
      handlerTimer.postDelayed( newsHandler, 5000 );
      super.onResume();
   }
}

<强> NewsHandler

public class NewsHandler implements Runnable {
   private static final int THERE_IS_NEWS = 999;
   private Handler timerHandler;
   private Handler newsEventHandler;
   private Context context;

   public NewsHandler( Handler timerHandler, Context context ) {
      this.timerHandler = timerHandler;
      this.newsEventHandler = new NewsEventHandler();
      this.context = context;
   }

   public void run() {
      Message msg = new Message();
      msg.what = THERE_IS_NEWS;
      newsEventHandler.sendMessage( msg );
      timerHandler.postDelayed( this, 5000 );
   }

   private class NewsEventHandler extends Handler { 
      @Override
      public void handleMessage( Message msg ) {
         if( msg.what == THERE_IS_NEWS )
               Toast.makeText( context, "HandlerMessage recieved! There is news!", Toast.LENGTH_SHORT ).show();
      }
   };
}