Server笔记

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

调用的位置

@Override
public void onCreate() {
    startTimer();
    Log.e("showme","onCreate");
    super.onCreate();
}
@Override
public 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: 1
12-25 16:39:34.246 20674-28409/com.example.administrator.servicedemo I/System.out: 2
12-25 16:39:35.247 20674-28409/com.example.administrator.servicedemo I/System.out: 3
12-25 16:39:36.246 20674-28409/com.example.administrator.servicedemo I/System.out: 4
12-25 16:39:37.246 20674-28409/com.example.administrator.servicedemo I/System.out: 5
12-25 16:39:38.246 20674-28409/com.example.administrator.servicedemo I/System.out: 6
12-25 16:39:39.246 20674-28409/com.example.administrator.servicedemo I/System.out: 7
12-25 16:39:40.246 20674-28409/com.example.administrator.servicedemo I/System.out: 8
12-25 16:39:41.246 20674-28409/com.example.administrator.servicedemo I/System.out: 9
12-25 16:39:42.247 20674-28409/com.example.administrator.servicedemo I/System.out: 10

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

Service和Activity的交互

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

@Override
public 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 statements

interface 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了

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

@Override
protected 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值