Android--线程--AsyncTask

1.线程

线程,是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。线程也有就绪、阻塞和运行三种基本状态。就绪状态是指线程具备运行的所有条件,逻辑上可以运行,在等待处理机;运行状态是指线程占有处理机正在运行;阻塞状态是指线程在等待一个事件(如某个信号量),逻辑上不可执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。而在单个程序中同时运行多个线程完成不同的工作,称为多线程。

2.Android线程

应用启动时,系统会为应用创建一个名为“主线程”的执行线程。此线程非常重要,因为它负责将事件分派给相应的用户界面小部件,其中包括绘图事件。此外,它也是应用与Android UI 工具包组件(来自 android.widgetandroid.view 软件包的组件)进行交互的线程。因此,主线程有时也称为UI 线程。

系统不会为每个组件实例创建单独的线程。运行于同一进程的所有组件均在 UI 线程中实例化,并且对每个组件的系统调用均由该线程进行分派。因此,响应系统回调的方法(例如,报告用户操作的onKeyDown()或生命周期回调方法)始终在进程的 UI 线程中运行。

例如,当用户触摸屏幕上的按钮时,应用的 UI 线程会将触摸事件分派给小部件,而小部件反过来又设置其按下状态,并将失效请求发布到事件队列中。UI 线程从队列中取消该请求并通知小部件应该重绘自身。

在应用执行繁重的任务以响应用户交互时,除非正确实现应用,否则这种单线程模式可能会导致性能低下。具体地讲,如果 UI 线程需要处理所有任务,则执行耗时很长的操作(例如,网络访问或数据库查询)将会阻塞整个 UI。一旦线程被阻塞,将无法分派任何事件,包括绘图事件。从用户的角度来看,应用显示为挂起。更糟糕的是,如果 UI线程被阻塞超过几秒钟时间(目前大约是 5 秒钟),用户就会看到一个让人厌烦的“应用无响应”(ANR)对话框。如果引起用户不满,他们可能就会决定退出并卸载此应用。

此外,Android UI 工具包并非线程安全工具包。因此,您不得通过工作线程操纵 UI,而只能通过 UI 线程操纵用户界面。因此,Android 的单线程模式必须遵守两条规则:

1.不要阻塞 UI 线程

2.不要在 UI 线程之外访问 Android UI 工具包

根据上述单线程模式,要保证应用 UI 的响应能力,关键是不能阻塞 UI 线程。如果执行的操作不能很快完成,则应确保它们在单独的线程(“后台”或“工作”线程)中运行。线程是程序员进阶的一道重要门槛。对于移动开发者来说,“将耗时的任务放到子线程去执行,以保证UI线程的流畅性”是线程编程的第一金科玉律。要通过工作线程处理更复杂的交互,可以考虑在工作线程中使用Handler处理来自 UI 线程的消息。当然,最好的解决方案或许是扩展 AsyncTask 类,Android提供的该类简化了与UI 进行交互所需执行的工作线程任务。

3.Android--AsyncTask

AsyncTask
public abstract class AsyncTask
extends Object
java.lang.Object
↳ android.os.AsyncTask<Params, Progress, Result>

AsyncTask是android提供的轻量级的异步类,可以直接继承AsyncTask在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程。使用起来简便快捷,过程可控。

AsyncTask定义的三种泛型类型 Params,Progress和Result:

1.Params 启动任务执行的输入参数,比如HTTP请求的URL。

2.Progress 后台任务执行的百分比。

3.Result 后台执行任务最终返回的结果,比如String。

使用过AsyncTask必须重写doInBackground(Params…)方法:

doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。

有必要的话还得重写其他方法,但不是必须的:

onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回

onProgressUpdate(Progress…)   可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。

onPreExecute(Result)        这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。

onCancelled()             用户调用取消时,要做的操作

其中执行顺序为:onPreExecute(),doInBackground(Params...), onProgressUpdate(Progress...), onPostExecute(Result)

使用AsyncTask类,尽管方便快捷,但也有很多限制:

1.Task的实例必须在UI thread中创建;

2.execute方法必须在UI thread中调用;

3.不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这些方法;

4.AsyncTask只能被执行一次,多次调用时将会出现异常;

4.Code

如下图,当在UI线程中使用URI连接下载数据显示时将会出现错误:



使用AsyncTask类改进如下:

    public class UriTestTask extends AsyncTask<URL, Void, String> {
        @Override
        protected String doInBackground(URL... urls) {
            URL searchUrl = urls[0];
            String SearchResults = null;
            try {
                SearchResults = NetworkUtils.getResponseFromHttpUrl(searchUrl);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return SearchResults;
        }

        @Override
        protected void onPostExecute(String s) {
            if (s != null && !s.equals("")) {
                mSearchResultsTextView.setText(s);
            }
        }
    }
并在UI线程中启动如下:

@Override

public boolean onOptionsItemSelected(MenuItem item) { int itemThatWasClickedId = item.getItemId(); if (itemThatWasClickedId == R.id.action_search) { makeSearchQuery(); return true; } return super.onOptionsItemSelected(item); } private void makeSearchQuery() { String queryStr = mSearchBoxEditText.getText().toString(); URL searchUrl = NetworkUtils.buildUrl(queryStr); mUrlDisplayTextView.setText(searchUrl.toString()); new UriTestTask().execute(searchUrl); }
App运行正常如下图:


5.参考

AsyncTask:https://developer.android.com/reference/android/os/AsyncTask.html

进程与线程:https://developer.android.com/guide/components/processes-and-threads.html


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值