菜鸟笔记,高手绕过。
文章内容列表:
1.分别通过startService和bindService的方式启动服务,比较两者不同,及在此期间发现的问题。
2.研究IntentService的 使用。
public class MyActivity extends Activity {
private String TAG="TAG";
Button startButton,stopButton,startIntentServiceButton,stopIntentServiceButton,jumpButton;
ServiceConnection mServiceConnection;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
startButton= (Button) findViewById(R.id.button);
stopButton= (Button) findViewById(R.id.button2);
startIntentServiceButton= (Button) findViewById(R.id.intentService_button);
stopIntentServiceButton= (Button) findViewById(R.id.stop_intentService);
jumpButton= (Button) findViewById(R.id.jump_button);
jumpButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent intent=new Intent(MyActivity.this,SecondActivity.class);
// startActivity(intent);
MyActivity.this.finish();
//android.os.Process.killProcess(android.os.Process.myPid());
}
});
startIntentServiceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG,"startIntentServiceButton is pressed");
MyIntentService myIntentService=new MyIntentService("myIntentService");
Intent intent=new Intent(MyActivity.this,MyIntentService.class);
startService(intent);
// bindService(intent,mServiceConnection,Context.BIND_AUTO_CREATE);
}
});
stopIntentServiceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MyActivity.this,MyIntentService.class);
stopService(intent);
/**
* 当调用stopService方法时,service的onDestroy方法会立即被调用,但是服务里面新开的线程还在跑,直到跑完。
*/
// unbindService(mServiceConnection);
}
});
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.v(TAG, "BUTTON IS CLICKED");
// startService(intent);
/**
* IntentService的启动方式跟service的启动方式是一样的,但他自己管理自己的service,此处调用了startService方式后,会调用onHandleIntent方法
* onHandleIntent-->onDestroy.
* 也就是说IntentService自己处理完onHandleIntent方法后,就会自己结束自己。大无畏的精神啊,然后就调用onDestroy了。
*/
Intent intent = new Intent(MyActivity.this, MyService.class);
IntentService intentService;
Handler handler;
bindService(intent,mServiceConnection, Context.BIND_AUTO_CREATE);
// startService(intent);
/***
* 调用startService之后,service调用onCreate 和onStartCommand方法,通过该方法启动的service会一直在运行,即使他的调用方已经结束了。
*所以如果使用这种方式启动,If you implement this, it is your responsibility to stop the service
/***
* 调用bindService要传进去一个ServiceConnection 参数,bindService方法调用后会调用onCreate ,onBind方法,和onServiceConnected方法
* 调用次序是onCreate--->onBind----->onServiceConnected
* 通过该Binder可以实现Service和调用方的通信。
*/
/***
* 不管是startService还是bindService方式启动的服务。从启动服务的activity跳转到另一个activity,
* 该服务也还会继续跑。
* 但是两者的不同是:
* 当启动服务的activity destroy掉不会影响startService方式启动的service即使没有调用stopService,也不会有影响
* 但通过bindService启动的服务如果此时没有主动调用unBindService,然后就调用启动他的activity的finish方法,此时,该activity的
* onDestroy方法不会被调用,可能是因为资源没有释放的原因吧。如果此时你将你的程序按多任务键将其从历史任务中划掉,此时会调用onDestroy方法
* 当然也会报内存泄露的错误,因为之前没有调onDestroy方法就是因为资源没有释放,当然是猜测了。
* 但还有一种情况,如果你通过android.os.Process.killProcess(android.os.Process.myPid());
* 将程序杀死的话就不会报内存泄露的错误,也许该方法本身会帮你做些处理吧,但是activity的onDestroy方法依然不会被调用。
* 也就是说bindService方式启动的service是依附于启动他的activity的。
*/
Context context;
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MyActivity.this,MyService.class);
unbindService(mServiceConnection);
// stopService(intent);
}
});
mServiceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder myBinder= (MyService.MyBinder) service;
int count=myBinder.getCount();
Log.v(TAG,"COUNT IS "+count);
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v(TAG,"!!1--onServiceDisconnected");
}
};
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.v(TAG,"---onDestroy");
}
}
MyService类:
public class MyService extends Service {
private static String TAG="TAG";
MyBinder myBinder=new MyBinder();
int count=0;
public MyService() {
}
/***
*
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.v(TAG,"ONBIND");
return myBinder;
}
class MyBinder extends Binder{
public int getCount(){
return count;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG,"SERVICE ONSTARTCOMMAND");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v(TAG,"service onDestroy");
}
@Override
public void onCreate() {
super.onCreate();
Log.v(TAG,"SERVICE ONCREATE");
}
}
MyIntentService类:
public class MyIntentService extends IntentService {
private static String TAG="TAG";
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super("MyIntentService");
}
public MyIntentService(){
super("MyIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.v(TAG,"onHandleIntent");
/*long futrueTime=System.currentTimeMillis()+5000;
//执行5s钟。
while (System.currentTimeMillis()<futrueTime) {
Log.v(TAG, "ONHANDLEINTENT");
synchronized (this) {
try {
Log.v(TAG,"WAIT");
wait(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}*/
for (int i=0;i<15;i++){
Log.v(TAG,"ONHandleThread "+i);
try {
Log.v(TAG,"CurrentThread id is "+Thread.currentThread().getName());
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG,"----onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
Log.v(TAG,"----onCreate");
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.v(TAG,"----INTENTSERVICE ONSTART");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v(TAG,"===onDestroy");
}
}
例子中有5个按钮,startButton和stopButton测试startService和bindService,startIntentService和stopIntentService测试IntentService.jumpButton来结束启动服务的activity.具体说明例子中有注释。
1.1通过startService方法启动的服务跟启动方没有关系,即使启动方destroy了,服务依然跑。
1.2但通过bindService启动的服务,必须在activity 调用destroy之前释放资源,unBindService,不然会造成资源泄露。
1.3像上面例子中bindService之后,如果按停止按钮去unBindService,直接按jumpButton去结束当前activity,你会发现当前activity的onDestroy方法并没有被调到。此处注意下。
1.4此时从后台任务里将应用划掉会报内存泄露的错误。如果用android.os.Process.killProcess(android.os.Process.myPid());去结束掉整个应用,你会发现不会报内存泄露的错误,即使没有调用unBindService方法。
2.IntentService是Service的子类,也需要在manifest里面进行注册,其中要注意MyIntentService必须要有一个空的构造函数,如代码中实现,否则注册会编译不过。
3.普通Service类是运行在主线程里的,要进行耗时操作需要自己新开线程,但IntentService可以进行耗时操作,直接在onHandleIntent方法里进行耗时操作就好。耗时操作完成后自动调用onDestroy方法,这一点注意,如果在进行耗时操作时你显式调用stopService的方式结束IntentService,这时IntentService的onDestroy方法会立即被调用,但耗时操作还是会继续执行,直到执行结束。这一点的原理可以从IntentService的源码中看出:
public abstract class IntentService extends Service {
}
从源码中可以看出,IntentService内部新开启了一个IntentThread的线程来处理耗时操作。当我们通过startService的方式启动IntentService时,会调用其的onStart和onStartCommand方法,这两个方法里面会去将你启动IntentService时所用的Intent传给Message的obj参数,然后将其发送给其内部的handler,在handler的handleMessage方法里面就去调用handleIntent方法了,这就是为什么我们启动服务后IntentService就会去调用onHandleIntent方法的原因了。同时我们发现在handleMessage方法里面onHandleIntent方法结束完之后,intentService就会调用stopSelf方法结束自己。IntentService的源码还是非常简单的,相信大家都能看懂,记录仅为后来复习所用。若有错误,欢迎拍砖。代码下载地址:https://github.com/happycodinggirl/AndroidLearningProcess.git