Android第一行代码 Day10 笔记

10. 服务

10.1 Service概述

Service能够在后台长时间运行,组件能够绑定到Service并与之交互,甚至执行进程间通信(IPC)。Service能够在后台处理网络事务、播放音乐、执行文件操作或者Content Provider通信。

10.2 Android多线程

10.2.1 线程的基本用法

Android多线程基本用法与Java中多线程基本一致
详细可以参考 Java多线程基础 这里不做赘述

10.2.2 子线程中更新UI

Android中的UI线程不安全,所以不能在子线程中做更新UI操作
所以就用到异步消息处理机制Handler

  • Handler类:用于发送消息和处理消息,使用sendMessage()发送消息,重写handleMessage()用来处理消息

  • Message 类:用于在线程之间传递消息,在内部携带少量的信息,在不同线程间交换数据
    使用what字段设置消息类型
    arg1,arg2这两个字段携带一些整形数据
    obj字段携带一个Object对象

  • MessageQueue:消息队列,用于存放所有通过Handler发送的消息,每个线程只有一个MessageQueue

  • Looper:循环的在MessageQueue中取消息,根据消息发送过来的时间决定消息取出的先后,每个线程只有一个Looper对象

代码示例:

子线程发送消息切换到主线程
    //在主活动中定义Handler,在按钮的点击事件中开启一个线程处理具体逻辑,此时由主线程切换到子线程。当想要更新UI时,发送消息,主线程接收到消息进行处理,此时由子线程切换到主线程进行UI操作
public class MainActivity extends AppCompatActivity {

    private static final int COMPLETE = 0;
    private TextView textView;
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button btn = (Button)findViewById(R.id.btn);
        textView = (TextView)findViewById(R.id.text_view);

        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG,"btn_click");

                //在子线程中如果想更新ui,利用Message发送消息,并且可以携带数据
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Log.d(TAG,"change_ui");
						//对消息对象进行复用
                        Message msg = Message.obtain();
                        msg.what = COMPLETE;
                        msg.arg1 = 1;
                        handler.sendMessage(msg);

                    }
                }).start();
            }
        });


    }


    private final Handler handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            Log.d(TAG,"change_complete");

            switch (msg.what){
                case COMPLETE:
                    Log.d(TAG,"arg1:"+msg.arg1);
                    textView.setText("complete"+msg.arg1);
                    break;
                default:
                    break;
            }
        }
    };
}


在这里插入图片描述
可以看到是从子线程切换到主线程的

主线程发送消息切换到子线程
public class SecondActivity extends AppCompatActivity {
    private static final int COMPLETE = 0;
    private static final int TRANSPORT = 1;
    private TextView textView;
    private static final String TAG = "SecondActivity";
    private HandlerThread childHandlerThread;
    private Handler childHandler;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);


        Button btn = (Button)findViewById(R.id.btn);
        textView = (TextView)findViewById(R.id.text_view);


        childHandlerThread = new HandlerThread("thread0");
        childHandlerThread.start();

        childHandler = new Handler(childHandlerThread.getLooper()){
            @Override
            public void handleMessage(@NonNull Message msg) {
                switch (msg.what){
                    case COMPLETE:
                        Log.d(TAG,"complete");
                        break;
                    case TRANSPORT:
                        Log.d(TAG,""+msg.obj);
                    default:
                        break;
                }
            }
        };


        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                Log.d(TAG,"update UI");
                Message msg = Message.obtain();

                msg.what = TRANSPORT;
                msg.obj = "start";
                childHandler.sendMessage(msg);

                Message msg2 = Message.obtain();
                msg2.what = COMPLETE;
                //延迟3秒发送消息
                childHandler.sendMessageDelayed(msg2,3000L);

            }
        });

    }
}

在这里插入图片描述
可以看到是从主线程切换到子线程的

10.2.3 使用AsyncTask

使用AsyncTask流程:

  • 自定义类继承自AsyncTask,并指定3个泛型参数

    • Params:执行AsyncTask时需要传入的参数,用于在后台任务中使用
    • Progress:后台执行时,使用这里指定的泛型作为进度单位
    • Result:当任务执行完毕后,使用这里指定的泛型作为返回值类型
  • 需要重写的方法:

    • onPreExecute(): 在后台任务开始执行前调用,用于界面的初始化,例如显示一个进度条对话框
    • doInBackground(Void… voids):后台任务 在子线程中运行,处理耗时任务,这个方法中不能进行UI操作
      如果需要更新UI,需要调用publishProgress()方法
    • onProgressUpdate(Integer… values):在后台任务中调用了publishProgress()方法,该方法就会被调用,可以对UI进行操作,利用参数中的数值就可以对界面进行更新
    • onPostExecute(Boolean aBoolean):当后台任务执行完并通过return返回时,该方法会被调用。返回的数据作为参数传递到该方法中可以利用返回的数据进行UI操作

代码示例:

public class DownloadTask extends AsyncTask<Void,Integer,Boolean> {
    /**
     * 后台任务
     * 在子线程中运行,处理耗时任务,这个方法中不能进行UI操作
     * 如果需要更新UI,需要调用publishProgress()方法
     * @param voids
     * @return
     */
    @Override
    protected Boolean doInBackground(Void... voids) {

        return null;
    }

    /**
     * 在后台任务开始执行前调用,用于界面的初始化,例如显示一个进度条对话框
     */
    @Override
    protected void onPreExecute() {

    }

    /**
     * 当后台任务执行完并通过return返回时,该方法会被调用。返回的数据作为参数传递到该方法中
     * 可以利用返回的数据进行UI操作
     * @param aBoolean
     */
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
    }


    /**
     * 在后台任务中调用了publishProgress()方法,该方法就会被调用,可以对UI进行操作,利用参数中的数值就可以对界面进行更新
     * @param values
     */
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }
}

//在主活动中启动任务
new DownloadTask().execute()

10.3 Service的基本用法

10.3.1 定义一个服务

服务的基本用法:
如果手动创建Service需要去Manifest文件中注册
定义一个服务:在所在包下右键New->Service->Service并重写常用的4个方法

  • onBind(Intent intent):绑定服务时使用
  • onCreate():在服务创建的时候调用
  • onStartCommand(Intent intent, int flags, int startId):在每次服务启动的时候调用
  • onDestroy():在服务销毁的时候调用

代码示例:

  • 手动定义一个MyService类并继承于Service
public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

  • 在Manifest文件中注册service
       <service android:name=".MyService"
            android:enabled="true"
            android:exported="true"/>

如果是AS自动创建,则只需要重写方法,不用注册service

10.3.2 启动和停止服务

  • 启动服务:
   Intent startIntent = new Intent(MainActivity.this,MyService.class);
   startService(startIntent);
  • 停止服务:
 Intent stopIntent = new Intent(MainActivity.this,MyService.class);
 stopService(stopIntent);

让服务自己停下来:在服务类中任何一个地方调用 stopSelf()方法就可以停止服务

10.3.3 活动和服务进行通信

流程:

  1. 创建一个内部类继承自Binder,并在onBind()方法中返回该类的实例对象
  2. 在主活动中创建 ServiceConnection的匿名类,并重写2个方法
    onServiceConnected():在活动与服务成功绑定时调用
    onServiceDisconnected():在活动与服务解绑时调用
  3. 绑定服务
    Intent bindIntent = new Intent(MainActivity.this,MyService.class);
    bindService(bindIntent,connection,BIND_AUTO_CREATE); 三个参数
    1. intent对象
    2. ServiceConnection实例对象
    3. 标志位,传入BIND_AUTO_CREATE表示在活动和服务进行绑定后自动创建服务
  4. 解绑服务
    unbindService(connection); 直接传入ServiceConnection实例对象进行解绑

代码示例:

//在刚才的MyService类中创建内部类MyBinder类并继承于Binder
//用于提供具体的方法,并在onBind()方法中返回MyBinder实例
    private MyBinder mBinder = new MyBinder();
    public static class MyBinder extends Binder{
        //服务里提供具体的方法的类
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }


//在主活动中定义变量MyBinder,以及匿名类ServiceConnection
    private MyService.MyBinder myBinder;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        	//赋值
            myBinder = (MyService.MyBinder) service;
            //TODO: 调用服务中的方法
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

//在Oncreate()方法中,按钮的点击事件中 绑定服务
     Intent intent = new Intent(ServiceActivity.this,MyService.class);
     bindService(intent,connection,BIND_AUTO_CREATE);


//解绑服务,服务会销毁
     unbindService(connection);

10.3.4 服务的生命周期

每个服务都只存在一个实例

  • onCreate():在服务创建时调用
  • onStartCommand():服务启动时调用
  • onBind():服务绑定时调用
  • onDestroy():服务被销毁时调用

Service的生命周期可以分成三个不同的路径:

  • 通过startService()方法启动Service
    其生命周期 onCreate() - onStartCommand() - onDestroy()
    当调用startService()方法时,Service被创建,并且无限期运行,其自身必须调用stopSelf()或者其他组件调用stopService()方法来停止Service。当Service停止时,系统将其销毁。

  • 通过bindService()方法启动Service,服务还没有被创建
    其生命周期 onCreate() - onBind() - onDestroy()
    当调用bindService()方法时,Service被创建。客户端通过IBinder接口与Service通信。客户端通过unbindService()方法关闭连接。当都解除绑定时,系统销毁Service(Service不需要被停止)。

  • 通过startService()方法,bindService()方法来启动服务
    需要同时调用stopService()方法和unbindService()方法来销毁服务

10.3.5 使用前台服务

在onCreate()方法中,构建出Notification对象,后使用startForeground(通知的id,Notification对象)方法让Service变成一个前台服务

代码示例:

在onCreate()方法中:

  		//将该注解写在方法上
  		//@RequiresApi(api = Build.VERSION_CODES.O)

        String channelId = "channel_id_01";
        String channelName = "channel";
        NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

        NotificationChannel channel = new NotificationChannel(channelId,channelName,NotificationManager.IMPORTANCE_DEFAULT);

        notificationManager.createNotificationChannel(channel);

        Notification notification = new Notification.Builder(this,channelId)
          
                .setContentTitle("service")
                .setContentText("service text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))
                .build();

        startForeground(1,notification); 

10.3.6 使用IntentService

在运行结束后会自动停止,IntentService使用流程:

新建类继承自IntentService,并重写常用的2个方法,在无参构造函数中调用父类的有参构造函数
onHandleIntent():处理具体的逻辑
onDestroy():自动停止服务时调用

代码示例:

public class MyIntentService extends IntentService { 

    public MyIntentService() {
        super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        //处理具体逻辑
    }

    @Override
    public void onDestroy() {
        
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值