老罗视频学习笔记。
一.AsyncTask异步类实现的多线程操作。
从网络上获取图片,不要忘记在AndroidManifest.xml文件中添加访问网络的权限
AndroidManifest.xml->Permissions->add->UsesPermission->INTERNET即可。
AsyncTask类是android提供的一个轻量级的用来执行多线程操作的类。
首先在布局文件里添加一个按钮和一个ImageView控件,本例实现用异步类从网络上下载图片并显示在ui上。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.android_asynctask_download.MainActivity"
tools:ignore="MergeRootFrame" >
<Button
android:id="@+id/loadPicButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载网络图片" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="214dp"
android:layout_height="wrap_content"
android:layout_weight="0.46"
android:src="@drawable/ic_launcher" />
</LinearLayout>
定义两个控件的对象。
public Button loadimageButton;
public ImageView imageView;
从网上找一张图片,并且右键点击复制图片网址,作为图片的网络地址。(可以新开一个网页把网址粘贴上测试是否正确)
private static String image_path = "http://f.hiphotos.baidu.com/image/pic/item/b64543a98226cffc632c0bbbbb014a90f603eab1.jpg";
再定义一个progressDialog对象,用来显示图片下载的进度。
private ProgressDialog progressDialog;
在Oncreate函数中实例化这几个控件对象:
loadimageButton = (Button)findViewById(R.id.loadPicButton);
imageView = (ImageView)findViewById(R.id.imageView1);
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("提示信息");
progressDialog.setMessage("正在下载,请稍后。。。");
定义内部类MyTask类,继承自AsyncTask类,
重载onPreExecute函数(表示任务执行之前的操作)
重载doInBackground函数(这个函数执行耗时的操作)
重载OnPressUpdate函数(这个函数用来执行更新)
重载OnPostExecute函数(这个函数用来执行结束后更新UI)
/*
* 使用异步任务的规则
* 1.第一个参数是传递的网络路径
* 2.第二个参数是表示进度的刻度
* 3.第三个参数表示返回的类型。
*/
public class MyTask extends AsyncTask<String, Void, Bitmap>{
//表示任务执行之前的操作
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog.show();//显示进度条对话框
}
//主要是完成耗时操作
//当异步任务执行的时候,先执行这个函数。执行后的结果发布给onPostExecute
@Override
protected Bitmap doInBackground(String... params) {
// TODO Auto-generated method stub
//定义一个HttpClient类用来从网络上获取图片
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(params[0]);
Bitmap bitmap = null;
try {
HttpResponse httpResponse = httpClient.execute(httpGet);
int responseCode = httpResponse.getStatusLine().getStatusCode();
System.out.print("responseCode!!!!!!!!!!!!!"+responseCode);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
byte[] data = EntityUtils.toByteArray(httpEntity);
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
return bitmap;
}
//主要是更新UI的操作
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
imageView.setImageBitmap(result);
progressDialog.dismiss();//图片完成后,把对话框关闭掉
}
}
在点击加载图片按钮后,按钮的响应事件如下:
loadimageButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//执行异步任务的操作
new MyTask().execute(image_path);
}
});
可以实现,点击按钮后,显示进度条对话框,当下载完成后,ImageView显示图片,进度条对话框关闭。
二.AsyncTask类实现异步下载图片2,用进度条显示。
主线程的代码和上边一样,不同是把progressDialog的样式改为直线型进度条。
并且设置为进度完全前不会消失。
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置为长条进度条
progressDialog.setCancelable(false);//设置为进度完成后才会消失,即过程中不会中断
MyTask类如下:
重载了onPreExecute函数。
重载了onProgressUpdate函数。
重载了doInBackground函数。
重载了doPostExecute函数。
doInBackground函数很重要,实现了从网络上下载图片,并且根据下载的量来显示设置进度条的位置。
public class MyTask extends AsyncTask<String, Integer, Bitmap>{
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog.show();
}
@Override
protected void onProgressUpdate(Integer... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
progressDialog.setProgress(values[0]);
}
@Override
protected Bitmap doInBackground(String... arg0) {
// TODO Auto-generated method stub
Bitmap bitmap = null;
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(arg0[0]);
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
inputStream = httpResponse.getEntity().getContent();
long file_length = httpResponse.getEntity().getContentLength();
int len = 0;
byte[] data = new byte[1024];
int total_length = 0;
while ((len = inputStream.read(data)) != -1) {
total_length += len;
int value = (int)((total_length / (float)file_length)*100);
publishProgress(value);
outputStream.write(data,0,len);
}
byte[] result = outputStream.toByteArray();
bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);
}
} catch (Exception e) {
// TODO: handle exception
}finally{
if(inputStream !=null){
try {
inputStream.close();
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
imageView2.setImageBitmap(result);
progressDialog.dismiss();
}
}
这个链接讲AsyncTask比较详细: http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html
关于HttpClient和HttpUrlConnection的区别,这个链接比较详细:http://blog.csdn.net/hguang_zjh/article/details/33743249
三.Handler和Message基本的使用。
布局文件依旧是一个button按钮和一个ImageView控件,从网络上下载图片并显示。
定义需要的控件对象,或者变量:
private final static int IS_FINISH = 1;
private Button button3;
private ImageView imageView;
private ProgressDialog progressDialog;
private static String image_path = "http://f.hiphotos.baidu.com/image/pic/item/b64543a98226cffc632c0bbbbb014a90f603eab1.jpg";
定义一个线程类,继承自Runnable
public class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(image_path);
HttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(httpGet);
if(httpResponse.getStatusLine().getStatusCode() == 200){
byte[] data=EntityUtils.toByteArray(httpResponse.getEntity());
Message message = Message.obtain();
message.obj = data;
message.what = IS_FINISH;
handler.sendMessage(message);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
在oncreate函数里:设置控件信息,并且设置按钮的点击事件。
在点击事件里,新建一个线程,并且显示进度条对话框。
button3 = (Button)findViewById(R.id.handlerimagebutton);
imageView = (ImageView)findViewById(R.id.imageView3);
progressDialog = new ProgressDialog(this);
progressDialog.setTitle("提示信息");
progressDialog.setMessage("正在下载,请稍后");
button3.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
new Thread(new MyThread()).start();
progressDialog.show();
}
});
定义的Handler对象中,获取到message的内容,把它转换为Bitmap图片,显示在ImageView控件中。关闭进度条对话框。
private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
byte[] data = (byte[])msg.obj;
Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
imageView.setImageBitmap(bm);
if (msg.what == IS_FINISH) {
progressDialog.dismiss();
}
};
这是最基本的HandlerMessage的使用,速度比之前的AsyncTask要快。
四.Handler和Message发送消息
在界面中添加一个button控件,点击后,可以发送消息。
定义一个Handler对象,处理接收的消息。
public Handler handler = new Handler(){
//接收从子线程传递过来的消息
public void handleMessage(android.os.Message msg) {
int what = msg.what;
int arg1 = msg.arg1;
int arg2 = msg.arg2;
Object object = msg.obj;
Log.i("TAG", "----what--->"+what);
Log.i("TAG", "----arg1--->"+arg1);
Log.i("TAG", "----arg2--->"+arg2);
Log.i("TAG", "----obj--->"+object);
System.out.print("----what--->"+what);
System.out.print("----arg1--->"+arg1);
System.out.print("----arg2--->"+arg2);
System.out.print("----obj--->"+object);
Bundle bundle = msg.getData();
System.out.println("--->>"+bundle.getShortArray("key").length);
};
};
定义一个自定义的线程MyThread类继承自Runnable类
//定义一个自定义线程类
public class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
//第一种方式
/*
Message message = Message.obtain();
message.what = 1;
message.arg1 = 1;
message.arg2 = 2;
message.obj = "jack";
handler.sendMessage(message);
*/
//第二种方式
/*
Message message = Message.obtain(handler);
message.what = 1;
message.arg1 = 2;
message.arg2 = 3;
message.obj = "jack";
message.sendToTarget();
*/
//第三种方式
/*
Message message = Message.obtain(handler, 33);
message.arg1 = 1;
message.arg2 = 2;
message.obj = "rose";
message.sendToTarget();
*/
//第四种方式
//Message message = Message.obtain(handler, 2, "tom");
//message.sendToTarget();
//第五种方式
Message message = Message.obtain(handler, 2, 1, 3, "test");
Bundle dataBundle = new Bundle();
dataBundle.putStringArray("str", new String[] {"jack","rose","tom"});
message.setData(dataBundle);
message.sendToTarget();
}
}
这里有五种方式可以构造message
启动线程就在button的onClick事件里实现
//启动一个线程
new Thread(new MyThread()).start();
logcat里就会输出获取到的消息了。
五.Handler和Message发送消息
线程中也可以这样发送消息
//1.发送what
//handler.sendEmptyMessage(3);
//2.在某一个时间发送
//handler.sendEmptyMessageAtTime(3, 3000);
//3.延时发送
//handler.sendEmptyMessageDelayed(3, 4000);
//4.用Message发送
/*
Message msg = Message.obtain();
msg.arg1 =1;
msg.arg2=2;
msg.what = 3;
msg.obj = "jack";
handler.sendMessage(msg);
*/
//5.用obtainMessage发送消息
/*
Message msg = handler.obtainMessage();
msg.arg1 = 1;
msg.arg2 = 2;
msg.obj = "rose";
handler.sendMessage(msg);
*/
//6.多参数obtainMessage发送消息
Message msg = handler.obtainMessage(1, 2, 3, "hello");
handler.sendMessage(msg);
这六种方式发送消息,都可以在Handler中接收到并显示在Logcat中。
int what = msg.what;
int arg1 = msg.arg1;
int arg2 = msg.arg2;
Object object = msg.obj;
Log.i("TAG", "----what--->"+what);
Log.i("TAG", "----arg1--->"+arg1);
Log.i("TAG", "----arg2--->"+arg2);
Log.i("TAG", "----obj--->"+object);
System.out.print("----what--->"+what);
System.out.print("----arg1--->"+arg1);
System.out.print("----arg2--->"+arg2);
System.out.print("----obj--->"+object);
六.Looper的使用(一)
首先,界面一个按钮,点击后发送消息,一个textview,接收消息并显示。
自定义一个线程类,继承自Runable类
public class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
Message msgMessage = Message.obtain();
msgMessage.arg1 = 1;
msgMessage.arg2 =2;
msgMessage.obj = "hello";
handler.sendMessage(msgMessage);
}
}
定义一个类继承自Handler,构造函数有无参和有参,有参的构造函数参数是Looper对象。
public class MyHandler extends Handler{
public MyHandler() {
// TODO Auto-generated constructor stub
}
public MyHandler(Looper looper) {
// TODO Auto-generated constructor stub
super(looper);
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
textView.setText("-接收到的内容是-->"+msg.obj);
}
}
定义一个looper对象,和MyHandler对象,参数是looper,那么会调用有参构造函数。
//Activity类有一个默认的looper对象,用来处理子线程中的消息。
Looper looper = Looper.myLooper();
handler = new MyHandler(looper);
按钮的点击事件如下:即开启一个子线程。
looperbt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new Thread(new MyThread()).start();
}
});
七.Looper的使用(二)
从主线程ui线程传递数据给子线程。
主要是用Looper的Prepare函数和loop函数实现。
在onCreate函数中,先把线程启动起来。
new Thread(new MyThread()).start();
定义Handler对象。
在按钮的点击事件中,构造消息,发送消息。
looperbt2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Message msgMessage = Message.obtain();
msgMessage.arg1 = 1;
msgMessage.arg2 =2;
msgMessage.obj = "hello";
handler.sendMessage(msgMessage);
}
});
子线程类继承自Runable类。
public class MyThread implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
//子线程中没有Looper
//所以要调用prepare函数,和loop函数,来循环执行
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
System.out.println("-接收到的内容是-->"+msg.obj);
// textView.setText("-接收到的内容是-->"+msg.obj);
}
};
Looper.loop();//循环直到队列结束
}
}
我们不能在没有Looper的时候直接获取数据,会报错,因为Looper属于主线程的,而Handler是在子线程中构造的。