2011-02-11 7 views
3

Nouveau sur Android, en essayant de comprendre Services. J'essaye de lier un service à une activité, je suis les exemples dans la documentation, mais je continue à obtenir une exception NullPointerException sur la ligne marquée ci-dessous (appService.playSong (titre)). Le vérifier dans le débogueur révèle que appService est en effet null.Android ne peut pas lier au service

public class Song extends Activity implements OnClickListener,Runnable { 
protected static int currentPosition; 
private ProgressBar progress; 
private TextView songTitle; 
private MPService appService; 

private ServiceConnection onService = new ServiceConnection() { 
    public void onServiceConnected(ComponentName className, 
      IBinder rawBinder) { 
     appService = ((MPService.LocalBinder)rawBinder).getService(); 
    } 

    public void onServiceDisconnected(ComponentName classname) { 
     appService = null; 
    } 
}; 


public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.song); 

    Intent bindIntent = new Intent(Song.this,MPService.class); 
    bindService(bindIntent,onService, 
      Context.BIND_AUTO_CREATE); 

    Bundle b = getIntent().getBundleExtra("songdata"); 
    String title = b.getString("song title"); 

    // ... 

    appService.playSong(title); // nullpointerexception 

    // ... 

} 

est ici la partie pertinente du service:

package org.example.music; 

// imports 

public class MPService extends Service { 
private MediaPlayer mp; 
public static int currentPosition = 0; 
public List<String> songs = new ArrayList<String>(); 
public static String songTitle; 
private static final String MEDIA_PATH = new String("/mnt/sdcard/"); 

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

    mp = new MediaPlayer(); 
    songs = Music.songs; 
} 

@Override 
public int onStartCommand(Intent intent, int flags, int startId) { 
    return Service.START_STICKY; 
} 

public class LocalBinder extends Binder { 
    MPService getService() { 
     return MPService.this; 
    } 
} 

private final IBinder binder = new LocalBinder(); 

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

public void playSong(String songPath) { 
try { 
    mp.reset(); 
    mp.setDataSource(songPath); 
    mp.prepare(); 
    mp.start(); 

    mp.setOnCompletionListener(new OnCompletionListener() { 
     public void onCompletion(MediaPlayer arg0) { 
      nextSong(); 
     } 
    }); 

    songTitle = songPath.substring(12,songPath.length()-4); 

} catch (IOException e) { 
    Log.v(getString(R.string.app_name),e.getMessage()); 
} 
} 

public void nextSong() { 
if (++currentPosition >= songs.size()) { 
    currentPosition = 0; 
} 
String song = MEDIA_PATH+songs.get(currentPosition); 
playSong(song); 
} 

public void prevSong() { 
if (--currentPosition<0) { 
    currentPosition=songs.size()-1; 
} 
String song = Music.MEDIA_PATH+songs.get(currentPosition); 
playSong(song); 
} 

public int getSongPosition() { 
return mp.getCurrentPosition(); 
} 

public MediaPlayer getMP() { 
return mp; 
} 
} 

Je me suis inscrit dans le service AndroidManifest.xml et définir android: activé = "true". Voyez-vous des erreurs évidentes ici?

Répondre

0

D'un rapide coup d'œil il semble que vous essayez d'accéder à votre service avant la liaison est terminée. Vous devez vous assurer que onServiceConnected a tiré avant d'essayer d'appeler des méthodes sur votre service.

Exemple:

Intent bindIntent = new Intent(Song.this,MPService.class); 
bindService(bindIntent,onService, Context.BIND_AUTO_CREATE); 

//Wait until service has bound 
while(appService == null){ 
    Thread.sleep(100); 
} 
appService.playSong(title); 

Cet exemple est pas le meilleur mais il démontre que vous devez attendre jusqu'à ce que la liaison soit terminée avant d'essayer d'accéder au service.

+0

comment faire exactement cela? – herpderp

+0

Eh bien, cela peut être aussi simple que de faire une vérification nulle sur appService, si c'est null, alors il n'est pas encore lié. Ou faites en sorte que la méthode onServiceConnected démarre la chanson. – CeejeeB

+0

ouais j'ai déjà essayé, la vérification nulle. Si appService est null, faites bindService(), puis effectuez l'appel playSong. ça n'a pas l'air d'aider. – herpderp

1

Il existe deux types de liaisons que vous pouvez effectuer localement et à distance. Local est seulement pour une utilisation par votre application et à distance s'il est utilisé par une application qui implémente certaines interfaces. Vous devriez commencer par la liaison locale.

Local binding tutorial.
Remote binding tutorial.

Ma solution sans se lier:

public class MyActivity extends Activity{ 

    @Override 
    public void onCreate(Bundle savedInstanceState){ 
    ... 
    Intent it = new Intent(MyService.ACTIVITY_START_APP); 
    it.setClass(getApplicationContext(), MyService.class); 
    startService(it); 
} 

    ... 

@Override 
    protected void onResume() { 
     super.onResume(); 
     registerBroadcastReceiver(); 
    } 

@Override 
    protected void onPause() { 
     super.onPause(); 
     this.unregisterReceiver(this.receiver); 
    } 

    ... 

private BroadcastReceiver receiver = new BroadcastReceiver(){ 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      if (intent.getAction().equals(MyService.BROADCAST_INIT)) { 
       //do your stuff here after init 
      } 
     } 
    }; 

private void registerBroadcastReceiver(){ 
     IntentFilter filter = new IntentFilter(); 
     filter.addAction(HMyService.BROADCAST_INIT); 
     this.registerReceiver(receiver, filter); 
    } 
} 

Votre service:

public class MyService extends Service{ 

public static final String BROADCAST_INITIAL_DATA = "org.myapp.BROADCAST_INIT"; 
public static final String ACTIVITY_START_APP = "org.myapp.ACTIVITY_START_APP"; 

    @Override 
    public int onStartCommand (Intent intent, int flags, int startId){ 
    super.onStartCommand(intent, flags, startId); 
    if(intent.getAction().equals(ACTIVITY_START_APP)){ 
     //do your initialization 
     //inform the client/GUI 
     Intent i = new Intent(); 
     i.setAction(BROADCAST_INIT); 
     sendBroadcast(i); 
    }else{ 
     //some other stuff like handle buttons 
    }    
    } 
} 

bonne chance.

+0

Euh, pourriez-vous expliquer le contenu de onServiceConnected? – herpderp

+0

En fait, ce que je voulais vous montrer est une liaison à distance, il nécessite des interfaces AIDL à mettre en œuvre et est plus complexe. Je vais vous donner des liens vers des tutoriels. – danizmax

1

Vous en supposant que le bindService() se connecte au service synchrone, mais la connexion sera disponible seulement après onCreate() finshed.

Le cadre court onCreate() sur le thread d'interface utilisateur et bindService() juste fait une note pour se connecter au service plus tard. La connexion à un service sera toujours effectuée sur le thread de l'interface utilisateur, ce qui ne peut se produire qu'après l'exécution de onCreate. Vous ne pouvez même pas compter sur la connexion en cours de création juste après onCreate(). Cela arrivera après ça :). En outre, le framework peut déconnecter le service sur sa volonté, même si cela ne devrait se produire que dans des conditions de mémoire insuffisante.

, déplacez le code qui fonctionne avec appService de onCreate() à onServiceConnected() et ça va marcher.

+0

Le problème est que onServiceConnected n'est jamais touché. – herpderp

Questions connexes