2011-10-05 4 views
4

Hy 서비스를 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

질문이 훨씬 분명하지 않다 ...! – Noby

답변

0

난 당신이 원하는 것을 정확히 모르겠지만,이 그것을 할 수있는 방법이 아니다. 당신이 많은 것들을 섞어 버리는 것 같아요.

자습서 자체는 서비스의 활동에 대한 정적 참조를 유지하는 것이 나쁘게 생각하는 나쁜 예입니다. 바인딩을 사용하여 서비스를 활동에 바인딩하거나, 원하지 않으면 Intent를 전달할 수 있습니다.

나는 당신이하는 것처럼 서비스를 인스턴스화하고 그것에 리스너를 설정하는 것이 효과가 없다는 것을 알고있다. 서비스 인스턴스가 클래스가 아니기 때문에 startService() 호출에서 오류가 발생합니다. 대신 TimerService.class을 사용해야합니다. 귀하의 서비스에는 onStart(); onStart() is a deprecated function 대신 onStartCommand()를 사용해야합니다.

이제 시계를 보여주고 자하는 활동이있는 경우 서비스가 UI를 물론 직접 업데이트 할 필요도없고 서비스가 새로운 시계 틱을 계산하도록하려면 당신을 위해, 단지 startService()를 호출하십시오; 서비스가 살아있는 한 새로운 시작 서비스 인 텐트를 보내면 보내려는 의도로 onStartCommand()가 호출됩니다.

시계가 활동중인 경우 활동 내에서 브로드 캐스트 리시버를 설정하고 사용자가 설정 한 브로드 캐스트 리시버가 수신 할 수있는 인 텐트를 새 브로드 캐스트 값과 함께 전달할 수있게하십시오.

-1

MrJre는 onStart가 가치가 떨어지고 onStartCommand()를 사용해야 함을 의미합니다.

이 기능을 사용하려면 더 좋은 방법이 있습니다.

나는 서비스에서 일어나는 결과로부터 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에
  • UI 파일
  • 등록 리스너가 응답하기 서비스 내부에서 브로드 캐스트합니다.

건배.

20

의 서비스 설명서를 가지고 당신의 응용 프로그램의 다른 부분에 결합에 전화를 걸 수있는 응용 프로그램에서 서비스 구현을위한 상당히 완전한 샘플 코드 : 그냥에 당신의 setUpdateListener() 메소드를 넣어

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

을 서비스를 호출하고 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

이 코드에 대해주의 할 점 : 콜백을 발행하는 서비스의 스레드에서 리스너 콜백이 호출되므로 fx가 궁금한 경우. 왜 액티비티의 뷰가 콜백으로 업데이트되지 않는지 그 이유가 그 이유 일 것입니다. –