首页 > 代码库 > 服务 Service【经典案例】

服务 Service【经典案例】

2017-1-19

Activity

技术分享
public class MainActivity extends ListActivity {
    private boolean flag;//线程结束条件
    public static final String ACTION_TEST_SERVICE = "com.bqt.service.TEST_SERVICE";
    private MyServiceConnection conn;
    private IBinderInterface mIBinder;//之所以另外定义一个接口IBinderInterface,而不是直接用MyService.MyBinder,是为了使用统一接口访问,达到解耦、隐藏的目的
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i("bqt""onDestroy");
        flag = false; //在onDestroy中把线程的关闭条件设为true,不然会导致内存泄漏**********************************************************************
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        List<String> mData = new ArrayList<String>(Arrays.asList("开启一个线程,执行死循环操作""通过标记位关闭上面开启的所有线程",//
                "通过startService方式(显示)开启服务","高版本中只能采用显示方式stopService""**隐式方式开启或关闭服务都会直接挂掉**",//
                "bindService方式开启服务 ""unbindService方式解除绑定服务",//
                "startService启动服务后再bindService""通过IBinder间接调用服务中的方法"));
        ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mData);
        setListAdapter(mAdapter);
        conn = new MyServiceConnection();
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            flag = true;
            final long time = System.currentTimeMillis();//当前时间的毫秒值
            Toast.makeText(MainActivity.this"一个新的线程已开启……", Toast.LENGTH_SHORT).show();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while (flag) {//这是一个死循环,关闭线程的唯一条件就是flag==false
                        Log.i("bqt"(System.currentTimeMillis() - time) / 1000 + "");//多少秒
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
            break;
        case 1:
            //采用线程执行耗时操作有一个大遗患:当屏幕旋转等原因导致Activity被重建后,开启的那些线程就关不掉了!
            //即使通过点击BACK键销毁Activity(通过日志,Activity可知已回调onDestroy方法)也无法结束正在运行的线程(因为线程的关闭条件为false)
            //只有通过杀后台进程的方式才可以强制结束掉这个线程,这是一个非常严重的内存泄漏情况!
            //(我能想到的、有效的)唯一的解决方法就是:在onDestroy中把线程的关闭条件设为true
            flag = false;
            Toast.makeText(MainActivity.this"所有线程已关闭……", Toast.LENGTH_SHORT).show();
            break;
        case 2://startService方式开启服务
            startService(new Intent(this, MyService.class));
            break;
        case 3://stopService方式显示关闭服务
            stopService(new Intent(this, MyService.class));
            break;
        case 4://隐式开启或关闭服务(直接挂掉)
            startService(new Intent(ACTION_TEST_SERVICE));
            stopService(new Intent(ACTION_TEST_SERVICE));
            break;
        case 5://bindService方式开启服务
            bindService(new Intent(this, MyService.class)connBIND_AUTO_CREATE);
            break;
        case 6:
            unbindService(conn);//多次调用会异常!
            mIBinder = null;//若不把mIBinder置为空,则服务销毁后仍然可以调用服务里的方法,因为内部类的引用还在
            break;
        case 7:
            startService(new Intent(this, MyService.class));
            //使用bindService来绑定一个【已启动】的Service时,系统只是将Service的内部IBinder对象传递给Activity,并不会将Service的生命周期与Activity绑定
            bindService(new Intent(this, MyService.class)connBIND_AUTO_CREATE);//所以,此时调用unBindService方法取消绑定后,Service不会调用onDestroy方法
            break;
        case 8:
            if (mIBinder != null) {
                mIBinder.callMethodInService(100);
            } else {
                Toast.makeText(this"还没有绑定呦……", Toast.LENGTH_SHORT).show();
            }
            break;
        }
    }
    private class MyServiceConnection implements ServiceConnection {//Interface for monitoring监控 the state of an application service
        @Override
        /**此方法中的IBinder即为我们调用bindService方法时Service的onBind方法返回的对象,我们可以在此方法回调后通过这个IBinder与Service进行通信 */
        public void onServiceConnected(ComponentName name, IBinder service) {//访问者与Service连接成功时回调 
            //Called when a connection连接 to the Service has been established确定、已建立, with the IBinder of the communication channel to the Service.
            mIBinder = (IBinderInterface) service;
            Toast.makeText(MainActivity.this"服务已连接……", Toast.LENGTH_SHORT).show();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {//异常终止或者其他原因终止导致Service与访问者断开连接时回调
            Toast.makeText(MainActivity.this"服务已断开连接……", Toast.LENGTH_SHORT).show();
        }
    }
}

Service

public class MyService extends Service {
    @Override
    public void onCreate() {
        Log.i("bqt""MyService-onCreate");
        super.onCreate();
    }
    @Override
    public IBinder onBind(Intent intent) {//如果再次使用bindService绑定Service,系统不会再调用onBind()方法,而是直接把IBinder对象传递给其他后来增加的客户端
        Log.i("bqt""MyService-onBind");
        //当访问者通过bindService方法与Service连接成功后,系统会将此返回的IBinder接口类型对象,
        //通过bindService中的参数ServiceConnection对象的onServiceConnected方法,传递给访问者,访问者通过该对象便可以与Service组件进行通信
        return new MyBinder();
    }
    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
        Log.i("bqt""MyService-onRebind");
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {//客户端每次调用startService方法时都会回调此方法;调用bindService时不会回调此方法
        Log.i("bqt""MyService-onStartCommand--"+flags+"--"+startId);//flags一直为0,startId每次会自动加1
        return super.onStartCommand(intent, flags, startId);
    }
    @Override
    public boolean onUnbind(Intent intent) {//绑定多客户端情况下,需要解除所有的绑定后才会(就会自动)调用onDestoryed方法,除非service也被startService()方法开启
        Log.i("bqt""MyService-onUnbind");
        return super.onUnbind(intent);
    }
    @Override
    public void onDestroy() {
        Log.i("bqt""MyService-onDestroy");
        super.onDestroy();
    }
    //******************************************************************************************
    /**这是服务里面的一个方法,对外是隐藏的,只能通过IBinder间接访问*/
    private void methodInService(int money) {
        Toast.makeText(this"服务里的方法被调用了……"+money, Toast.LENGTH_SHORT).show();
    }
    private class MyBinder extends Binder implements IBinderInterface {//须实现IBinder接口或继承Binder类。对外是隐藏的
        public void callMethodInService(int money) {
            if (money > 0) {
                methodInService(money);//间接调用了服务中的方法
            }
        }
    }
}

中间接口

public interface IBinderInterface {
    public void callMethodInService(int money);
}

清单文件

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.bqt.service"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />
    <permission
        android:name="com.bqt.permission"
        android:protectionLevel="normal" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service
            android:name=".MyService"
            android:permission="com.bqt.permission" >
            <intent-filter>
                <!-- 自定义的Action。服务建议显式开启,所以Action一般是不需要的 -->
                <action android:name="com.bqt.service.TEST_SERVICE" />
            </intent-filter>
        </service>
    </application>
</manifest>

附件列表

     

    服务 Service【经典案例】