我在服务中设置ServiceUpdateUIListener以更新UI时遇到问题。制作一个新的Service对象并在那里设置监听器并将其置于意图中是错误的。
代码源位于http://developerlife.com/tutorials/?p=356,我无法找到如何设置监听器并正确启动服务。
通话:
TimerService service = new TimerService();
TimerService.setUpdateListener(new ServiceUpdateUIListener() {
@Override
public void updateUI(String time) {
clock.setText(time);
}
});
Intent i = new Intent(Timer.this,service.class); //service cannot be resolved to a type
i.putExtra("ms", ms);
startService(i);
服务:
public class TimerService extends Service{
CountDownTimer timer;
Chronometer clock;
public static ServiceUpdateUIListener UI_UPDATE_LISTENER;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
int ms = intent.getIntExtra("ms", 0);
timer = new CountDownTimer(ms,1000){
@Override
public void onTick(long millisUntilFinished) {
int seconds = (int) (millisUntilFinished / 1000) % 60 ;
int minutes = (int) ((millisUntilFinished / (1000*60)) % 60);
int hours = (int) ((millisUntilFinished / (1000*60*60)) % 24);
clock.setText( String.format("%02d:%02d:%02d", hours,minutes,seconds));
Log.e("Timer", String.valueOf(millisUntilFinished));
}
@Override
public void onFinish() {
// TODO Auto-generated method stub
}
}.start();
super.onStart(intent, startId);
}
public static void setUpdateListener(ServiceUpdateUIListener l) {
UI_UPDATE_LISTENER = l;
}
答案 0 :(得分:24)
服务文档包含相当完整的示例代码,用于在您的应用中实现服务的另一部分可以绑定并拨打电话:
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
只需将您的setUpdateListener()方法放在Service上,并在使用该服务获得ServiceConnected()后调用它。
所以你的代码会是这样的:
public interface UpdateListener {
public void onUpdate(long value);
}
class LocalService {
// Like in the Service sample code, plus:
public static String ACTION_START = "com.mypackage.START";
private final ArrayList<UpdateListener> mListeners
= new ArrayList<UpdateListener>();
private final Handler mHandler = new Handler();
private long mTick = 0;
private final Runnable mTickRunnable = new Runnable() {
public void run() {
mTick++;
sendUpdate(mTick);
mHandler.postDelayed(mTickRunnable, 1000);
}
}
public void registerListener(UpdateListener listener) {
mListeners.add(listener);
}
public void unregisterListener(UpdateListener listener) {
mListeners.remove(listener);
}
private void sendUpdate(long value) {
for (int i=mListeners.size()-1; i>=0; i--) {
mListeners.get(i).onUpdate(value);
}
}
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_START.equals(intent.getAction()) {
mTick = 0;
mHandler.removeCallbacks(mTickRunnable);
mHandler.post(mTickRunnable);
}
return START_STICKY;
}
public void onDestroy() {
mHandler.removeCallbacks(mTickRunnable);
}
现在你可以启动服务让它开始计数,任何人都可以绑定它来注册一个监听器来接收回调计数。
很难回答你的问题,因为你并没有真正说出你真正想要完成的事情。有很多方法可以使用服务,无论是启动还是绑定或将两者混合在一起,具体取决于您想要完成的任务。
现在,您可以根据示例再次实现客户端代码:
public class SomeActivity extends Activity implements UpdateListener {
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mBoundService = ((LocalService.LocalBinder)service).getService();
mBoundService.registerListener(this);
}
public void onServiceDisconnected(ComponentName className) {
mBoundService = null;
}
};
void doBindService() {
bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
if (mBoundService != null) {
mBoundService.unregisterListener(this);
}
unbindService(mConnection);
mIsBound = false;
}
}
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
答案 1 :(得分:1)
我不知道你想要什么,但这不是这样做的方法。看来你混淆了很多东西。
本教程本身就是一个不好的例子,在服务中保持对活动的静态引用似乎是不好的做法;你会使用绑定将你的服务绑定到一个活动,或者如果你不想,你可以传递Intents。
据我所知,像你一样实例化服务并在其上设置一个监听器就好了。你在startService()调用中得到一个错误,因为服务实例显然不是一个类;你应该使用TimerService.class
代替。在您的服务中,您有一个onStart(); onStart() is a deprecated function,你应该改用onStartCommand()。
现在,如果你有一个活动,你想要显示一个你不需要的时钟,也不希望服务直接更新它的UI,但如果你想让服务计算一个新的时钟滴答你,只需调用startService();只要您的服务处于活动状态,发送新的启动服务意图只会使用您发送的意图调用onStartCommand()。
如果您的时钟处于某项活动中,请在您的活动中设置一个广播接收器,并让您的服务广播您设置的广播接收器可以接收的意图,并传递新的时钟值。
答案 2 :(得分:-1)
MrJre是正确的,onStart是折旧的,你应该使用onStartCommand()。
如果你想让它发挥作用,有更好的方法。
我正在做类似的事情,比如想要从服务中发生的结果更新UI。这不是特别容易。 (在我看来)
以下是如何操作:(首先废弃现有代码)
在UI类中添加:
public Intent service;
service = new Intent(thisContext, TimerService.class);
service.putExtra("ms", ms);
startService(service);
//bind service to the UI **Important**
bindService();
IntentFilter timerFilter = new IntentFilter("TimerIntent"); // Filter that gets stuff from the service
registerReceiver(myReceiver, timerFilter);
void bindService() {
Intent newIntent = new Intent(this, TimerService.class);
bindService(newIntent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder binder) {
s = ((TimerService.MyBinder) binder).getService();
}
@Override
public void onServiceDisconnected(ComponentName className) {
s = null;
}
};
public void releaseBind() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
// Now in this class we need to add in the listener that will update the UI (the receiver registered above)
private BroadcastReceiver myReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
//Get Bundles
Bundle extras = intent.getExtras();
/* DO ANY UI UPDATING YOU WANT HERE (set text boxes, etc.) TAKING INFO FROM THE "extras" Bundle ie: setting the clock*/
//ie: int timerTest = extras.getInt("0");
// Now update screen with value from timerTest
}
};
服务档案:
public class TimerService extends Service {
public TimerService () {
super();
}
private final IBinder mBinder = new MyBinder();
public Timer clockTimer = new Timer();
public int timer = 0;
// We return the binder class upon a call of bindService
@Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// After service starts this executes
Bundle extras;
extras = intent.getExtras();
/* Call a function to do stuff here. Like if you are a clock call a timer function updates every second */
// Here's an example, modify to fit your needs.
clock();
return START_STICKY;
}
public class MyBinder extends Binder {
TimerService getService() {
return TimerService.this;
}
}
public void clock() {
clockTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
// Some function ie: Time = Time + 1 //
/* MAKE SURE YOU BROADCAST THE RECEIVER HERE. This is what you send back to the UI. IE:*/
timer = timer+ 1; // increment counter
Intent intent = new
//Bundle the timervalue with Intent
intent.putExtra("0", timer);
intent.setAction("TimerIntent");
sendBroadcast(intent); // finally broadcast to the UI
} catch(Exception ie) {
}
}
},
0, // Delay to start timer
1000); // how often this loop iterates in ms (so look runs every second)
}
此代码中可能存在一些语法错误,因为我刚刚修改了现有代码和工作代码以尝试满足您的需求。显然,根据您的要求,还需要进行一些修改。但是按照这个框架,你将能够做你想做的事情。
这对我有用,所以希望你可以修改它以适合你。 (我唯一遗漏的是进口,但你应该能够轻松搞清楚)
关键点:
干杯。