2011-06-07 64 views
0

我目前正在開發音樂播放器,並且由於每當電話的方向發生變化並且活動重新創建時,我都希望音樂由服務播放。通過這種方式,用戶可以在沒有音樂停止的情況下離開活動。 現在..我有這個奇怪的問題,我一直無法解決...每次我創建活動並膨脹GUI時,服務都會啓動。但是在活動發送數據後服務總是被限制...所以音樂永遠不會開始......我知道發生這種情況是因爲如果我添加一個Button來重新發送數據,音樂開始播放......這是我的代碼該活動:從活動到服務的連接需要很長的時間

public class Player extends Activity{ 

private Cursor audioCursor; 
public static int position=0; 
private int count; 
private boolean pause = false, 
       play= false, 
       stop= false, 
       next= false, 
       back= false, 
       playerActive= true, 
       dataChanged= false, 
       finished= false, 
       playing= true; 
private String action; 
Messenger mService = null; 
boolean mIsBound; 
final Messenger mMessenger = new Messenger(new IncomingHandler()); 
private ServiceConnection mConnection=null; 
static final int MSG_SET_BOOLEAN_VALUE = 5; 
static final int MSG_SET_STRING_VALUE = 4; 
static final int MSG_SET_INT_VALUE = 3; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    requestWindowFeature(Window.FEATURE_NO_TITLE); 
    super.onCreate(savedInstanceState); 

    setContentView(R.layout.player); 
    Bundle extras = getIntent().getExtras(); 
    action=extras.getString("action"); 

      if(!(Background.isRunning())) 
       startService(new Intent(Player.this, Background.class)); 
     doBindService(); 

    if(action.equals("play")){ 
     position=extras.getInt("position"); 
     String[] proj = { 
       MediaStore.Audio.Media.ARTIST, 
       MediaStore.Audio.Media.TITLE, 
       MediaStore.Audio.Media.ALBUM, 
       MediaStore.Audio.Media.DURATION, 
       MediaStore.Audio.Media.IS_MUSIC, 
       MediaStore.Audio.Media.ALBUM_ID}; 

     audioCursor = getContentResolver().query(
       MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj, 
       MediaStore.Audio.Media.IS_MUSIC, null, 
       MediaStore.Audio.Media.TITLE + " ASC"); 
     startManagingCursor(audioCursor); 
     count = audioCursor.getCount(); 

     inflatePlayer(); 
        /////////////////////THIS IS THE CODE THAT ACTS BEFORE THE SERVICE CONNECTION 
     sendBoolToService(playerActive, "playerActive"); 
     sendIntToService(position); 
     sendStringToService(action); 
    } 
} 

    //THIS CODE MUST BE FASTER, BUT THE CONNECTION TAKES TOO LONG 

private ServiceConnection mConnection = new ServiceConnection() { 
    public void onServiceConnected(ComponentName className, IBinder service) { 
     mService = new Messenger(service); 
     Toast.makeText(getApplicationContext(), "ATTACHED!", Toast.LENGTH_LONG).show(); 
     try { 
      Message msg = Message.obtain(null, Background.MSG_REGISTER_CLIENT); 
      msg.replyTo = mMessenger; 
      mService.send(msg); 
     } catch (RemoteException e) { 
      Toast.makeText(getApplicationContext(), "Connection failed!", Toast.LENGTH_LONG).show(); 
     } 
    } 
    public void onServiceDisconnected(ComponentName className) { 
     mService = null; 
     Toast.makeText(getApplicationContext(), "UNATTACHED!", Toast.LENGTH_LONG).show(); 
    } 
}; 

private void inflatePlayer(){ 
    //LOTS OF CODE FOR THE GUI, NOTHING TO DO WITH THE SERVICE... SO I OMITTED IT 
} 

@Override 
protected void onStop(){ 
    playerActive=false; 
    try { 
     doUnbindService(); 
    } catch (Throwable t) { 
    } 
    if(!playing) 
     stopService(new Intent(Player.this, Background.class)); 
    super.onStop(); 
} 

@Override 
protected void onDestroy(){ 
    playerActive=false; 
    audioCursor.close(); 
    try { 
     doUnbindService(); 
    } catch (Throwable t) { 
    } 
    if(!playing) 
     stopService(new Intent(Player.this, Background.class)); 
    super.onDestroy(); 
} 

class IncomingHandler extends Handler { 
    @Override 
    public void handleMessage(Message msg) { 
     switch (msg.what) { 
     case MSG_SET_INT_VALUE: 
      String str = Integer.toString(msg.getData().getInt("int1")); 
      Toast.makeText(getApplicationContext(), "Int Message: " + str, Toast.LENGTH_LONG).show(); 
      break; 
     case MSG_SET_STRING_VALUE: 
      String str1 = msg.getData().getString("str1"); 
      break; 
     case MSG_SET_BOOLEAN_VALUE: 
      dataChanged=msg.getData().getBoolean("dataChanged"); 
      finished=msg.getData().getBoolean("finished"); 
      playing=msg.getData().getBoolean("playing"); 
      if(!playing){ 
       if(finished){ 
        finished=false; 
        finish(); 
       } 
      } 
     default: 
      super.handleMessage(msg); 
     } 
    } 
} 

private void sendIntToService(int intvaluetosend) { 
    if (mService != null) { 
     try { 
      Bundle b = new Bundle(); 
      b.putInt("int1", intvaluetosend); 
      Message msg = Message.obtain(null, MSG_SET_INT_VALUE); 
      msg.setData(b); 
      mService.send(msg); 
     } catch (RemoteException e) { 
     } 
    } 
} 

private void sendStringToService(String stringtosend) { 
    if (mService != null) { 
     try { 
      Bundle b = new Bundle(); 
      b.putString("str1", stringtosend); 
      Message msg = Message.obtain(null, MSG_SET_STRING_VALUE); 
      msg.setData(b); 
      mService.send(msg); 
     } catch (RemoteException e) { 
     } 
    } 
} 

private void sendBoolToService(boolean booltosend, String name) { 
    if (mService != null) { 
     try { 
      Bundle b = new Bundle(); 
      b.putBoolean(name, booltosend); 
      Message msg = Message.obtain(null, MSG_SET_BOOLEAN_VALUE); 
      msg.setData(b); 
      mService.send(msg); 
     } catch (RemoteException e) { 
     } 
    } 
} 


void doBindService() { 
    bindService(new Intent(this, Background.class), mConnection, Context.BIND_AUTO_CREATE); 
    mIsBound = true; 
    Toast.makeText(getApplicationContext(), "BOUND!", Toast.LENGTH_LONG).show(); 
} 

void doUnbindService() { 
    if (mIsBound) { 
     if (mService != null) { 
      try { 
       Message msg = Message.obtain(null, Background.MSG_UNREGISTER_CLIENT); 
       msg.replyTo = mMessenger; 
       mService.send(msg); 
      } catch (RemoteException e) { 
      } 
     } 
     unbindService(mConnection); 
     mIsBound = false; 
     Toast.makeText(getApplicationContext(), "UNBOUND!", Toast.LENGTH_LONG).show(); 
    } 
} 
} 

的服務:

public class Background extends Service { 

private NotificationManager nm; 
private Cursor audioCursor; 
MediaPlayer mp = new MediaPlayer(); 
private int count; 
private boolean pause = false, 
       play= false, 
       stop= false, 
       next= false, 
       back= false, 
       playerActive= true, 
       dataChanged= false, 
       finished= false, 
       playing= false; 
private int position; 
private String action; 

ArrayList<Messenger> mClients = new ArrayList<Messenger>(); 
static final int MSG_REGISTER_CLIENT = 1; 
static final int MSG_UNREGISTER_CLIENT = 2; 
static final int MSG_SET_INT_VALUE = 3; 
static final int MSG_SET_STRING_VALUE = 4; 
static final int MSG_SET_BOOLEAN_VALUE = 5; 
final Messenger mMessenger = new Messenger(new IncomingHandler()); 
private static boolean isRunning = false; 
private static final String TAG = "Background"; 

@Override 
public IBinder onBind(Intent intent) { 
    return mMessenger.getBinder(); 
} 

class IncomingHandler extends Handler { 
    @Override 
    public void handleMessage(Message msg) { 
     switch (msg.what) { 
     case MSG_REGISTER_CLIENT: 
      mClients.add(msg.replyTo); 
      break; 
     case MSG_UNREGISTER_CLIENT: 
      mClients.remove(msg.replyTo); 
      break; 
     case MSG_SET_INT_VALUE: 
      position=msg.getData().getInt("int1"); 
      break; 
     case MSG_SET_STRING_VALUE: 
      action=msg.getData().getString("str1"); 
      if(action.equals("play")){ 
       String[] proj = { MediaStore.Audio.Media.DATA, 
         MediaStore.Audio.Media.DURATION, 
         MediaStore.Audio.Media.IS_MUSIC, 
         MediaStore.Audio.Media.TITLE}; 

       audioCursor = getContentResolver().query(
         MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, proj, 
         MediaStore.Audio.Media.IS_MUSIC, null, 
         MediaStore.Audio.Media.TITLE + " ASC"); 
       count = audioCursor.getCount(); 

       audioCursor.moveToPosition(position); 
       int column_index = audioCursor.getColumnIndex(MediaStore.Audio.Media.DATA); 
       String path = audioCursor.getString(column_index); 
       startAudioPlayer(path); 
       playing=true; 
       if(playerActive) 
        sendBool(playing, "playing"); 
      }else{ 
       startAudioPlayer(action); 
       playing=true; 
       if(playerActive) 
        sendBool(playing, "playing"); 
      } 
      action=null; 
      break; 
     case MSG_SET_BOOLEAN_VALUE: 
      pause=msg.getData().getBoolean("pause"); 
      play=msg.getData().getBoolean("play"); 
      stop=msg.getData().getBoolean("stop"); 
      next=msg.getData().getBoolean("next"); 
      back=msg.getData().getBoolean("back"); 
      playerActive=msg.getData().getBoolean("playerActive"); 
      if(pause){ 
       mp.pause(); 
       play=false; 
       playing=false; 
       sendBool(playing, "playing"); 
       pause=false; 
      } 
      if(play){ 
       pause=false; 
       mp.start(); 
       playing=true; 
       sendBool(playing, "playing"); 
       play=false; 
      } 
     default: 
      super.handleMessage(msg); 
     } 
    } 
} 

private void sendInt(int intvaluetosend) { 
    for (int i=mClients.size()-1; i>=0; i--) { 
     try { 
      Bundle b = new Bundle(); 
      b.putInt("int1", intvaluetosend); 
      Message msg = Message.obtain(null, MSG_SET_INT_VALUE); 
      msg.setData(b); 
      mClients.get(i).send(msg); 
     } catch (RemoteException e) { 
      mClients.remove(i); 
      Log.d(TAG, "Int not send..."+e.getMessage()); 
     } 
    } 
} 

private void sendString(String stringtosend) { 
    for (int i=mClients.size()-1; i>=0; i--) { 
     try { 
      Bundle b = new Bundle(); 
      b.putString("str1", stringtosend); 
      Message msg = Message.obtain(null, MSG_SET_STRING_VALUE); 
      msg.setData(b); 
      mClients.get(i).send(msg); 
     } catch (RemoteException e) { 
      mClients.remove(i); 
      Log.d(TAG, "String not send..." +e.getMessage()); 
     } 
    } 
} 

private void sendBool(boolean booltosend, String name) { 
    for (int i=mClients.size()-1; i>=0; i--) { 
     try { 
      Bundle b = new Bundle(); 
      b.putBoolean(name, booltosend); 
      Message msg = Message.obtain(null, MSG_SET_BOOLEAN_VALUE); 
      msg.setData(b); 
      mClients.get(i).send(msg); 
     } catch (RemoteException e) { 
      mClients.remove(i); 
      Log.d(TAG, "Bool not send..." +e.getMessage()); 
     } 
    } 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
    showNotification(); 
    isRunning=true; 
} 

private void showNotification() { 
    nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); 
    CharSequence text = getText(R.string.maintit); 
    Notification notification = new Notification(R.drawable.icon, text, System.currentTimeMillis()); 
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Player.class), 0); 
    notification.setLatestEventInfo(this, getText(R.string.app_name), text, contentIntent); 
    nm.notify(R.string.app_name, notification); 
} 

@Override 
public void onDestroy() { 

    //REMEMBER TO SAVE DATA! 
    if(mp.isPlaying()) 
     mp.stop(); 
    mp.release(); 
    isRunning=false; 
    audioCursor.close(); 
    nm.cancel(R.string.app_name); 
    super.onDestroy(); 
} 

public static boolean isRunning() 
{ 
    return isRunning; 
} 

public void startAudioPlayer(String path){  
    try { 
     if(mp.isPlaying()) 
      mp.reset(); 
     mp.setDataSource(path); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
     Log.d(TAG,e.getMessage()); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
     Log.d(TAG,e.getMessage()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     Log.d(TAG,e.getMessage()); 
    } 
    try { 
     mp.prepare(); 
    } catch (IllegalStateException e) { 
     e.printStackTrace(); 
     Log.d(TAG,e.getMessage()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
     Log.d(TAG,e.getMessage()); 
    } 
    mp.start(); 
} 
} 

我希望有人能幫助,即時通訊變得非常沮喪與此!另外,我很確定媒體播放器沒有問題,我在沒有服務之前測試過它...遊標也正常工作...事情是...我是否需要從GUI爲它調用服務玩音樂?我究竟做錯了什麼?

編輯:網站不會允許我回答我自己的問題,所以我在這裏發佈的解決方案:

好了,終於找到了解決辦法! 我讀一旦onCreate方法完成與服務之間的交互是唯一可用的。所以,我增加了一個定時器,並與方法填充它,我需要運行:

new Timer().schedule(new TimerTask(){ 
       public void run(){ 
        sendBoolToService(playerActive, "playerActive"); 
        sendIntToService(position); 
        sendStringToService(action);  
      } 
     }, 1000); 

,瞧!有用! :D希望它有用的人!

+0

我不認爲你的解決方案實際上是在糾正原因。這只是恰巧工作的黑客。請參閱下面的答案,瞭解如何通過在服務生命週期中正確的位置調用代碼來正確實現此目標。 – 2011-06-07 06:46:13

回答

0

你需要做的是在的onCreate(),這是依賴於該服務是提供給您onServiceConnected()方法在你ServiceConnection實現移動代碼:

private ServiceConnection mConnection = new ServiceConnection() { 
    public void onServiceConnected(ComponentName className, IBinder service) { 
     mService = new Messenger(service); 
     Toast.makeText(getApplicationContext(), "ATTACHED!", Toast.LENGTH_LONG).show(); 
     try { 
      Message msg = Message.obtain(null, Background.MSG_REGISTER_CLIENT); 
      msg.replyTo = mMessenger; 
      mService.send(msg); 
      sendBoolToService(playerActive, "playerActive"); 
      sendIntToService(position); 
      sendStringToService(action);  
     } catch (RemoteException e) { 
      Toast.makeText(getApplicationContext(), "Connection failed!", Toast.LENGTH_LONG).show(); 
     } 
    } 
    public void onServiceDisconnected(ComponentName className) { 
     mService = null; 
     Toast.makeText(getApplicationContext(), "UNATTACHED!", Toast.LENGTH_LONG).show(); 
    } 
}; 

我還要看看你的服務實現,因爲我不明白你爲什麼調用mService =新的Messenger(服務)。您的IBinder實例應該爲您提供一種獲取對您的服務實例的引用的機制。

+0

但事情是,我需要發送不同類型的數據,具體取決於要播放的音樂,如果只發送一次數據,這將是完美的。此外,如果屏幕中的方向改變,連接將被重新制作。這意味着服務會再次收到數據... – CodeKrieger 2011-06-07 20:59:15

+0

關於我的實現,事實是......我沒有太多經驗,我從其他人那裏創建了自己的代碼......有一種方法可以使它更多有效? – CodeKrieger 2011-06-07 21:02:06

+0

也許你需要考慮擁有比你的活動壽命更長的服務。從服務中解除綁定並不一定會停止服務。當我不知道您的應用程序試圖實現什麼功能時,很難更精確或提供有關如何最佳地優化內容的想法。但是,您的「解決方案」可能會導致偶爾出現的難以追查的崩潰。我強烈建議您熟悉服務生命週期,以更好地瞭解如何高效地使用服務。 – 2011-06-08 05:32:14