没有用户界面在后台运行执行耗时操作的应用组件,存在于当前进程 的主线程中;
但是一些阻塞UI操作(耗时操作,网络请求,联网操作、数据请求)不能放在service中,需另开启一个线程处理。
启动方式,不同的启动方式对应不同的生命周期
注:他的生命周期中只有onStartCommand 可以执行多次,其他都只执行一次;
1. startServie(intent);
onCreate > onStartCommand >onDestory
2.BindService(intent,ServiceConnection,BIND_AUTO_CREATE);
onCreate > onBind > unOnbind > onDestory
<span style="font-size:14px;"><service android:name="com.scxh.android.service.MusicService" /></span>
实现:
一:通过startService开启服务可以通过intent传参数。
startServie(intent);
1.建立一个接口,定义方法
2.定义一个类实现这个接口,并继承Binder
3. 在onBind方法中返回这个接口实例对象;
4.在activity 声明接口,在 new ServiceConnection 里的onServiceConnected方法中将里面的IBinder service 对象强转成接口对象,(当他们建立连接就会得到这个对象)
通过这个接口的实例来实现后台的操作,以播放器为例:
startServie(intent);和BindService 一起在用
package com.scxh.android.service; import java.io.IOException; import java.util.ArrayList; import Constance.MusicBean; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; import android.os.Binder; import android.os.IBinder; import android.util.Log; public class MusicService extends Service { MediaPlayer mPlayer; // 接口的实例 MusicServiceBinder musicBinder = new MusicServiceBinder(); // 数据源 和当前播放位置 是从 activity中通过startService穿过来的 ArrayList<MusicBean> mListData; int currentPosition; @Override public void onCreate() { super.onCreate(); } /* * MediaPlayer 的初始化 */ private void initPlayer() { if (mPlayer == null) { mPlayer = new MediaPlayer(); } try { mPlayer.reset(); mPlayer.setDataSource(mListData.get(currentPosition).getPath()); mPlayer.prepare(); mPlayer.start(); if (musicBinder != null) { musicBinder.changeState(); } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } /* * 一首歌曲播放完以后的方法 */ mPlayer.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { musicBinder.nextMusic(); mp.start(); } }); } /* * 接收从activity传过来的数据源及position */ @Override public int onStartCommand(Intent intent, int flags, int startId) { mListData = intent.getParcelableArrayListExtra("musicList"); currentPosition = intent.getIntExtra("currentPosition", 0); initPlayer(); return super.onStartCommand(intent, flags, startId); } /* * 返回一个接口的实例 */ @Override public IBinder onBind(Intent intent) { return musicBinder; } @Override public void onDestroy() { super.onDestroy(); if (mPlayer != null) { mPlayer.stop(); mPlayer.release(); } } /* * 定義的接口 */ public interface MusicBinder { // 得到player的播放状态 public boolean playMusic(); // 点击下一首 public int nextMusic(); // 点击上一首 public int lastMusic(); // 得到当前播放的时间 public int currentTime(); // 得到当前歌曲的总时间 public int TotalTime(); // 当前选中的歌曲播放 public String seekTo(int position); // 得到正在播放歌曲的名字 public String getCurrentTitle(); // 拖动进度条,设置他的播放位置 public void setCurrentTime(int progress); // 改变他的播放状态 public boolean changeState(); } /* * 接口实现类,继承的binder */ public class MusicServiceBinder extends Binder implements MusicBinder { @Override public boolean playMusic() { if (mPlayer.isPlaying()) { mPlayer.pause(); return false; } else { mPlayer.start(); return true; } } @Override public int nextMusic() { if (++currentPosition > mListData.size() - 1) { currentPosition = mListData.size() - 1; } mPlayer.reset(); initPlayer(); sendBroadcast(intent); return currentPosition; } @Override public int lastMusic() { if (--currentPosition < 0) { currentPosition = 0; } mPlayer.reset(); initPlayer(); sendBroadcast(intent); return currentPosition; } @Override public int currentTime() { if (mPlayer != null) { return mPlayer.getCurrentPosition(); } return 0; } @Override public int TotalTime() { if (mPlayer != null) { return mPlayer.getDuration(); } return 0; } @Override public void setCurrentTime(int progress) { if (mPlayer != null) { mPlayer.seekTo(progress); } } @Override public boolean changeState() { if (mPlayer.isPlaying()) { return true; } else { return false; } } @Override public String seekTo(int position) { if (mPlayer != null) { mPlayer.reset(); try { mPlayer.setDataSource(mListData.get(position).getPath()); mPlayer.prepare(); currentPosition = position; mPlayer.start(); return mListData.get(position).getName(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return null; } @Override public String getCurrentTitle() { return mListData.get(currentPosition).getName(); } } }
<span style="font-size:14px;">package com.scxh.android.music; import java.io.File; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Random; import Constance.MusicBean; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.scxh.android.music.adapter.MusicBaseAdapter; import com.scxh.android.music.adapter.MusicPagerAdapter; import com.scxh.android.service.MusicService; import com.scxh.android.service.MusicService.MusicBinder; public class PlayActivity extends Activity implements OnClickListener, OnSeekBarChangeListener { LayoutInflater inflater; ViewPager mPager; int oldPostion = 1;// 记录小圆点 ImageView mDot1, mDot2, mDot3, mListImg; ImageButton mLastBtn, mPlayBtn, mNextBtn, mCollection; SeekBar mSeekBar; TextView mCurrentTxt, mTotalTxt, mTitle; ArrayList<MusicBean> mListData; int selectPosition; File file = new File(Environment.getExternalStorageDirectory() + "/music"); boolean threadFlag = true; Handler mHandler = new Handler(); // 接口对象 MusicBinder mBinder; //建立连接时的两个方法 ServiceConnection sConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mBinder = null; } //建立连接后,能得到onBind中返回的IBinder对象 @Override public void onServiceConnected(ComponentName name, IBinder service) { mBinder = (MusicBinder) service; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.playactivity_layout); initView();// 初始化view receiveData();// listActivity传过来的歌曲数据和当前选中的位置 setPagerItem();// 为ViewPager添加item布局 setPagerListener(); registerListener();// view注册监听 Intent intent = new Intent(this, MusicService.class);<span style="font-family: Arial, Helvetica, sans-serif;"> </span></span>
<span style="font-size:14px;"><span style="white-space: pre;"> </span>intent.putParcelableArrayListExtra("musicList", mListData);</span>
<span style="font-size:14px;"> intent.putExtra("currentPosition", selectPosition); startService(intent);//启动服务 mTitle.setText(mListData.get(selectPosition).getName()); <span style="white-space:pre"> </span>//绑定服务 bindService(intent, sConnection, BIND_AUTO_CREATE); new Thread(new UIThread()).start(); } /* * 接收到listActivity传过来的歌曲数据和当前选中的位置 */ private void receiveData() { Intent intent = getIntent(); mListData = intent.getParcelableArrayListExtra("musicList"); selectPosition = intent.getIntExtra("selectPosition", 0); } private void registerListener() { mLastBtn.setOnClickListener(this); mPlayBtn.setOnClickListener(this); mNextBtn.setOnClickListener(this); mSeekBar.setOnSeekBarChangeListener(this); mListImg.setOnClickListener(this); } private void initView() { inflater = LayoutInflater.from(this); mPager = (ViewPager) findViewById(R.id.pager_music); mDot1 = (ImageView) findViewById(R.id.dot1_img); mDot2 = (ImageView) findViewById(R.id.dot2_img); mDot3 = (ImageView) findViewById(R.id.dot3_img); mListData = new ArrayList<MusicBean>(); mLastBtn = (ImageButton) findViewById(R.id.last_song_btn); mPlayBtn = (ImageButton) findViewById(R.id.palying_btn); mNextBtn = (ImageButton) findViewById(R.id.next_song_btn); mSeekBar = (SeekBar) findViewById(R.id.progressbar); mCurrentTxt = (TextView) findViewById(R.id.current_progress_txt); mTotalTxt = (TextView) findViewById(R.id.total_progress_txt); mListImg = (ImageView) findViewById(R.id.list_img); mCollection = (ImageButton) findViewById(R.id.collection_ibtn); mTitle = (TextView) findViewById(R.id.tile_play_txt); } ImageView img; /* * PagerView添加组件 */ private void setPagerItem() { ArrayList<View> data = new ArrayList<View>(); View item1 = inflater.inflate(R.layout.pager_item1_list_layout, null); MusicBaseAdapter baseAdapter = new MusicBaseAdapter(this); baseAdapter.setData(mListData); final ListView listView = (ListView) item1 .findViewById(R.id.list_item1_pager); listView.setAdapter(baseAdapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { mTitle.setText(mBinder.seekTo(position)); } }); View item2 = inflater.inflate(R.layout.pager_item2_image_layout, null); img = (ImageView) item2.findViewById(R.id.img_music_playing); View item3 = inflater.inflate(R.layout.pager_item3_lyric_layout, null); data.add(item1); data.add(item2); data.add(item3); MusicPagerAdapter adapter = new MusicPagerAdapter(); adapter.setData(data); mPager.setAdapter(adapter); } @SuppressWarnings("deprecation") private void setPagerListener() { final ArrayList<View> dotData = new ArrayList<View>(); dotData.add(mDot1); dotData.add(mDot2); dotData.add(mDot3); mPager.setCurrentItem(1); dotData.get(1).setBackgroundResource(R.drawable.dot_pressed); mPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int arg0) { dotData.get(oldPostion).setBackgroundResource( R.drawable.dot_default); dotData.get(arg0).setBackgroundResource(R.drawable.dot_pressed); oldPostion = arg0; } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } }); } @Override public void onClick(View v) { switch (v.getId()) { //播放/暂停的监听 case R.id.palying_btn: boolean playFlag = mBinder.playMusic(); if (playFlag == true) { mPlayBtn.setBackgroundResource(R.drawable.play_song_selector); } else { mPlayBtn.setBackgroundResource(R.drawable.pause_song_selector); } break; //点击下一首 case R.id.next_song_btn: if (mBinder != null) { int nextPostion = mBinder.nextMusic(); mTitle.setText(mListData.get(nextPostion).getName()); } mPlayBtn.setBackgroundResource(R.drawable.play_song_selector); break; //点击上一首 case R.id.last_song_btn: if (mBinder != null) { int lastPosition = mBinder.lastMusic(); mTitle.setText(mListData.get(lastPosition).getName()); } mPlayBtn.setBackgroundResource(R.drawable.play_song_selector); break; case R.id.list_img: startActivity(new Intent(this, ListActivity.class)); finish(); break; } } @Override protected void onDestroy() { super.onDestroy(); } int mProgress;//记录拖动的进度条进度 @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mSeekBar.setProgress(progress); mProgress = progress; } /* * 刷新界面的(SeekBar 進度及顯示) */ public class UIThread implements Runnable { @Override public void run() { while (threadFlag) { if (mBinder != null) { mHandler.post(new Runnable() { @Override public void run() { int current = mBinder.currentTime(); int total = mBinder.TotalTime(); mSeekBar.setMax(total); mSeekBar.setProgress(current); mCurrentTxt.setText(timeFormat(current)); mTotalTxt.setText(timeFormat(total)); } }); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } /* * 拖動进度条的监听,避免因延迟造成播放卡顿,所以在onStopTrackingTouch方法中将进度传到服务器 */ @Override public void onStopTrackingTouch(SeekBar seekBar) { mBinder.setCurrentTime(mProgress); } private String timeFormat(int time) { SimpleDateFormat df = new SimpleDateFormat("mm:ss"); String timeStr = df.format(new Date(time)); return timeStr; } } </span>