2011-10-05 80 views
4

Hy我有一个问题,在服务中设置ServiceUpdateUIListener以更新UI。制作一个新的服务对象并在那里设置监听器并将其放在一个意图中是错误的。在基于服务的类中设置监听器

代码的来源是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

问题是没有多少明确你能解释更多...! – Noby

回答

0

我并不确切地知道自己想要什么,但是这是不这样做的方式。看来你在混合很多东西。

本教程本身对我的意见来说是一个坏例子,对服务中的活动保持静态引用对我来说似乎是不好的做法;您可以使用绑定将您的服务绑定到活动,或者如果您不想要,您可以传递Intents。

据我所知,实例化一个像你一样的服务,并设置一个监听器就像这样不起作用。你在startService()调用中会出错,因为服务实例显然不是一个类;您应该使用TimerService.class。在你的服务中你有一个onStart(); onStart() is a deprecated function,你应该使用onStartCommand()来代替。

现在,如果您有一个想要显示时钟的活动,您不需要,也不希望该服务直接更新其UI,但是如果您希望服务计算新的时钟刻度为你,只需调用startService();只要你的服务是活着的,发送一个新的启动服务意图就会调用onStartCommand()来发送你的意图。

如果你的时钟是一个活动,设置您的活动内的广播接收器,让你的服务广播可以由广播接收器在安装接收,连同通过您的新时钟值的意图。

-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) 
    } 

有可能是这段代码中的一些语法错误,因为我刚刚修改了我的现有代码和正在运行的代码以尝试并适合您的需求。显然还需要进行一些修改,具体取决于你想要做什么。但按照这个框架,你将能够做你想做的事情。

这对我的作品,所以希望你可以修改这个为你工作。(只有我已经离开了的东西是进口的,但你应该能够很容易地找出答案)

要点:

  • 绑定服务UI
  • 在UI文件
  • 注册听众回应从服务内部进行广播。

干杯。

20

的服务文档具有实施在您的应用程序服务,您的应用程序的其他部分可以结合并做出通话相当完整的示例代码:

http://developer.android.com/reference/android/app/Service.html#LocalServiceSample

只要把你的setUpdateListener()方法服务,并调用它,一旦你得到onServiceConnected()的服务。

所以,你的代码将是这样的:

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(); 
    } 
+0

关于此代码需要注意的一点是:您的监听器回调函数来自发出回调函数的Service中的线程,因此如果您想知道fx。为什么您的活动中的视图不会在回调中更新,那可能就是原因。 –