Java学习教程-异步任务

更新时间:2024-01-05 13:56:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

http://www.moliying.com

一,什么是异步任务:

使用子线程执行耗时的操作,然后通过回调把结果返回给主线程

二 ,为什么使用异步任务:

1、开发Android应用时必须遵守单线程模型的原则:

Android UI操作并不是线程安全的,并且某些操作必须在UI线程中执行。 2,android使用线程的规则:

2.1 主线程不能被阻塞,不能执行耗时的操作(不能超过5秒) 2.2 子线程不能操作UI线程

当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。 3、Android4.0以上版本中,主线程中不允许访问网络。涉及到网络操作的程序一般都是需要开一个新线程完成。但是在获得页面数据后,又不能将数据返回到UI界面中 。因为子线程(Worker Thread)不能直接访问UI线程中的组件,也就是说没有办法对UI界面上的内容进行操作,如果操作,将抛出异常:CalledFromWrongThreadException。

4、Handle是线程间的通信,将子线程的数据传递给主线程,在Android中已经实现了这种线程间的通信,这个类就是AsyncTask。

磨砺营IT教育版权所有

http://www.moliying.com

在AsyncTask类中通过接口回调,实现子线程与主线程之间的通信。

为了降低异步任务的开发难度,在handler基础上提供了AsyncTask,AsyncTask其实就是封装过的后台任务类。

三,如何使用AsyncTask(必须在主线程中启动)

3.1 定义一个类,继承AsyncTask,同时声明三个泛型

Public class MyTask extends AsyncTask 如果没有返回值为Void

第一个泛型:子线程执行方法的参数类型 第二个泛型:子线程执行任务的进度 第三个泛型:子线程执行任务的结果数据类型 3.2 重写核心方法

protected void onPreExecute(){}

//运行在主线程中,执行任务时,首先调用,可以在该方法中做一些准备工作,如

在界面上显示一个进度条(ProgressDialog)。

protected byte[] doInBackground(String... params) {return null;} 运行在子线程中,执行耗时的操作(后台线程)

可以在该方法中调用 publishProgress方法来通知UI线程更新实时的任务进度。 protected void onProgressUpdate(Integer... values) {}

//运行在主线程中,更新UI(进度条),在publishProgress方法被调用

后,UI 线程将调用本方法更新进度

protected void onPostExecute(byte[] result) {}

//运行在主线程中,在doInBackground 执行完成后,本方法将被UI 线程调用,

在此方法中更新UI界面.

磨砺营IT教育版权所有

http://www.moliying.com

3.5 创建完成后,在UI线程中执行异步任务

new MyTask().execute();

注:

必须要重写doInBackground方法 (在工作线程中) 通常要重写onPostExecute方法(在UI线程中), 其他方法根据需要进行重写

案例一:利用异步任务从网络上读取一个图片,进度条对话框提示用户正在加载,并显示到ImageView中

图片地址:http://www.http://www.wodefanwen.com//img/bd_logo1.png public class MainActivity extends Activity {

private Button button;

private ImageView imageView; @Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState); //加载UI布局

setContentView(R.layout.activity_main);

//得到控件初始化

button = (Button) findViewById(R.id.button);

imageView = (ImageView) findViewById(R.id.image_view_id);

3.6 取消异步任务,new MyTask().cancel(true);

button.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

磨砺营IT教育版权所有

http://www.moliying.com

// TODO 启动异步任务,下载图片

MyAsyncTask mTask = new MyAsyncTask();

mTask.execute(\http://www.http://www.wodefanwen.com//img/bd_logo1.png\; }

});

}

/**

* 自定义异步任务 加载网络图片 * 第一个泛型: 子线程执行方法的参数类型 * 第二个泛型: 子线程执行任务的进度 * 第三个泛型: 子线程执行任务的返回结果类型 * @author fancx */

public class MyAsyncTask extends AsyncTask {

private ProgressDialog pDialog;

@Override

protected void onPreExecute() {

// TODO 事前的方法 , 初始化的工作(初始化对话框) super.onPreExecute(); //初始化进度条对话框

pDialog = new ProgressDialog(MainActivity.this); //设置图标

pDialog.setIcon(R.drawable.ic_launcher); //设置标题

磨砺营IT教育版权所有

http://www.moliying.com

}

pDialog.setTitle(\提示信息\); //设置内容

pDialog.setMessage(\正在加载,请稍后...\); //点击空白地方,对话框不消失 pDialog.setCancelable(false); //显示对话框 pDialog.show();

@Override

protected byte[] doInBackground(String... params) {

// TODO 后台运行,执行耗时的操作 try {

//获取图片 //得到图片地址

String path = params[0];

//加载图片

HttpClient client =new DefaultHttpClient();

HttpGet get = new HttpGet(path);

HttpResponse response = client.execute(get);

if(response.getStatusLine().getStatusCode() ==

HttpStatus.SC_OK)

{

磨砺营IT教育版权所有

http://www.moliying.com

return

EntityUtils.toByteArray(response.getEntity()); }

磨砺营IT教育版权所有

} @Override

protected void onPostExecute(byte[] result) {

// TODO 显示图片

super.onPostExecute(result); //对话框消失 pDialog.dismiss();

if(result!=null && result.length>0) {

}

} catch (Exception e) { }

return null;

// TODO Auto-generated catch block e.printStackTrace();

Bitmap bitmap =

BitmapFactory.decodeByteArray(result, 0, result.length); }

}

}

imageView.setImageBitmap(bitmap);

http://www.moliying.com

案例二:通过异步任务向网络获取json数据,(带有进度条的提示),并填充到

Spinner中

MainActivity.java

public class MainActivity extends Activity {

private Button startLoad,stopLoad;

private ProgressBar progressBar;

private Spinner spinner;

private MyTask task;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);

//初始化控件 init();

//进度条消失

progressBar.setVisibility(View.GONE);

//开始获取数据

startLoad.setOnClickListener(new OnClickListener() {

@Override

磨砺营IT教育版权所有

http://www.moliying.com

public void onClick(View v) {

// 开启异步任务,获取数据

task = new MyTask();

task.execute(\20.html\);

/**

* 自定义异步任务 获取网络的数据 * */

public class MyTask extends AsyncTask> {

磨砺营IT教育版权所有

}

});

//停止获取数据

stopLoad.setOnClickListener(new OnClickListener() { });

@Override

public void onClick(View v) { }

// TODO 停止异步任务

task.cancel(true);

}

http://www.moliying.com

@Override

protected void onPreExecute() { }

// TODO 事前方法,初始化工作 super.onPreExecute();

//显示进度条

progressBar.setVisibility(View.VISIBLE); //设置进度条的初始值为0 progressBar.setProgress(0);

@Override

protected List doInBackground(String... params) {

// TODO 执行网络加载数据,解析数据 try {

URL url = new URL(params[0]);

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod(\);

//请求的数据不要gzip压缩返回

conn.setRequestProperty(\,

\);

磨砺营IT教育版权所有

http://www.moliying.com

conn.connect();

if(conn.getResponseCode() == HttpStatus.SC_OK) {

InputStream is = conn.getInputStream();

//得到流的总长度

long maxLen = conn.getContentLength(); //当前读取的长度 long curLen = 0;

//读取数据

byte[] buffer = new byte[1024]; int len = 0 ;

StringBuilder sBuilder = new StringBuilder(); while ((len = is.read(buffer))!=-1) {

sBuilder.append(new String(buffer,0,len));

//进度条的进度值 = 当前读取的长度 * 100 / 流的总长度

curLen +=len;

int progress = (int)(curLen*100/maxLen);

//异步更新进度(执行后会调用onProgressUpdate(Integer... values))

}

publishProgress(progress);

Thread.sleep(500);

//解析数据

return JsonParse.parseJson(sBuilder.toString() }

磨砺营IT教育版权所有

http://www.moliying.com

} catch (Exception e) { } }

// TODO Auto-generated catch block e.printStackTrace();

return null;

@Override

protected void onProgressUpdate(Integer... values) {

}

@Override

// TODO 更新进度

super.onProgressUpdate(values); progressBar.setProgress(values[0]);

protected void onPostExecute(List result) {

// TODO 更新UI

super.onPostExecute(result); //进度条消失

progressBar.setVisibility(View.GONE); if(result!=null && result.size()>0) {

//得到控件 spinner //得到数据源 result //适配器

ArrayAdapter adapter = new ArrayAdapter(

MainActivity.this,

磨砺营IT教育版权所有

http://www.moliying.com

android.R.layout.simple_spinner_item, result);

spinner.setAdapter(adapter); }

//初始化控件

private void init() { } } /**

* 解析json数据 * @author fancx */

public class JsonParse {

public static List parseJson(String jsonStr) {

startLoad = (Button) findViewById(R.id.start_load); stopLoad = (Button) findViewById(R.id.stop_load); progressBar = (ProgressBar) findViewById(R.id.progress_id);

}

}

spinner = (Spinner) findViewById(R.id.spinner_id);

if(jsonStr == null) return null;

try {

JSONObject jsonObject = new JSONObject(jsonStr); List result = new ArrayList();

JSONArray jsonArray =

jsonObject.getJSONArray(\);

磨砺营IT教育版权所有

http://www.moliying.com

for(int i = 0 ;i

{

JSONObject jsonObject2 = jsonArray.getJSONObject(i); }

[面试常考]

关于ANR异常:Application Not Responsing应用程序无响应异常 1)什么引发了ANR?

在Android里,应用程序的响应性是由Activity Manager和Window Manager系统服务监视的。当它监测到以下情况中的一个时,Android就会针对特定的应用程序显示ANR: 在5秒内没有响应输入的事件(例如,按键按下,屏幕触摸)当做了某种操作启动一个了耗时的操作(如网络下载),不等此操作运行完毕,继续快速点其他位置,或者多次点击此按钮

String title = jsonObject2.getString(\); result.add(title); }

} catch (JSONException e) { }

}

return result;

e.printStackTrace();

磨砺营IT教育版权所有

http://www.moliying.com

一个ANR对话框显示给用户

比如在按钮的点击事件处理方法中sleep 5秒钟,快速点击该按钮以及其他位置时,可能会触发ANR. 2)如何避免ANR?

运行在主线程里的任何方法都尽可能少做事情。特别是,Activity应该在它的关键生命周期方法(如onCreate()和onResume())里尽可能少的去做创建操作。潜在的耗时操作,例如网络或数据库操作,或者高耗时的计算如改变位图尺寸,应该在子线程里(或者以数据库操作为例,通过异步请求的方式)来完成。 但Android绝对不允许在子线程中操作UI界面.

磨砺营IT教育版权所有

本文来源:https://www.bwwdw.com/article/alrx.html

Top