Server笔记

来源:互联网 发布:梅宏 大数据系统软件 编辑:程序博客网 时间:2024/06/17 18:43

Service笔记

作为Android的四大控件的之一,是每个Android开发者都需要了解的控件,因此特意在这里写下自己的学习笔记。

博客地址 http://blog.csdn.net/sinat_17314503/article/details/53871294

Service是什么,可以干什么

大家都知道Activity是负责前台显示的而Service却恰好相反在后台显示并没有什么界面。例如舞台上的表演,表演者在舞台上表演而幕后工作者,在舞台后面给表演者调灯光、音乐等等。在这里表演者相当于Activity,因为显示在前面观众,观众可以直观的看到,但是幕后工作者观众是看不到的,Service就类似于幕后工作者。既然我们知道Service类似于幕后工作者那么它的能力可以干什么,聪明的你就可以猜出一二分。没错,就是在不阻碍前台的显示的前提下,在后台计算辅助前台更好的显示,还有可以是后台人员发微博,与其他人互动并不一定要一直依附在前台。

Service如何建立和运行

其实Service的建立是十分简单的,只要新建一个类继承Service就好了。
基本上继承以下的方法就可以了

然后在Activity里面点击事件里面写上

Intent i = new Intent(this, EchoService.class);startService(i);

就可以启动了一个后台Service了,但是但是千万不要忘记在注册表里面注册这个Service

   <application      ...>       ...        <service android:name=".EchoService"/>    </application>

当然又开始就有停止 停止Service的方法

stopService(i);

但是上述的代码并没有运行什么东西。于是我就加一点东西,在后台运行一个计时器,代码如下:

private Timer timer=null;    private TimerTask task=null;    private int i = 0;    public void startTimer(){        if(timer==null){            timer = new Timer();            task = new TimerTask() {                @Override                public void run() {                //---------------------------                //这里注意 现在这个Service没有和前台绑定                //这里可以先注释掉 下面会说Activity和                //Service互动                    echoServiceBind.setData(i);                    i++;                    if(mDataListener!=null){                        mDataListener.Show(i);                    }                //---------------------------                    System.out.println(i);                }            };            timer.schedule(task, 1000,1000);        }    }    public void stopTmer(){        if(timer!=null){            task.cancel();            timer.cancel();            task=null;            timer=null;        }    }

调用的位置

@Overridepublic void onCreate() {    startTimer();    Log.e("showme","onCreate");    super.onCreate();}@Overridepublic void onDestroy() {    stopTmer();    Log.e("showme","onDestroy");    super.onDestroy();}

运行后你就会发现Logcat在不断打断的打印:

12-25 16:39:33.249 20674-28409/com.example.administrator.servicedemo I/System.out: 112-25 16:39:34.246 20674-28409/com.example.administrator.servicedemo I/System.out: 212-25 16:39:35.247 20674-28409/com.example.administrator.servicedemo I/System.out: 312-25 16:39:36.246 20674-28409/com.example.administrator.servicedemo I/System.out: 412-25 16:39:37.246 20674-28409/com.example.administrator.servicedemo I/System.out: 512-25 16:39:38.246 20674-28409/com.example.administrator.servicedemo I/System.out: 612-25 16:39:39.246 20674-28409/com.example.administrator.servicedemo I/System.out: 712-25 16:39:40.246 20674-28409/com.example.administrator.servicedemo I/System.out: 812-25 16:39:41.246 20674-28409/com.example.administrator.servicedemo I/System.out: 912-25 16:39:42.247 20674-28409/com.example.administrator.servicedemo I/System.out: 10

然后你按home键返回桌面它还是会继续运行,这就是Service。在后台默默的运行。

Service和Activity的交互

到这个时候你会说:这样有卵用啊,Service运行之后和Activity都没有交互。
上面我不是继承了4个方法吗,那么剩下两个就是和Activity的交互有关系的。猜得不错,但是真正有关系的只有

@Overridepublic IBinder onBind(Intent intent) {    Log.e("showme","onBind");    return echoServiceBind;}

看它的返回值就知道(IBinder是关于信息底层传递,现在我不懂,不要问我,你只要知道它可以传递数据就可以了)我们需要IBinder对象,现在的状况是 我没有这个对象啊。身为(面向对象的)程序员,当听到没有没有对象那怎么办,那就new啊。没有对象就new一个出来啊。

于是就有下面这个类

public final EchoServiceBind echoServiceBind = new EchoServiceBind();public class EchoServiceBind extends Binder{    private int data = 0;    public EchoService getService(){        return EchoService.this;    }    public int getData() {        return data;    }    public void setData(int data) {        this.data = data;    }}

然后返回就可以了。

Service那里解决了那么Activity那里怎么办呢。欲知后事如何,且听下会分解。我好想这样说的,越写越多字。

那么我们需要在Activity里面继承ServiceConnection类重写

private EchoService.EchoServiceBind mBind;private EchoService echoService = null;    @Override    public void onServiceConnected(ComponentName name, IBinder binder) {        Log.e("showme","onServiceConnected");        mBind = (EchoService.EchoServiceBind) binder;        echoService = ((EchoService.EchoServiceBind) binder).getService();        echoService.addDataListener(new EchoService.DataListener() {            @Override            public void Show(int t) {                Message message = mHandler.obtainMessage();                message.arg1 = t;                mHandler.sendMessage(message);            }        });    }    @Override    public void onServiceDisconnected(ComponentName name) {        Log.e("showme","onServiceDisconnected");    }

通过

echoService = ((EchoService.EchoServiceBind) binder).getService();mBind = (EchoService.EchoServiceBind) binder;

我们可以获取到EchoService本体 和 EchoService.EchoServiceBind内部类的本体。

于是我们就可以愉快的调用本体里,但是这里我会告诉你,你都没有绑定,你调用什么。

先说一下这两个方法的作用onServiceConnected是当Service和Activity绑定成功之后会调用的而onServiceDisconnected只有在Service发生异常的情况下断掉连接的时候调用。

现在说一下如何绑定Service和Activity。

bindService(i, this, Context.BIND_AUTO_CREATE);

讲完了是不是很快,对就是这么简单就可以绑定Activity和Service。

bindService()方法接收三个参数,第一个参数就是刚刚构建出的Intent对象,第二个参数是前面创建出的ServiceConnection的实例,第三个参数是一个标志位,这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service。

于是我们可以愉快的调用EchoService本体和EchoServiceBind本体的方法了。

注意

bindService Service中的onCreate()方法得到执行,但onStartCommand()方法不会执行当Startservice和bindService都运行了需要stopService和  unbindService(this);都运行了对应的关闭了Service才停下来。

Service是否可以进行耗时操作

很遗憾的告诉你,不行,因为Service也是运行在UI线程,超过3秒之后就会ANR。那么有什么方法可以让它进行耗时操作,在Service里面开启一个线程进行耗时操作,或者为其开启一个进程

    <!--普通的Service转换成远程Service其实非常简单,只需要在注册Service的时候将它的android:process属性指定成:remote就可以-->    <!--使用了远程Service后,MyService已经在另外一个进程当中运行了,所以只会阻塞该进程中的主线程,并不会影响到当前的应用程序。-->    <service android:name=".MyService2"             android:process=":remote"/>

但是有会面临一个问题,卧槽那我怎么和Activity进行交互啊。这就要使用AIDL来进行跨进程通信了(IPC)。

在AS里面步骤

aidl的文件代码如下

package com.example.administrator.servicedemo2;// Declare any non-default types here with import statementsinterface IMyAidlInterface {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);                 int plus(int a, int b);                        String toUpperCase(String str);}

调用

/** * 想和Activity進行交互 这就要使用AIDL来进行跨进程通信了(IPC) * AIDL(Android Interface Definition Language)是Android接口定义语言的意思, * 它可以用于让某个Service与多个应用程序组件之间进行跨进程通信, * 从而可以实现多个应用程序共享同一个Service的功能。 */public class MyService2 extends Service{    public static final String TAG = "MyService";    @Nullable    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG,"onStartCommand() executed");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onCreate() {        super.onCreate();        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            e.printStackTrace();        }        Log.e(TAG,"MyService2  onStartCommand() executed");        Log.e("ThreadID","Service="+Thread.currentThread().getId());        Log.d("TAG", "process id is " + Process.myPid());    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e(TAG,"onDestroy() executed");    }    public IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {        @Override        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {        }        @Override        public int plus(int a, int b) throws RemoteException {            return a+b;        }        @Override        public String toUpperCase(String str) throws RemoteException {            if(str!=null){                return str.toUpperCase();            }            return null;        }    };}

上面的代码做了以下的步骤 一.初始化IMyAidlInterface.Stub 二.将其返回给Activity

Activity调用

 private ServiceConnection mConnection2 = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            myBinder2 = IMyAidlInterface.Stub.asInterface(iBinder);            try {                int a = myBinder2.plus(10,15);                String b = myBinder2.toUpperCase("abc");                Toast.makeText(MainActivity.this,b+"顯示一下"+a,Toast.LENGTH_SHORT).show();            } catch (RemoteException e) {                e.printStackTrace();            }        }        //        只有在service因异常而断开连接的时候,这个方法才会用到。        @Override        public void onServiceDisconnected(ComponentName componentName) {            Log.e("showme","onServiceDisconnected excuted");        }    };

上面的代码做了以下的步骤 一.获取IMyAidlInterface.Stub 二.调用里面的方法.

IntentService的使用

原来还有一种方法在Service建线程,我还是太年轻了。在Service里面我们肯定不能直接进行耗时操作,一般都需要去开启子线程去做一些事情,自己去管理Service的生命周期以及子线程并非是个优雅的做法;好在Android给我们提供了一个类,叫做IntentService

使用了IntentService最起码有两个好处,一方面不需要自己去new Thread了;另一方面不需要考虑在什么时候关闭该Service了

使用这个方法我们需要重写

@Overrideprotected void onHandleIntent(Intent intent) {}

在这里面实现你的逻辑然后和Activity的交互可以选择用广播来实现。这个没什么好说的。

参考http://blog.csdn.net/lmj623565791/article/details/47143563

好了需要将的都讲完了。最后 纸上得来终觉浅,绝知此事要躬行

参考 http://blog.csdn.net/guolin_blog/article/details/9797169
http://blog.csdn.net/guolin_blog/article/details/11952435

0 0
原创粉丝点击