Android中的多任务与服务

一.基本概念

1.操作一些耗时的操作时,如I/O读写大文件,数据库操作以及网络下载需要很长的时间,为了不堵塞用户界面,出现ANR的响应提示窗口,这个时候我们考虑使用Thread线程来解决。

2.Android中的进程和线程:

在android系统之中,如果有一个应用程序组件是第一次被启动,而这个时候应用程序也没有其他的组件在运行,则Android系统会为应用程序创建一个linux进程(Linux Process),这个Linux进程包含一个线程(Tread),称之为主线程(MainThread)或UI线程(UI Thread)

当一个组件在启动的时候,如果该Process已经存在,那么该组件就直接通过这个process被启动起来,并且运行在这个process的UI Thread之中。

3.进程

默认情况下,同一个应用程序内的所有组件都是运行在同一个进程之中的,大部分应用程序都是按照这种的方式运行的。

在具体的应用中,很多的时候需要通过在manifest文件中进行设置,通过修改四大组件在Manifest.xml中的代码块(<activity><service><provider><receiver>)中的Android:process属性指定组件运行的进程,使其运行在不同的process中。

<application>元素也支持android:process属性,用于指定所有组件的默认进程。

4.进程的重要性的层次结构

进程有5中层次,按其重要的程度递减分为

(1)前台进程(正在和用户交互)

(2)可见进程(没有任何的前台组件,但仍然会影响用户在屏幕上所见内容的进程)

(3)服务进程(虽然不直接和用户所见的内容关联,但是会执行一些用户关心的操作,若系统不足以维持前台进程和可见进程,才会牺牲服务进程空间)

(4)后台进程(包含用户不可见的Activity的进程,这些进程对用户体验没有直接的影响,可以随时的在任意的时间终止他们,以回收内存资源),系统通过LRU(最近最少使用)列表进行多个后台进程的管理,确保最近使用的Activity会后被终止。

(5)空进程(进程不含有任何的应用组件,该进程主要的作用是缓存,以改善在此进程中运行组件的启动时间,系统会经常的终结此类的进程)

5.线程

Android 是单线程模型,我们创建的Service,Activity以及Broadcast均是在一个主线程处理,这里我们可以理解为一个UI线程。(应用程序是一个默认的单线程单任务程序),也就是说默认一个主线程控制所有的交互。我们编写的代码穿插在主线程的逻辑之中,比如对用户触摸事件的检测和相应,对用户输入的处理,自定义View的绘制等,如果我们插入的代码比较耗时,如网络请求和数据库的读取,就会阻塞UI线程其他的逻辑的执行,从而导致界面的卡顿。如果卡顿的时间超过5秒,系统就会报ANR错误,所以执行耗时的操作的时候,我们需要另起线程执行。

在新线程执行完耗时的逻辑后,往往需要将结果反馈给界面,进行UI更新,Android的UI toolkit不是线程安全的,不可以在非UI线程进行UI的更新,所有对界面的更新必须在UI线程中进行、

1.Android 的单线程模式遵循两个原则

(1).不要阻塞UI线程

(2).不要在UI线程外访问UI组件

线程

创建线程:基础操作都在UI线程中运行,耗时的操作可以创建新的线程去完成

继承Thread类

实现Runnable接口

Android提供了四种常用的操作多线程的方式,分别是:

1.Handler+Thread

2.AsyncTask

3.ThreadPoolExecutor

4.IntentService

二.实现多任务

在Android中,我们把除了UI线程外的,其他所有的线程都叫工作线程,也就是说Android只会存在两种线程:UI主线程()和工作线程(workthread)

我们把耗时的操作放在工作线程中做,操作完成后再通知UI主线程去做相应的响应。

这就需要掌握线程之间通信的方式,在Android中提供了两种线程之间的通信方式;

AsyncTask机制(AsyncTask异步执行任务)

Handler机制(创建新线程Thread,用handler负责线程间的通信和消息)

1.使用AsyncTask

AsyncTask是android框架提供的异步处理的辅助类,他可以实现耗时操作在其他的线程执行,而处理结果在Main线程执行。

他屏蔽掉了多线程和Handler的概念,进行了较高程度的封装。

使用AsyncTask的代码很容易被理解,因为他们都具有一些特定职责的方法,如预处理的方法onPreExecute,后台执行任务的方法dolnBackground,更新进度的方法publishProgress,返回结果的方法onPostExecute等等。

2.Handler机制

Handler机制是通过消息队列进行通信机制的,通过使用Handler,Looper,MessageQueue,和Message这几个类协调来完成。

(1)Handler:在android里负责发送和处理消息,通过它可以实现其他的线程与Main线程之间的消息通信。UI主线程在创建的时候会自动的创建一个消息对列和消息循环。主线程的Looper通过创建一个Handler对象,对外界提供了访问消息对列的渠道。

通过Handler.handleMessage()读取消息队列中的消息,在新的线程中调用主线程的Handler的postXXX和sendmessage方法来实现与主线程之间的通信。

使用post方法实现多任务的主要步骤如下;

(1)创建一个Handler对象

(2)将要执行的操作写在线程对象的run方法中。

(3)使用post方法运行线程对象

(4)如需循环执行,如果在线程对象的run方法中再次调用post方法。

详细的步骤如下

工作线程通过方法发送信息到主线程的消息队列。

一个例子

package com.example.mynotification;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    final static String TaG="HANDLER_TEST";
    TextView txt=null;
    Handler handler=new Handler(){
        public void handleMessage(Message message ){
            Log.i(MainActivity.TaG,"onCreate:the main Tread id:"+Thread.currentThread().getId());
            txt.setText("这是工作线程文本");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        txt=findViewById(R.id.hello);
        Log.i(TaG,"onCreate:the main Tread id:"+Thread.currentThread().getId());
      //  txt.setText("这是一段文本");
        new ActivityThread().start();
    }
    class ActivityThread extends Thread{
        public void run(){
            Log.i(TaG,"onCreate:the work Tread id:"+Thread.currentThread().getId());
            handler.sendMessage(new Message());

        }
    }
}

下面再举一个Handler和Runnable一起实现一个延迟显示的例子

package com.example.handlerpostdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Handler countHandler=new Handler();

    Runnable mRunToast=new Runnable() {
        @Override
        public void run() {
            Toast.makeText(MainActivity.this,"hello toast",Toast.LENGTH_SHORT).show();

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((Button)findViewById(R.id.btnShowToast)).setOnClickListener(this);
    }
    public void onClick(View  view){
        switch (view.getId()){
            case R.id.btnShowToast:
                countHandler.postAtTime(mRunToast, SystemClock.uptimeMillis()+5*1000);
                break;
        }

    }
}

可以运行试一下

(2)Looper:负责管理线程的消息队列和消息循环

Looper.myLooper();得到当前线程的Looper对象

Looper.getMainLooper();可以获得当前的进程的主线程的Looper

Looper.prepare();创建消息队列

Looper.loop();进入消息循环。

(3)Message:线程之间通信的消息载体,Message充当消息封装的功能,里面可以存放任何想要传递的消息。

(4)MessageQueue:消息队列先进先出,它的作用是保存有待线程处理的消息。

三.理解服务

猜你喜欢

转载自blog.csdn.net/a15929748502/article/details/110951532