2011-02-11 60 views
3

刚接触android时,试图找出服务。我试图将一个服务绑定到一个活动,我正在遵循文档中的示例,但我在下面标记的行(appService.playSong(title))上不断收到NullPointerException。在调试器中检查它显示appService确实为null。Android无法绑定服务

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 

    // ... 

} 

这里是服务的相关部分:

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

我已经注册在AndroidManifest.xml服务,并设置机器人:启用=“真”。你看到这里有什么明显的错误吗?

回答

0

从快速浏览起,它看起来像是在绑定完成之前尝试访问您的服务。您必须确保onServiceConnected在尝试调用您的服务上的任何方法之前已经解雇。

例子:

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

这个例子并不是最好的,但它证明了你必须要等到结合已尝试访问该服务之前完成。

+0

我到底该怎么做? – herpderp 2011-02-11 09:20:36

+0

好吧,它可以像appService上的空检查一样简单,如果它为null,那么它尚未绑定。或者让onServiceConnected方法启动歌曲。 – CeejeeB 2011-02-11 10:34:02

+0

是的,我已经试过,空检查。如果appService为null,则执行bindService(),然后进行playSong调用。它似乎没有帮助。 – herpderp 2011-02-11 22:48:31

1

有两种绑定可以使本地和远程。本地只供您的应用程序和远程使用,以供任何实现特定界面的应用程序使用。 你应该从本地绑定开始。

Local binding tutorial
Remote binding tutorial

我不绑定解决方案:

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

您的服务:

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

好运。

1

假设bindService()将同步连接到服务,但连接将仅在onCreate()完成后才可用。

该框架在UI线程上运行onCreate(),并且bindService()只是稍后注释以便连接到该服务。连接到服务将始终在UI线程上完成,所以这只能在执行onCreate之后才会发生。你甚至不能指望在onCreate()之后立即建立连接。它会在某个时候发生:)。此外,该框架可能会断开它的意愿,但它应该只发生在内存不足的情况下。

因此,将与appService一起使用的代码从onCreate()移动到onServiceConnected(),它会工作。