I'm trying to create a simple program that does the following:
- A service (NewsService) started by my activity (UpdateServiceActivity) checks for news.
- If news are found (NewsService) sends a broadcast to a receiver (NewsReceiver).
- Upon receiving the broadcast the receiver (NewsReceiver) should notify the activity (UpdateServiceActivity) that there are news.
- Upon notification, the activity (UpdateServiceActivity) gets the news and handles them.
So far I'm just working on a simple example. Here is my code so far:
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
<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>
The problems I run in to are:
- When hitting the 'Home'-button (the App goes to the background, and on pause is called) the NewsReceiver keeps firing toasts. I was of the understanding that once I unregister the receiver, it shouldn't be availible for receiving broadcast.
- Even if I hit the button to stop the NewsService, the TimerTask keeps running and posting broadcast.
What am I doing wrong? Is it a general misunderstanding of how Broadcasting/Receiving works? Am I on track and what should be changed to accomplish what I desire?
Receiver
instance, but that has no effect on the receiver you have registered in the manifest file. Try removing it from the manifest.Timer
that's why it keeps firing. Stopping the service doesn't automatically stop threads you have created (such as the one used by theTimer
)Generally, you should use
AlarmManager
with anIntentService
to schedule repeating background tasks. ATimer
is unreliable and doesn't fit too well with the Android framework. Also, aTimer
won't execute if the phone is asleep. You can have alarms wake up the phone to execute (whether that is a good idea for a news-updating service is another matter) withAlarmManager
.EDIT
This in combination with Nikolay Elenkov suggestion about using ScheduledThreadPoolExecutor provided a very nice solution.
I found a solution that fits my purpose better than using a Service and BroadcastReceiver. I have no need to check for news/updates when the app is not running, so using a service would be overkill and just use more data than needed. I found that using Handlers was the way to go. Here is the implementation that works perfectly:
Avtivity:
NewsHandler