android Service学习

菜鸟笔记,高手绕过。android

文章内容列表:git

1.分别经过startService和bindService的方式启动服务,比较二者不一样,及在此期间发现的问题。github

2.研究IntentService的 使用。app


public class MyActivity extends Activity {
    
private String TAG="TAG";less

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

ide

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

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

}

例子中有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 {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;


    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }


        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }


    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }


    /**
     * Sets intent redelivery preferences.  Usually called from the constructor
     * with your preferred semantics.
     *
     * <p>If enabled is true,
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_REDELIVER_INTENT}, so if this process dies before
     * {@link #onHandleIntent(Intent)} returns, the process will be restarted
     * and the intent redelivered.  If multiple Intents have been sent, only
     * the most recent one is guaranteed to be redelivered.
     *
     * <p>If enabled is false (the default),
     * {@link #onStartCommand(Intent, int, int)} will return
     * {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
     * dies along with it.
     */
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }


    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.


        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();


        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }


    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }


    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }


    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }


    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null. 
     * @see android.app.Service#onBind
     */
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    protected abstract void onHandleIntent(Intent intent);

}

从源码中能够看出,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

相关文章
相关标签/搜索