2011-10-05 22 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。爲什麼您的活動中的視圖不會在回調中更新,那可能就是原因。 –