【安卓移动应用开发】四大组件之——Service

【安卓移动应用开发】四大组件之——Service

1,安卓中进程的概念

1.1,Android中的进程与线程

1.每一个app就是一个进程,进程开启的时候默认就有一个主线程(UI线程)
2.线程之间可以做到数据共享,但是进程之间无法直接进行数据共享(但可通过组件进行)
3.主线程才能进行UI更新的操作
4.不要把耗时操作放在主线程,而是开启一个子线程去处理这些事情

1.2,开启一个子进程

下面介绍两种常用的方法来创建子线程,这两种方法都是基于Java的多线程来实现的。

1.2.1,继承Thread对象

步骤1:编写子线程类,这里可以使用内部类,方便共享数据

/**
 * 继承Thread类开启子线程
 */
class SonThread extends Thread {
    /*
     * 自定义方法,run方法调用,使得run方法更加简洁
     */
    protected int CountSum() {
        for (int i = 0; i < 1000; i++) {
            sum += 1;
        }
        return sum;
    }

    /**
     * 重写run方法
     * 在run方法中调用子线程需要执行的方法
     */
    @Override
    public void run() {
        super.run();
        CountSum();
        tv_log.setText(sum+"");
    }
}

步骤2通过start方法开启子线程

Thread mThread = new SonThread();
// 注意不是使用run方法来开启线程,而是使用start方法
// 直接使用run方法的话还是在主线程中运行
mThread.start();
1.2.2,实现Runnable接口

(考虑到Java的单继承,更加推荐此方法)

步骤1:编写子线程类实现Runnable方法

class SonThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            sum += 1;
        }
        Log.d("zhiqiang","当前运行线程ID:"+Thread.currentThread().getId());
        tv_log.setText(sum+"");
    }
}

步骤2:通过Thread的构造方法来构造Thread对象,并通过start方法开启子线程

Thread mThread = new Thread(new SonThread());
mThread.start();

注意,开启多个子线程,子线程的执行顺序与代码顺序无关

1.3,子线程更新UI

为了用户体验的流畅,安卓禁止在子线程中更新UI,在子线程直接更新UI会导致崩溃(某些情况下不会崩溃??但是还是要按照规范只在主线程中更新UI)。

1.3.1,Handler切换线程

下面介绍最为基础的方式----通过Handler来实现子线程间接更新UI的方法:

步骤1:构建类,继承Handler类,实现handleMessage方法

// 类属性
protected static final int CHANGE_TEXT_MAG = 1;

protected class UIHandler extends Handler{
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case CHANGE_TEXT_MAG:
                // 实现更新UI的操作
                tv_log.setText(msg.arg1+"");
                break;
        }
    }
}

步骤2:在主线程对Handler初始化

// 声明Handler类对象
private UIHandler uiHandler;
// 初始化Handler对象
uiHandler = new UIHandler();

Handler对象在那个线程中创建的,其中的方法就会在那个线程中执行

步骤3:在子线程中创建Message类,向Handler发送消息

// 向Handler发送消息
Message message = new Message();
message.what = CHANGE_TEXT_MAG;
message.arg1 = sum;
uiHandler.sendMessage(message);
1.3.2,AsyncTask框架

使用上一节中的方法完成子线程更行UI操作太过麻烦,使用AsyncTask框架,能够省去繁琐的Handler线程切换。

步骤:1编写类,继承AsyncTask类,并实现必要的方法

// 使用框架更新UI
protected class DownloadTask extends AsyncTask<String,Integer,Boolean>{
    // 需要提前准备的任务,在doInBackground之前运行
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        Log.d("zhiqiang","运行--onPreExecute方法");
    }

    // 后台需要进行的操作,这也是最主要的方法 **
    @Override
    protected Boolean doInBackground(String... strings) {
        String data = strings[0];
        Log.d("zhiqiang","接受参数"+data+"\n开始执行doInBackground方法");
        int prograss = 0;
        while (prograss < 100){
            prograss += 10;
            // 通过publishProgress方法通知主进程当前线程进度
            publishProgress(prograss);
            Log.d("zhiqiang","当前下载进度:"+prograss);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    // 主线程运行过程中,使用该方法接受子线程运行进度(与publishProgress方法配合使用,通知一次,接收一次)
    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
        int progress = values[0];
        tv_log.setText("下载进度:"+progress);
    }

    // 子线程任务结束会调用该方法(doInBackground方法结束时调用)
    @Override
    protected void onPostExecute(Boolean aBoolean) {
        super.onPostExecute(aBoolean);
        tv_log.setText("下载完成!!");
    }
}

2,Service

2.1,Service的使用

2.1.1,创建Service

Java包上右键 > New > Service > Service

2.1.2,Service生命周期方法
// onCreate方法只会在初次创建的时候被调用(销毁之后再创建也会被调用)
@Override
public void onCreate() {
    super.onCreate();
}
// onStartCommand方法每次调用startService方法的时候都会被调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    return super.onStartCommand(intent, flags, startId);
}
// 使用stopService方法销毁Service的时候会调用onDestroy方法
@Override
public void onDestroy() {
    super.onDestroy();
}
2.1.3,Service的使用

通过startService和stopService来创建和关闭Service

// 1 > 使用Service创建Intent
Intent intent = new Intent(MainActivity.this,MyService.class);
// 2 > 调用startService方法传递Intent来开启Service
startService(intent);
/*在调用stopService方法之前再次调用startService方法,不会触发Service的onCreate方法*/
// 3 > 停止Service
stopService(intent);

通过bindService和unBindService来创建和关闭Service,这种方式创建的Service可以和很方便Activity进行通信

/* 1 > 编写类继承Binder类,并通过Service的onBind方法返回该类的实体对象*/
public class MyBinder extends Binder{
    private int sum = 0;
    public void Count(int num1,int num2){
        sum = num1 + num2;
    }
    public int getSum(){
        return sum;
    }
}

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    return new MyBinder();
}
// 2 > 使用Service创建Intent
Intent intent = new Intent(MainActivity.this,MyService.class);
// 3 > 在Activity中调用bindService方法,连接Service
bindService(intent,connection,BIND_AUTO_CREATE);
// 4 > 初始化Binder对象,在connection中对其进行赋值    
private MyService.MyBinder mBinder = null;

// 5 > bindService方法中的connection参数需要手动编写ServiceConnection类
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // 其中的参数service为连接的service中onBind方法返回的Binder对象
        mBinder = (MyService.MyBinder)service;
        
        // 调用service中bind类返回的方法
        mBinder.Count(1,2);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // 一般在Activity与Service被动非正常断开连接的时候,重新连接Service会被调用。。
    }
};
// 6 > 使用unbindService方法,传递connection为参数,断开与Service的连接
unbindService(connection);

bindService和stopService,只会在第一次调用bindService的时候会调用bindService和onCreate方法,调用stopService的时候会调用onDestroy方法。不会调用onStartCommand方法

2.1.4,Service的线程

Service默认运行在主线程中,若想要在Service中运行耗时操作,需要手动创建子线程。

3,特殊的Service

3.1,前台Service

通过前台Service,service会在通知中显示,并且在Activity不可见的时候,继续在后台执行。

步骤1:在AndroidManifest.xml配置文件中添加permission

<manifest ...>
     <!--添加下方uses-permission配置-->
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
     ...
     <application ...>
     ...
</manifest>

步骤2:编写Service,在适当的生命周期方法中将Service挂载到Notification上

public class MyService extends Service{
...
    
@Override
public int onStartCommand(Intent intent, int flags, int startId) {

    // 开启前台Service
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        NotificationChannel channel = new NotificationChannel("LearnService", "LearnService",NotificationManager.IMPORTANCE_DEFAULT);
        manager.createNotificationChannel(channel);
    }
    // 定义点击通知后跳转的Activity
    Intent mIntent = new Intent(MyService.this,MainActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(MyService.this,0,mIntent,0);

    // 生成通知
    Notification notification = (new NotificationCompat.Builder(MyService.this,"LearnService"))
        .setContentTitle("setContentTitle")
        .setContentText("setContentText")
        .setSmallIcon(R.drawable.ic_launcher_background)
        .setContentIntent(pendingIntent)
        .build();

    // 关键步骤
    startForeground(1,notification);

    return super.onStartCommand(intent, flags, startId);
}

这样,通过Activity调用startService方法开启Service的时候,就会生成一个Service的通知了。该Service在退出App的时候不会一起关闭

3.2,IntentService

后台调用的Service,会自动创建子线程,且运行完会被自动回收

public class MyService extends IntentService {

也可以使用普通Service每次调用stopSelf,但是需要添加子线程。。

步骤1:创建继承IntentService

再Java包上右键 > Service > Service(IntentService) 来创建 IntentService

步骤2:在onHandleIntent方法中编写子线程中需要执行的操作

步骤2:在Activity中调用启动IntentService

Intent intent = new Intent(MainActivity.this,MyIntentService.class);
startService(intent);

IntentService中子线程的任务完成之后,回自动的调用Destroy方法,结束子线程。而普通的Service创建子线程运行结束之后,不会自动关闭子线程

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值