android service探究(附:使用服务功能下载文件)

像service一样做后台默默的劳动者,还是如acticity光鲜亮丽走在台前

在android设计中,作为四大组件之一service有着不可替代的功能,可是实际开发项目中使用的并不多,或者说它的作用有些时候被activity,第三方开源支持给弱化了。不管怎么说,基础的使用时我们进化的阶梯,本节来说说service的那些事。

  1. service的启动类型:

启动型

    services : context.startService() --> onCreate() --> onStart() -->      service running --> context.stopService() --> onDestroy() --> Service stop;

方法的调用顺序:

Intent intent = new Intent(this,ServicesClass.class);
//启动服务
StartServices(intent);
|
//进入服务类
|
//当服务没有创建的时候,onCreate()方法进行调用
|
onStartCommand(Intent intent, int flags, int startId)
|
stopService()
|
onDestroy()

绑定型

     services:  context.bindService() --> onCreate() --> onBind() --> service running --> onUnbind() --> onDestroy() --> service stop

方法调用的顺序

private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {//获取service }
        @Override
        public void onServiceDisconnected(ComponentName name) {}
    };

Intent intent = new Intent(this,ServicesClass.class);
//启动并且绑定服务,这里需要一个ServiceConnection参数,所以需要在调用的类中声明
|
bindService(Intent service, ServiceConnection conn,int flags)
|
//如果服务没有被实例化过onCreate()方法进行调用
//此时服务中的该方法启动
public IBinder onBind(Intent intent){return bind}
|
//因为返回的对象为IBinder 所以在service中定义一个类进行继承Binder
|
//可以在个类中定义自己所需要的方法来进行相应的逻辑功能
public class MyBinder extends Binder {
        @Override
        public String getInterfaceDescriptor() {
            return super.getInterfaceDescriptor();
        }
}
|
//在主类中调用里面的方法`conn` 中进行方法强转类型,直接获取Service实例,***表示自己定义的方法,这样就可以与主类进行数据传递,逻辑沟通
|
返回类型声明 = ((ServicesClass.MyBinder)(service)).***;
|
unbindService(ServiceConnection conn)
|
onUnbind(Intent intent)
|
onDestroy() 

2.服务的进阶技巧
使用前台服务:服务几乎都是在后台进行的,一直以来在后台默默工作提供服务,但是服务的系统优先级是比较低,在系统内存紧张时便会回收正在后台运行的服务,当你的app在运行时及时系统内存紧张也不能回收你的服务时便可以使用前台服务

/*启动前台服务的方法两个参数 */
public final void startForeground(int id, Notification notification) {
        try {
            mActivityManager.setServiceForeground(
                 new ComponentName(this, mClassName), mToken, id,
                    notification, true);
        } catch (RemoteException ex) {
        }
    }

在receiver的onCreate()方法中添加如下代码

Intent intent = new Intent(this,MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,intent,0);

Notification notification = new NotificationCompat.Builder(this).setContentTitle("让我偷偷看你").setStyle(new NotificationCompat.BigTextStyle().bigText("头轻轻一抬,望见你的风采,扶流苏的裙摆,脸上挂着粉黛,微微的笑像小孩,站在你家门外,轻轻的把门敲开,害羞的地下脑袋,让我偷偷看你,在你回眸的春风里"))
.setSmallIcon(R.mipmap.ic_launcher)                  .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
.setContentIntent(pendingIntent).setWhen(System.currentTimeMillis()).build();
//启动前台的服务
startForeground(1,notification);

//停止前台服务

stopForeground(true);// 停止前台服务--参数:表示是否移除之前的通

3.关于IntentService

子实践中,服务是在主线程开启的,所以如果服务中有耗时的操作,那么就需要对service开启线程

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    //需要进行开启线程的操作
    new Thread(new Runnable(){
        @Override
        public void run(){
            //处理相应的逻辑内容
                ···//服务中的方法处理完成后,如果牵扯到UI处理,还需要进行处理
            stopSelf();
        }
    }).start();
}

所以,android系统提供另外一种方法IntentService

1.首先是自己定义类继承IntentService
2.创建构造函数,在其内部调用父类的有参构造函数
3.在类中实现onHandleIntent()方法

说白了,跟使用Service类似,因为IntentService继承的父类是Service

4 . 说说AsyncTask的这些事
在android多线程编程中,提供asyncTask方法进行线程的管理。相比起Thread和Handler的使用,asyncTask的使用相对来讲更加简单,我们并不需要知道它内部的实现逻辑,只需要书写我们自己的逻辑方法即可。
先看代码:

public class DownLoadTask extends AsyncTask<String ,Integer,Integer> {
    public DownLoadTask() {}
    /**
     * 在进行doInBackground方法之前进行调用,执行准备工作
     * 属于主线程范畴
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    /**
     * 在doInBackground完成之后进行调用
     * 属于主线程范畴
     * @param integer
     */
    @Override
    protected void onPostExecute(Integer integer) {
        super.onPostExecute(integer);
    }
    /**
     * 更新方法进行进度的提示
     * 属于主线程范畴,这里可以进行UI更新操作
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    /**
     *这个方法用来书写逻辑耗时操作,属于另开子线程的范畴
     * 使用:Thread.currentThread().getId()查看子线程Id
     * @param params
     * @return
     */
    @Override
    protected Integer doInBackground(String... params) {
    return 0;
    }

在使用asyncTask时候,需要实现上述方法来进行逻辑操作,对于AsyncTask<Params, Progress, Result>的参数说明一下:
@params Params:表示传入的参数,在进行异步请求时所需值,并在doInBackground()中进行使用
@params Progress:进度值,在onProgressUpdate()进行使用,主动调用该方法的时候需要在doInBackground()方法中调用publishProgress()方法
@params Result:结果判断值,也就是说当doInBackground()执行完毕之后会主动调用onPostExecute()方法,但是对于耗时的操作中,可能的情况:成功、失败、中断等等,这时的参数便可以作为判断参数进行逻辑处理。

关于方法的调用:

downLoadTask = new DownLoadTask();
downLoadTask.execute("自己定义的参数类型值");

另外补充说明:因为asyncTask中execute()使用的是单一线程池,若你需要好几个asyncTask同时执行,需要使用如下的调用

 /**
         * 参数说明:executeOnExecutor(Executor exec,Params... params)
         *
         * @params exec  引用 java.util.concurrent.Executors包的newCachedThreadPool()方法
         *
         *                另一种方法自己定义线程池:Executor exec = new ThreadPoolExecutor(15, 200, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
         * 效果允许在同一时刻有15个任务正在执行,并且最多能够存储200个任务。
         *
         * @params params 同execute()中的方法
         */
downLoadTask.executeOnExecutor(java.util.concurrent.Executors.newCachedThreadPool(),downloadUrl);

方法来进行启动。

最后:在这里附加一段代码,来查询你的服务是否开启

//代码有点问题,先放着,后面找找在来改进
public static boolean isServiceExisted(Context context,String className){

        ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);

        List<ActivityManager.RunningServiceInfo> serviceInfoList = activityManager.getRunningServices(Integer.MAX_VALUE);

        if (!(serviceInfoList.size()>0)){

            return false;
        }
        for (int i = 0; i<serviceInfoList.size();i++){

            ActivityManager.RunningServiceInfo serviceInfo = serviceInfoList.get(i);

            ComponentName componentName = serviceInfo.service;

            System.out.println("componentName.getClassName()--------------->"+componentName.getClassName());

            if (componentName.getClassName().equals(className)){

                return true;
            }else{

                return false;
            }

        }
        return false;
    }

关于使用服务下载文件的源码地址,请在个人github平台进行下载
https://github.com/wedfrendwang/Service.git

猜猜这句歌词是哪首民谣 —-春风又吹红了花蕊,你也已经添了新岁。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值