android多线程学习

老罗视频学习笔记。


一.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是在子线程中构造的。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值