使用Service、TimerTask和BroadcastReceiver来检查各种更新
我正在尝试创建一个执行以下操作的简单程序:
- 由我的活动 (UpdateServiceActivity) 启动的服务 (NewsService) 检查新闻。
- 如果发现新闻(NewsService),则会向接收者(NewsReceiver)发送广播。
- 接收到广播后,接收者 (NewsReceiver) 应通知活动 (UpdateServiceActivity) 有新闻。
- 收到通知后,活动 (UpdateServiceActivity) 获取消息并处理它们。
到目前为止,我只是在研究一个简单的例子。到目前为止,这是我的代码:
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>
我遇到的问题是:
- 当点击“Home”按钮(应用程序转到后台,并在暂停时调用)NewsReceiver 不断触发 toast。我的理解是,一旦取消注册接收器,它就不能用于接收广播。
- 即使我按下按钮停止 NewsService,TimerTask 也会继续运行并发布广播。
我做错了什么?这是对广播/接收工作原理的普遍误解吗?我是否步入正轨?应该做出哪些改变才能实现我的愿望?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
计时器
,这就是它不断触发的原因。停止服务不会自动停止您创建的线程(例如Timer
使用的线程)。通常,您应该将
AlarmManager
与IntentService
一起使用code> 安排重复的后台任务。Timer
不可靠,并且不太适合 Android 框架。此外,如果手机处于睡眠状态,Timer
将不会执行。您可以使用AlarmManager
让闹钟唤醒手机来执行(这对于新闻更新服务是否是一个好主意是另一回事)。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
.编辑
这与 Nikolay Elenkov 关于使用 ScheduledThreadPoolExecutor 的建议相结合,提供了一个非常好的解决方案。
我找到了一个比使用服务和广播接收器更适合我的目的的解决方案。当应用程序未运行时,我不需要检查新闻/更新,因此使用服务会太过分,只会使用比需要更多的数据。我发现使用处理程序是正确的方法。这是完美运行的实现:
Avtivity:
NewsHandler
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