2013-05-22 16 views
9

Ho un servizio associato. Un'attività è vincolante. Non associa il metodo Service on Activity al metodo onStop().Come impedire che il servizio associato venga distrutto mentre il runtime di Activity cambia (es: orientamento)

Il problema è che se le modifiche di runtime (ad esempio, il cambiamento di orientamento) si verificano sull'attività, l'attività viene ricreata. Quindi, il metodo onStop() viene chiamato dall'attività e l'attività non svolge il servizio in quel metodo, il che comporta la distruzione del servizio (e il suo riavvio).

Voglio preservare il Servizio dall'essere distrutto nelle modifiche di runtime mantenendo il Servizio fermo quando l'attività è invisibile. Si potrebbe dire che provare startService() ma fa in modo che il servizio non si fermi quando l'attività è invisibile. Se aggiungo l'attività stopService all'attività onStop(), il risultato è lo stesso di bindService() e unbindService().

PostDelaying unbindService() in onStop() di Acility è in grado di risolvere parzialmente questo problema, ma il tempo di ritardo sarà arbitrario e ciò impedisce all'attività di ottenere GC per qualche tempo. Voglio una soluzione più chiara.

Non voglio soluzioni come android:configChanges="orientation" poiché ci sono anche altre modifiche di runtime, ed è un modo scoraggiato di elaborare le modifiche di runtime.

In breve, voglio che il servizio si comporti come un frammento che ha chiamato setRetainInstance(true). Tuttavia, i frammenti non hanno qualcosa come bindService(). Cosa dovrei fare?

risposta

9

Tuttavia, i frammenti non hanno qualcosa come bindService().

Ma possono utilizzare bindService() dal Application contesto:

public class BshFragment extends Fragment implements OnClickListener, 
    ServiceConnection { 
    private IScript service=null; 
    private Button btn=null; 

    public View onCreateView(LayoutInflater inflater, 
          ViewGroup container, 
          Bundle savedInstanceState) { 
    View result=inflater.inflate(R.layout.main, container, false); 

    btn=(Button)result.findViewById(R.id.eval); 
    btn.setOnClickListener(this); 
    btn.setEnabled(false); 

    setRetainInstance(true); 

    return(result); 
    } 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
    super.onActivityCreated(savedInstanceState); 

    getActivity().getApplicationContext() 
       .bindService(new Intent(getActivity(), 
             BshService.class), this, 
           Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    public void onDestroy() { 
    getActivity().getApplicationContext().unbindService(this); 
    disconnect(); 

    super.onDestroy(); 
    } 

    @Override 
    public void onClick(View view) { 
    EditText script=(EditText)getView().findViewById(R.id.script); 
    String src=script.getText().toString(); 

    service.executeScript(src); 
    } 

    @Override 
    public void onServiceConnected(ComponentName className, IBinder binder) { 
    service=(IScript)binder; 
    btn.setEnabled(true); 
    } 

    @Override 
    public void onServiceDisconnected(ComponentName className) { 
    disconnect(); 
    } 

    private void disconnect() { 
    service=null; 
    btn.setEnabled(false); 
    } 
} 

(come si vede nella this sample project, rivestito in this book)

Usando il contesto Application, siamo in grado di utilizzare lo stesso Context per legare e slegare. Mantenendo il frammento, possiamo evitare di slegare e ribobinarsi su un cambio di configurazione.

Personalmente, cerco solo di evitare lo schema di rilegatura. Sono un appassionato di interfacce liberamente accoppiate, quindi preferisco utilizzare i servizi tramite lo schema di comando e startService().

+0

Non ho trovato il contesto dell'applicazione. Grazie per la risposta. – Naetmul

2

chiamata StartService in onCreate e poi onStop

@Override 
protected void onStop() 
{ 
    super.onStop(); 
    if (!isChangingConfigurations()) 
    { 
      // call stopService 
    } 
} 
+0

Ciò causerà la fuoriuscita della connessione da parte di un servizio associato. – Adam

0

Un altro modo per mantenere vivo un solo-bound servizio durante i cambi di runtime potrebbe essere quella di definire la classe di servizio un metodo come keepAlive:

public void keepAlive(boolean value) { 
    if (value) startService(new Intent(getApplicationContext(), getClass())); 
    else stopSelf(); 
} 

@Override 
public void onRebind(Intent intent) { 
    keepAlive(false); 
} 

@Override 
public boolean onUnbind(Intent intent) { 
    return true; 
} 

Nello stato onRebind() viene ripristinato lo stato del servizio associato solo.

Problemi correlati