6

Ok, sono nuovo nello sviluppo di Android e sto tentando di collegarmi a un servizio in modo da poter chiamare i metodi sul servizio dopo che è stato avviato. L'attività e il servizio descritti di seguito sono entrambi parte della stessa applicazione quindi non dovrebbero esserci problemi, ma ogni volta che eseguo la mia app viene visualizzato il seguente errore:Eccezione ClassCast Android durante il binding al servizio

java.lang.ClassCastException: android.os.BinderProxy

La linea di questo accade su è:

LocalBinder binder = (LocalBinder) service; 

Il mio codice attività (semplificato è):

public class Main extends Activity { 

    boolean gpsBound = false; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
    } 

    /** Called whenever the activity is started. */ 
    @Override 
    protected void onStart() { 
     super.onStart(); 
     // Bind to GPSService 
     Intent i = new Intent(this, GPSService.class); 
    startService(i); 
    bindService(i, connection, Context.BIND_AUTO_CREATE); 
    } 

    /** service binding */ 
    private ServiceConnection connection = new ServiceConnection() { 

     public void onServiceConnected(ComponentName className, IBinder service) { 
      // After binding to GPSService get the instance of it returned by IBinder 
     LocalBinder binder = (LocalBinder) service; 
      gpsBound = true; 
     } 

     public void onServiceDisconnected(ComponentName className) { 
      gpsBound = false; 
     } 
    }; 

} 

Servizio:

public class GPSService extends Service { 

    @Override 
    public void onCreate() { 
      super.onCreate(); 
    } 

    @Override 
    public IBinder onBind(Intent i) { 
    // TODO Auto-generated method stub 
    return new LocalBinder<GPSService>(this); 
    } 


    /** 
    * Our implementation of LocationListener that handles updates given to us 
    * by the LocationManager. 
    */ 
    public class CustomLocationListener implements LocationListener { 

     DBHelper db; 

     CustomLocationListener() { 
      super(); 
     } 

    // Overridden methods here... 

    } 

} 

E infine il mio LocalBinder:

/** 
* A generic implementation of Binder to be used for local services 
* @author Geoff Bruckner 12th December 2009 
* 
* @param <S> The type of the service being bound 
*/ 

public class LocalBinder<S> extends Binder { 
    private String TAG = "LocalGPSBinder"; 
    private WeakReference<S> mService; 


    public LocalBinder(S service){ 
     mService = new WeakReference<S>(service); 
    } 


    public S getService() { 
     return mService.get(); 
    } 
} 

ho capito il senso della deroga ClassCast, ma non riesco a capire cosa fare! Ho seguito l'esempio nella documentazione di google, ma non funziona ancora. Qualcuno può far luce su ciò che potrebbe causare questo?

Grazie in anticipo!

risposta

3

il LocalBinder passato in onServiceConnected ha un argomento di tipo generico, mentre la variabile locale LocalBinder binder non ne ha uno.

risolvere questo un modo o nell'altro, sia rimuovendo il tipo generico dalla definizione di LocalBinder, o con l'aggiunta di uno al vostro dichiarazione di vostro raccoglitore variabile locale in onServiceConnected

class MyBoundService extends Service{ 
    private final IBinder mBinder = new MyBinder(); 

    @Override 
    public IBinder onBind(Intent intent) { 
     return mBinder; 
    } 

    public class MyBinder extends Binder{ 

     public void doStuff(){ 
      //Stuff 
     } 
     //More Binder Methods 
    } 
} 

class MyActivity extends Activity{ 
    private MyBinder mBinder; 

    @Override 
    protected void onStart(){ 
     Intent intent = new Intent(this, MyBoundService.class); 
     bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 
    } 

    @Override 
    protected void onStop(){ 
     unbindService(mConnection); 
    } 

    private ServiceConnection mConnection = new ServiceConnection() { 

     @Override 
     public void onServiceConnected(ComponentName className, IBinder service) { 
      mBinder = (TaskBinder) service; 
      mBound = true; 
     } 

     @Override 
     public void onServiceDisconnected(ComponentName arg0) { 
      mBound = false; 
     } 
    }; 

    private void doStuff(){ 
     if (mBound) 
      mBinder.doStuff(); 
    } 
} 

alcuna reale necessità di smanettare con riferimenti deboli e quant'altro. assicurati di svincolarti (non nel campione)

Se vuoi invocare i metodi di servizio appena possibile, basta mettere le chiamate su onServiceConnected, dopo aver impostato mBinder. altrimenti, è sufficiente richiamare da altri callback (eventi onClick e whatnot).

+0

vuoi dire come: 'servizio LocalBinder legante = (LocalBinder );' Se così si dà ancora lo stesso errore! –

+0

Ero inclinato a togliere completamente i farmaci generici. Modificherò in un rapido esempio di utilizzo di un boundService che sto scrivendo in questo momento. –

+0

Ci proveremo senza generici ma se potessi dare un esempio sarebbe fantastico!Grazie, James –

3

Se si sta tentando di collegarsi a un servizio locale che sì, è possibile semplicemente trasmetterlo. Tuttavia, se si sta tentando di eseguire il binding a un servizio remoto (processo separato), è necessario utilizzare il metodo AIDL come prescritto in questo articolo.

http://developer.android.com/guide/components/aidl.html

+0

link non è più valido. –

+0

Ecco il nuovo link valido http://developer.android.com/guide/components/aidl.html – MrMaffen

32

attributo Elimina process nella vostra AndroidManifest.xml del vostro servizio.

+2

Questa è la risposta giusta. – Snicolas

+1

Curioso, qualsiasi motivo dettagliato? –

+0

@ThomasDecaux Credo che sia perché LocalBinder può essere utilizzato solo ogni volta che il servizio viene eseguito nello stesso processo (locale) dell'applicazione. L'attributo di processo crea un processo separato per l'esecuzione del servizio e, pertanto, è necessario utilizzare IPC per comunicare con esso. Durante il processo di bind, Android ti offre un BinderProxy che funge da ponte per il servizio in modo da poter istanziare le tue classi IPC (scritte in AIDL). http://stackoverflow.com/a/10610463/269876 –

4

Aveva lo stesso errore. Ho aggiunto l'attributo android: process = ": process_description" nel manifest. Quando si aggiunge che, il servizio viene creato come processo separato e quindi si ottiene un'istanza di binderProxy (qui l'eccezione calco)