Android学习之服务

举报
ReCclay 发表于 2022/02/22 00:41:08 2022/02/22
【摘要】 完整测试代码,上Github<传送门> 快速查阅 STEP1: 创建好自己的Service文件,并让它继承Service,然后加上onBind函数 public class Serv...

完整测试代码,上Github<传送门>


快速查阅

STEP1: 创建好自己的Service文件,并让它继承Service,然后加上onBind函数

public class ServiceTest extends Service {
    ...

    /*onBlind这个方法其实就是用于和Activity建立关联的*/
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    ...
}

STEP2: 在主活动启动后台服务

通常在onStart函数中进行!

/** 当活动即将可见时调用 */
@Override
protected void onStart() 
{
    Intent startIntent = new Intent(getApplicationContext(), ServiceTest.class);  
    startService(startIntent); //启动后台服务 

    ...
    super.onStart();
}

STEP3:在注册文件中注册服务

<service android:name=".ServiceMqtt" >  
</service>

详细解读

1、自己建的服务,先继承Service,然后加上onBindonBind 这个函数是创建一个Service必须要有的。

![这里写图片描述](https://img-blog.csdn.net/20180809190402392?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1JlQ2NsYXk=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
public class MyService extends Service {
    ...

    /*onBlind这个方法其实就是用于和Activity建立关联的*/
    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    ...
}

2、还有记得在总的注册文件中(AndroidManifest.xml)进行注册Service,如果和主活动在一个包下,可以直接.×××,譬如 下面的.MyService

<service android:name=".MyService" >
</service>

3、Stop Service按钮只会让Service停止,点击Unbind Service按钮只会让ServiceActivity解除关联,一个Service必须要在既没有和任何Activity关联又处于停止状态的时候才会被销毁。

4、Thread是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。
每一个进程有好多线程,而必有一个主线程。

Service是运行在主线程里的,也就是说如果你在Service里编写了非常耗时的代码,程序必定会出现ANR的。

正确食用方法,在Service建立线程,进行耗时的操作。

/*标准Service写法*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            // 开始执行后台任务
        }
    }).start();
    return super.onStartCommand(intent, flags, startId);
}

7、想要让Activity与Service之间建立关联,需要调用bindService()方法,并将Intent作为参数传递进去,在Intent里指定好要绑定的Service

Intent bindIntent = new Intent(this, MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);

6、关于Service郭神两段精妙的话!

Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。


你可能又会问,前面不是刚刚验证过Service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。


既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。

8、防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息

/*前台Service的写法*/
@Override
public void onCreate() {
    super.onCreate();

    showNotification(getApplicationContext());//文本通知
    //showNotificationProgress(getApplicationContext());//带进度条的通知
    Log.e(TAG, "onCreate() executed");
}

通知的具体实现,可参考这里


贴上自己的两段实验程序:

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private Button startService;
    private Button stopService;

    private Button bindService;
    private Button unbindService;

    private MyService.MyBinder myBinder;

    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (MyService.MyBinder) service;//向下转型,实现在Activity中根据具体的场景来调用MyBinder中的任何public方法
            myBinder.startDownload();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        startService = (Button) findViewById(R.id.start_service);
        stopService = (Button) findViewById(R.id.stop_service);
        bindService = (Button) findViewById(R.id.bind_service);
        unbindService = (Button) findViewById(R.id.unbind_service);
        startService.setOnClickListener(startServiceListener);
        stopService.setOnClickListener(stopServiceListener);
        bindService.setOnClickListener(bindServiceListener);
        unbindService.setOnClickListener(unbindServiceListener);

        Log.e("MyService", "MainActivity thread id is " + Thread.currentThread().getId());//打印线程id

    }


    private View.OnClickListener startServiceListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent startIntent = new Intent(MainActivity.this, MyService.class);
            startService(startIntent);//onCreate()和onStartCommand()方法都会执行。
        }
    };

    private View.OnClickListener stopServiceListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.e(TAG, "click stop");
            Intent stopIntent = new Intent(MainActivity.this, MyService.class);
            stopService(stopIntent);
        }
    };

    private View.OnClickListener bindServiceListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent bindIntent = new Intent(MainActivity.this, MyService.class);
            bindService(bindIntent, connection, BIND_AUTO_CREATE);//onCreate()方法得到执行,但onStartCommand()方法不会执行。
        }
    };

    private View.OnClickListener unbindServiceListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Log.e(TAG, "click unbind" );
            unbindService(connection);
        }
    };

}

MyService.java

public class MyService extends Service {

    private static final String TAG = "MyService";
    private MyBinder mBinder = new MyBinder();

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

//    @Override
//    public void onCreate() {
//
//        Log.e("MyService", "MyService thread id is " + Thread.currentThread().getId());//打印线程id
//
//        super.onCreate();
//        Log.e(TAG, "onCreate() executed");
//    }

    /*前台Service的写法*/
    @Override
    public void onCreate() {
        super.onCreate();

        //showNotification(getApplicationContext());//文本通知
        //showNotificationProgress(getApplicationContext());//带进度条的通知
        Log.e(TAG, "onCreate() executed");
    }

    /*标准Service写法*/
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 开始执行后台任务
            }
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestroy() executed");
    }

    class MyBinder extends Binder {

        public void startDownload() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Log.e("TAG", "startDownload() executed");
                    // 执行具体的下载任务
                }
            }).start();
        }
    }

    /**
     * 显示一个普通的通知
     *
     * @param context 上下文
     */
    public static void showNotification(Context context) {
        Notification notification = new NotificationCompat.Builder(context)
                /**设置通知左边的大图标**/
                .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
                /**设置通知右边的小图标**/
                .setSmallIcon(R.mipmap.ic_launcher)
                /**通知首次出现在通知栏,带上升动画效果的**/
                .setTicker("通知来了")
                /**设置通知的标题**/
                .setContentTitle("这是一个通知的标题")
                /**设置通知的内容**/
                .setContentText("这是一个通知的内容这是一个通知的内容")
                /**通知产生的时间,会在通知信息里显示**/
                .setWhen(System.currentTimeMillis())
                /**设置该通知优先级**/
                .setPriority(Notification.PRIORITY_DEFAULT)
                /**设置这个标志当用户单击面板就可以让通知将自动取消**/
                .setAutoCancel(true)
                /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/
                .setOngoing(false)
                /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/
                .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
                .setContentIntent(PendingIntent.getActivity(context, 1, new Intent(context, MainActivity.class), PendingIntent.FLAG_CANCEL_CURRENT))
                .build();
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        /**发起通知**/
        notificationManager.notify(0, notification);
    }

    /**
     * 显示一个下载带进度条的通知
     *
     * @param context 上下文
     */
    public static void showNotificationProgress(Context context) {
        //进度条通知
        final NotificationCompat.Builder builderProgress = new NotificationCompat.Builder(context);
        builderProgress.setContentTitle("下载中");
        builderProgress.setSmallIcon(R.mipmap.ic_launcher);
        builderProgress.setTicker("进度条通知");
        builderProgress.setProgress(100, 0, false);
        final Notification notification = builderProgress.build();
        final NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
        //发送一个通知
        notificationManager.notify(2, notification);
        /**创建一个计时器,模拟下载进度**/
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            int progress = 0;

            @Override
            public void run() {
                Log.i("progress", progress + "");
                while (progress <= 100) {
                    progress++;
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    //更新进度条
                    builderProgress.setProgress(100, progress, false);
                    //再次通知
                    notificationManager.notify(2, builderProgress.build());
                }
                //计时器退出
                this.cancel();
                //进度条退出
                notificationManager.cancel(2);
                return;//结束方法
            }
        }, 0);
    }

}

学习郭神的文章总结:
https://blog.csdn.net/guolin_blog/article/details/11952435(上)
https://blog.csdn.net/guolin_blog/article/details/9797169(下)
<下>还没看,主要是应用在应用程序之间,用到再来研究!

文章来源: recclay.blog.csdn.net,作者:ReCclay,版权归原作者所有,如需转载,请联系作者。

原文链接:recclay.blog.csdn.net/article/details/81542561

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。