写这个博客时抽抽了,顺便又用了一些WebView的东西,更多webview参见这里
1.简单介绍下AsyncTask
AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.比Handler更轻量级,但是在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.代码量上,如果只开一个后台进程AsyncTask是绝对首选,因为handler处理结构相对复杂。
2.使用
要使用AsyncTask工作我们要提供三个泛型参数,并重载几个方法(至少重载一个doInBackground)。
参考:android AsyncTask介绍 - Devin Zhang - 博客园
AsyncTask定义了三种泛型类型 Params,Progress和Result。
- Params 启动任务执行的输入参数,比如HTTP请求的URL。
- Progress 后台任务执行的百分比, 比如Integer。
- Result 后台执行任务最终返回的结果,比如String。
使用过AsyncTask 的同学都知道一个异步加载数据最少要重写以下这两个方法:
- doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
- onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回
有必要的话你还得重写以下这三个方法,但不是必须的:
- onProgressUpdate(Progress…) 可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。
- onPreExecute() 这里是最终用户调用Excute时的接口,当任务执行之前开始调用此方法,可以在这里显示进度对话框。
- onCancelled() 用户调用取消时,要做的操作
使用AsyncTask类,以下是几条必须遵守的准则:
- Task的实例必须在UI thread中创建;
- execute方法必须在UI thread中调用;
- 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法;
- 该task只能被执行一次,否则多次调用时将会出现异常;
3.看个栗子
建立在上一个博客项目基础上,创建了新的布局处理。
XMl:activity_async_task.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:padding="10dp"
android:text="download" />
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@id/download"
android:layout_marginTop="10dp"
android:scaleType="centerCrop"/>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_below="@id/image"
android:layout_margin="5dp"
android:max="100"
android:progress="0"
android:id="@+id/seekbar"/>
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/seekbar"/>
</RelativeLayout>
AsyncTaskActivity.java(该文件弃用,因为后来优化遇到了些问题,作为对比故保留,详见第二个文件)
package com.lzy.exploremessagedemo;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;
public class AsyncTaskActivity extends Activity {
private Button downloadButton;
private ImageView mImageView;
private ProgressDialog progressDialog;
private SeekBar seekBar;
private WebView webView;
private final String url = "http://b.hiphotos.baidu.com/image/h%3D300/sign=1b921b860d24ab18ff16e" +
"73705fbe69a/86d6277f9e2f070861ccd4a0ed24b899a801f241.jpg";
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
progressDialog = new ProgressDialog(this);
mImageView = (ImageView) findViewById(R.id.image);
seekBar = (SeekBar) findViewById(R.id.seekbar);
webView = (WebView) findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(true);
settings.setSupportZoom(true);
downloadButton = (Button) findViewById(R.id.download);
downloadButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
new MyAsyncTask().execute(url);//异步加载网络图片
webView.loadUrl(url);//使用webview加载网络图片
}
});
}
class MyAsyncTask extends AsyncTask<String, Integer, Bitmap>{//参数,进度,结果
@Override
protected void onPreExecute() {
progressDialog.setMessage("请稍后...");
progressDialog.show();
}
@Override
protected Bitmap doInBackground(String... prarm) {
String url = prarm[0];
Bitmap bitmap = null;
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode()) {
HttpEntity entity = httpResponse.getEntity();
InputStream in = entity.getContent();
bitmap = BitmapFactory.decodeStream(in);
publishProgress(100);//进度显示,这里作为一个知识点,结果显示回调在onProgressUpdate(Integer... values)方法中
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpClient.getConnectionManager().shutdown();
}
return bitmap;
}
@Override
protected void onProgressUpdate(Integer... values) {
seekBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
progressDialog.dismiss();
mImageView.setImageBitmap(result);
Toast.makeText(getApplicationContext(), "下载成功!", Toast.LENGTH_SHORT).show();
}
}
}
vvvvvvvv22222222222222222222222222↓
package com.lzy.exploremessagedemo;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;
public class AsyncTaskActivity extends Activity {
private Button downloadButton;
private ImageView mImageView;
private ProgressDialog progressDialog;
private SeekBar seekBar;
private WebView webView;
private final String url = "http://b.hiphotos.baidu.com/image/h%3D300/sign=1b921b860d24ab18ff16e" +
"73705fbe69a/86d6277f9e2f070861ccd4a0ed24b899a801f241.jpg";
@SuppressLint("SetJavaScriptEnabled")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_task);
progressDialog = new ProgressDialog(this);
mImageView = (ImageView) findViewById(R.id.image);
seekBar = (SeekBar) findViewById(R.id.seekbar);
webView = (WebView) findViewById(R.id.webview);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(true);
settings.setSupportZoom(true);
downloadButton = (Button) findViewById(R.id.download);
downloadButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
new MyAsyncTask().execute(url);
webView.loadUrl(url);
}
});
}
class MyAsyncTask extends AsyncTask<String, Integer, Bitmap>{//参数,进度,结果
@Override
protected void onPreExecute() {
progressDialog.setMessage("请稍后");
progressDialog.show();
}
@SuppressWarnings("unused")
@Override
protected Bitmap doInBackground(String... prarm) {
String url = prarm[0];
Bitmap bitmap = null;
InputStream in = null;
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
if (HttpStatus.SC_OK == httpResponse.getStatusLine().getStatusCode()) {
HttpEntity entity = httpResponse.getEntity();
in = entity.getContent();
long total = entity.getContentLength();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int count = 0;
int length = -1;
while ((length = in.read(buf)) != -1) {
baos.write(buf, 0, length);
count += length;
//调用publishProgress公布进度,最后onProgressUpdate方法将被执行
publishProgress((int) ((count / (float) total) * 100));
//为了演示进度,休眠100毫秒
Thread.sleep(100);
}
/**
* @time 2015-9-22 - 下午1:48:59
* @bug 这是android 1.6的一个bug,解决方案如下
* */
//bitmap = BitmapFactory.decodeStream(in);//不清楚为什么这样写获取不到图片,改用如下方式就能了,如果不为了演示进度条的功能,将while注掉,然后使用此方法,却能显示图片??????
//bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.toByteArray().length);
/**
* 最终解决办法
* */
if (in == null) {
bitmap = BitmapFactory.decodeStream(in);
}else {
//为了防止加载大图片OOM 采用BitmapFactory.Options进行缩略图处理
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//不返回实际的Bitmap
options.inSampleSize = Util.computeSampleSize(options, -1, 128 * 128);
//为什么加上options参数获取的Bitmap就为null呢???????????? 心累。。。。。
/**
* @time 2015-9-22 - 下午3:03:32
* @bug 这是因为options.inJustDecodeBounds = true后不会创建Bitmap空间只作为暂存,最后
* 还要设置回来显示Bitmap
* */
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.toByteArray().length, options);
}
return bitmap;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
httpClient.getConnectionManager().shutdown();
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
seekBar.setProgress(values[0]);
}
@Override
protected void onPostExecute(Bitmap result) {
progressDialog.dismiss();
/**
* 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,
* 因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。 ☆
* */
mImageView.setImageBitmap(result);
Toast.makeText(getApplicationContext(), "下载成功!", Toast.LENGTH_SHORT).show();
}
}
}
里面有用到一个缩放比的工具类:在这里
☆的说明参看博客:BitmapFactory.Options避免 内存溢出 OutOfMemoryError的优化方法_骑猪追大象的博客-CSDN博客
最后别忘了添加网络访问权限
<uses-permission android:name="android.permission.INTERNET"/>
不了解HttpClient用法的参见这篇博客:Java HttpClient使用小结_solari_bian的博客-CSDN博客_schemeregistry
我把manifest也贴出来吧:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lzy.exploremessagedemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@android:style/Theme.Holo.Light" >
<activity
android:name=".AsyncTaskActivity" <!-- 换成上一篇博文的主文件".MainActivity"就可以启动上一个项目了 -->
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
至此关于AsyncTask的使用就是这么简单。
栗子源码下载:点我下载