Установите прослушиватель в сервис-класс - PullRequest
4 голосов
/ 05 октября 2011

Hy У меня проблема с настройкой ServiceUpdateUIListener в службе для обновления пользовательского интерфейса. Неправильно создавать новый объект 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;

        }

Ответы [ 3 ]

24 голосов
/ 15 октября 2011

Сервисная документация содержит достаточно полный пример кода для реализации службы в вашем приложении, к которой может привязываться и выполнять вызовы другая часть вашего приложения:

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();
    }
1 голос
/ 12 октября 2011

Я не знаю точно, что вы хотите, но это не способ сделать это.Кажется, ты много чего путаешь.

Сам учебник, на мой взгляд, является плохим примером, и сохранение статической ссылки на действие в сервисе кажется мне плохой практикой;вы бы использовали привязку, чтобы связать свой сервис с действием, или если вы не хотите, вы можете передать Intents.

Насколько я знаю, создание такого сервиса, как вы, и установка слушателя на него, например,это не работаетВы получаете ошибку в вызове startService (), потому что экземпляр службы, очевидно, не является классом;Вы должны использовать TimerService.class вместо.В вашем сервисе у вас есть onStart (); onStart () является устаревшей функцией , вместо этого следует использовать onStartCommand ().

Теперь, если у вас есть действие, в котором вы хотите показывать часы, которые вам не нужны или не нужныслужба, конечно, обновляет свой пользовательский интерфейс напрямую, но если вы хотите, чтобы служба рассчитывала для вас новый такт, просто вызовите startService ();Пока ваша служба жива, отправка нового намерения службы запуска будет просто вызывать onStartCommand () с намерением, которое вы отправляете.

Если ваши часы заняты, настройте приемник вещания внутри своей деятельности, и пусть ваша служба передает намерение, которое может быть получено настроенным вами вещателем, с передачей нового значения часов.

0 голосов
/ 13 октября 2011

MrJre правильно, что onStart устарела и что вы должны использовать onStartCommand ().

Если вы хотите, чтобы это работало, есть лучший способ.

Я делаю что-то похожее, например, чтобы обновить пользовательский интерфейс на основе результатов, происходящих в службе.Это было не особенно легко.(На мой взгляд)

Вот как это сделать: (Сначала удалите существующий код)

В классе пользовательского интерфейса добавьте:

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

В этом коде могут быть некоторые синтаксические ошибки, так как я только что изменил свой существующий и рабочий код, чтобы он соответствовал вашим потребностям.Очевидно, что также потребуется внести некоторые изменения в зависимости от того, что вы хотите сделать.Но следуйте этой схеме, и вы сможете делать то, что пытаетесь сделать.

Это работает для меня, так что, надеюсь, вы можете изменить это, чтобы работать для вас.(Единственное, что я пропустил, это импорт, но вы должны легко это выяснить)

Ключевые моменты:

  • Служба привязки к интерфейсу пользователя
  • Зарегистрируйте слушателя в файле пользовательского интерфейса для ответа на трансляцию изнутри службы.

Приветствия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...