Android多线程

Thread线程的实现方法

1.继承Java.lang.Thread类,重载它的run()方法,用start()函数来启动线程:

Thread thread=new Thread(new Runnable()    
        {    
            @Override    
            public void run()    
            {    
                Log.e("1111", "111111111");    
                // TODO Auto-generated method stub    
                Message message=new Message();    
                message.what=1;    
                mHandler.sendMessage(message);    
            }    
        });    
        thread.start();    
 2.实现Runnalbe接口,重载它的run()方法,用start()函数来启动线程
public class Title_Change_Demo extends Activity implements Runnable    
{    
    public Button button;    
    public LinearLayout my_layout;    
        
    public Handler mHandler=new Handler()    
    {    
        public void handleMessage(Message msg)    
        {    
            switch(msg.what)    
            {    
            case 1:    
                button.setText(R.string.text2);    
                break;    
            default:    
                break;              
            }    
            my_layout.invalidate();    
            super.handleMessage(msg);    
        }    
    };    
        
    /** Called when the activity is first created. */    
    @Override    
    public void onCreate(Bundle savedInstanceState)    
    {    
        super.onCreate(savedInstanceState);    
        setContentView(R.layout.main);    
            
        button=(Button)findViewById(R.id.button);    
        my_layout=(LinearLayout)findViewById(R.id.my_layout);    
            
        Thread thread=new Thread(this);    
        thread.start();    
    }    
        
    @Override    
    public void run()    
    {    
        Log.e("ok", "111111111");    
        // TODO Auto-generated method stub    
        Message message=new Message();    
        message.what=1;    
        mHandler.sendMessage(message);    
    }    
}    


在开发工程中线程可以帮助我们提高运行速度,Android开发中我知道的线程有4个:

1.是老生长谈的Thread

2.是Handler: Handler.post(Runnable()); Handler.postDelay(Runnable())

2.是asyncTask

3.是TimetTask

4.是Looper

5.runOnUiThread(new Runnable())

6.使用线程同步 synchronized、 wait()、notify()

四个多线程各有个的有点,Thread的运行速度是最快的,AsyncTask的规范性是最棒的,其它两个也有自己的优点,下面先贴上4个列子

1.Thread与Handler组合,比较常见

Handler主要是帮助我们来时时更新UI线程

这里在后天加载100张图片,然后没加载完成一个用handler 返回给UI线程一张图片并显示

最后加载完成返回一个List给UI线程 ,Handler就是一个后台线程与UI线程中间的桥梁


package com.android.wei.thread;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class Activity01 extends Activity {
    /** Called when the activity is first created. */
  
    /**读取进度**/
    public final static int LOAD_PROGRESS =0;
    
    /**标志读取进度结束**/
    public final static int LOAD_COMPLETE = 1;
    /**开始加载100张图片按钮**/
    Button mButton = null;
    
    /**显示内容**/
    TextView mTextView = null;
    
    /**加载图片前的时间**/
    Long mLoadStart = 0L;
    /**加载图片完成的时间**/
    Long mLoadEndt = 0L;
    
    Context mContext = null;
    /**图片列表**/
    private List<Bitmap> list;
    /**图片容器**/
    private ImageView mImageView;
    //接受传过来得消息
    Handler handler = new Handler(){
    	public void handleMessage(Message msg){
    		switch(msg.what){
    		case LOAD_PROGRESS:
    			Bitmap bitmap = (Bitmap)msg.obj;
    			mTextView.setText("当前读取到第"+msg.arg1+"张图片");
    			mImageView.setImageBitmap(bitmap);
    			break;
    		case LOAD_COMPLETE:	
    			list = (List<Bitmap>) msg.obj;
    			mTextView.setText("读取结束一共加载"+list.size()+"图片");
    			break;
    		}
    		super.handleMessage(msg);
    	}
    };
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        setContentView(R.layout.main);
        mButton =(Button) findViewById(R.id.button1);
        mTextView=(TextView) findViewById(R.id.textView1);
        mImageView =(ImageView) this.findViewById(R.id.imageview);
        mTextView.setText("点击按钮加载图片");
        mButton.setOnClickListener(new OnClickListener(){
        	public void onClick(View v){
        		//调用方法
        		LoadImage();
        	}
        });
        	
        
    }
    public void LoadImage(){
    	new Thread(){
    		public void run(){
    			mLoadStart = System.currentTimeMillis();
    			List<Bitmap> list = new ArrayList<Bitmap>();
    			for(int i =0;i<100;i++){
    				Bitmap bitmap=ReadBitmap(mContext,R.drawable.icon);
    				Message msg = new Message();
    				msg.what = LOAD_PROGRESS;
    				msg.arg1 = i+1;
    				list.add(bitmap);
    				msg.obj = bitmap;
    				handler.sendMessage(msg);
    			}
    			mLoadEndt = System.currentTimeMillis();
    			Message msg = new Message();
    			msg.what = LOAD_COMPLETE;
    			msg.obj=list;
    			msg.arg1 = (int) (mLoadEndt - mLoadStart);
    			handler.sendMessage(msg);
    			
    		}
    	}.start();
    }
    public Bitmap ReadBitmap(Context context,int resId){
    	BitmapFactory.Options opt = new BitmapFactory.Options();
    	opt.inPreferredConfig = Bitmap.Config.RGB_565;
    	opt.inPurgeable = true;
    	opt.inInputShareable = true;
    	InputStream is = context.getResources().openRawResource(resId);
    	return BitmapFactory.decodeStream(is, null, opt);
    }
}

2AsyncTask异步多线程

AsyncTask的规范型很强,能够时时反映更新的情况

它一般有这么几个方法

 * onPreExecute(), 该方法将在执行实际的后台操作前被UI 线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。
       * doInBackground(Params...), 将在onPreExecute 方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台处理工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。
      * onProgressUpdate(Progress...),在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。
      * onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute 方法将被UI 线程调用,后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户.

      * onCancelled(),在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

    1) Task的实例必须在UI 线程中创建

    2) execute方法必须在UI 线程中调用

    3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用。

    4) 该task只能被执行一次,否则多次调用时将会出现异常

package com.android.wei.thread;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;
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.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class Activity02 extends Activity{
	
	/**开始StartAsync按钮**/
	Button mButton = null;
	
	Context mContext = null;
	
	//内容显示出来
	TextView mTextView = null;
	
	//Timer 对象
	Timer mTimer = null;
	
	/** timerTask 对象**/
	TimerTask mTimerTask = null;
	
	/**记录TimerId**/
	int mTimerId =0;
	/**图片列表**/
	private List<Bitmap> list;
	/**图片容器**/
	private ImageView mImageView;
	public void onCreate(Bundle s){
		super.onCreate(s);
		setContentView(R.layout.main);
		mContext = this;
		mButton =(Button) this.findViewById(R.id.button1);
		mImageView =(ImageView)this.findViewById(R.id.imageview);
		mTextView =(TextView) this.findViewById(R.id.textView1);
		mButton.setOnClickListener(new OnClickListener(){
			public void onClick(View v){
				StartAsync();
			}
		});
		
		
	}
	public void StartAsync(){
		new AsyncTask<Object,Object,Object>(){
            protected void onPreExecute(){
            	//首先执行这个方法,它在UI线程中,可以执行一些异步操作
            	mTextView.setText("开始加载进度");
            	super.onPreExecute();
            }
			@Override
			protected Object doInBackground(Object... params) {
				// TODO Auto-generated method stub
				//异步后台执行,执行完毕可以返回出去一个结果 Object 对象
				//得到开始加载得时间
				list = new ArrayList<Bitmap>();
				for(int i =0;i<100;i++){
					Bitmap bitmap =ReadBitmap(mContext,R.drawable.icon);					
					final ByteArrayOutputStream os = new ByteArrayOutputStream();
					bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
					byte[] image = os.toByteArray();
					Bundle bundle = new Bundle();
					bundle.putInt("index", i);
					bundle.putByteArray("image", image);
					publishProgress(bundle);
					list.add(bitmap);
					
				}
				
				return list;
			}
			protected void onPostExecute(Object result){
				//doInBackground 执行之后在这里可以接受到返回结果的对象
				List<Bitmap> list = (List<Bitmap>) result;
				mTextView.setText("一共加载了"+list.size()+"张图片");
			   super.onPostExecute(result);
			}
			protected void onProgressUpdate(Object... values){
				//时时拿到当前的进度更新UI
				Bundle bundle = (Bundle)values[0];
				byte[] image = bundle.getByteArray("image");
				Bitmap bitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
				int index = bundle.getInt("index");
				mTextView.setText("当前加载进度"+index);
				mImageView.setImageBitmap(bitmap);
				super.onProgressUpdate(values);
			}
			
		}.execute();
	}
	public Bitmap ReadBitmap(Context context,int resId){
		BitmapFactory.Options opt = new BitmapFactory.Options();
		opt.inPreferredConfig = Bitmap.Config.RGB_565;
		opt.inPurgeable = true;
		opt.inInputShareable = true;
		InputStream is = context.getResources().openRawResource(resId);
		return BitmapFactory.decodeStream(is, null, opt);
	}
	
}



3.采用runOnUiThread(new Runnable()),这要实现Runnable借口,我们可以直接在这个线程中进行UI的更新。是api提供的方法,较为便捷。

new Thread(){
        @Override
        public void run() {
            final String result = LoginServices.loginByGet(username, password);
            if(result != null){
                //成功
                runOnUiThread(new Runnable() {
                     
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this, result, 0).show();
                    }
                });
            }else{
                //请求失败
                runOnUiThread(new Runnable() {
                     
                    @Override
                    public void run() {
                        // TODO Auto-generated method stub
                        Toast.makeText(MainActivity.this, "请求失败", 0).show();
                    }
                });
            }
             
        };
    }.start();


4.TimerTask

可以根据我们的设置来间隔性的运行,可以很好的实现监听功能一般也跟handler一起

package com.android.wei.thread;

import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class TimerTaskActivity extends Activity{
	/**执行Timer进度**/
	public final static int LOAD_PROGRESS =0;
	
	/**关闭TImer进度**/
	public final static int CLOSE_PROGRESS =1;
	
	/**开始TIMERTASK按钮**/
	Button mButton0 = null;
	
	/**关闭TIMERTASK按钮**/
	Button mButton1 =null;
	
	/**显示内容**/
	TextView mTextView = null;
	
	Context mContext = null;
	
	/**timer对象**/
	Timer mTimer = null;
	
	/**TimerTask对象**/
	TimerTask mTimerTask = null;
	
	/**记录TimerID**/
	int mTimerID =0;
	
	Handler handler = new Handler(){
		public void handleMessage(Message msg){
			switch(msg.what){
			case LOAD_PROGRESS:
				mTextView.setText("当前得TimerID为:"+msg.arg1);
				break;
			case CLOSE_PROGRESS:
				mTextView.setText("当前Timer已经关闭请重新启动");
				break;
			}
			super.handleMessage(msg);
		}
	};
    protected void onCreate(Bundle s){
    	setContentView(R.layout.timer);
    	mContext  = this;
    	mButton0 = (Button) this.findViewById(R.id.button1);
    	mButton1 = (Button) this.findViewById(R.id.button2);
    	mTextView = (TextView) this.findViewById(R.id.textView1);
    	mTextView.setText("点击按钮开始更新时间");
    	mButton0.setOnClickListener(new OnClickListener(){
    		public void onClick(View v){
    			StartTimer();
    		}
    	});
    	mButton1.setOnClickListener(new OnClickListener(){
    		public void onClick(View v){
    			CloseTimer();
    		}
    	});
    	super.onCreate(s);
    }
   public void StartTimer(){
	    if(mTimer == null){
	    	mTimerTask = new TimerTask(){

				@Override
				public void run() {
					mTimerID ++;
					Message msg = new Message();
					msg.what = LOAD_PROGRESS;
					msg.arg1 =(int) (mTimerID);
					handler.sendMessage(msg);
					
				}			
	    		
	    	};
	    	mTimer = new Timer();
	    	//第一个参数为执行的mTimerTask
	    	//第二个参数为延迟得事件,这里写1000得意思是 mTimerTask将延迟1秒执行
	    	//第三个参数为多久执行一次,这里写1000 表示没1秒执行一次mTimerTask的Run方法
	    	mTimer.schedule(mTimerTask, 1000,1000);
	    }
   }
   public void CloseTimer(){
	   if(mTimer !=null){
		   mTimer.cancel();
		   mTimer = null;
	   }
	   if(mTimerTask!= null){
		   mTimerTask = null;
	   }
	   mTimerID =0;
	   handler.sendEmptyMessage(CLOSE_PROGRESS);
   }
}


5.使用线程同步 synchronized、 wait()、notify()

使用线程同步机制synchronized实现多线程操作,相对来说比较复杂,但也是灵活性最佳、效率最高的一种做法,在产品开发当中也使用得最广。本人水平相当有限,也只学得一点皮毛。

synchronized相当于一把锁,当线程运行的时候,会同时有几个线程访问一个对象,对其进行操作或者修改。这可能引起很不良的后果(例如改变判定条件,或者在别的线程还没使用完的时候对象已经被析构等等),所以必须对一些对象进行加锁,保证它在同一时间只允许被一个线程访问。

synchronized使用方法有两种:

<1>同步方法在方法名前加入synchronized关键字,则该方法在同一时间内只允许一个线程访问它,其代码逻辑较为简单,但使用起来不太灵活,并且大大降低效率,耗时太长的同步方法甚至会使得多线程失去原本的意义成为单线程

<2>同步参数 对某一个代码块加锁,并且以synchronized(obj)的方式,表明该代码块内的obj对象是线程同步的。这个做法使得代码灵活性大大加强,缩小同步代码块的范围,并且可以在不同的函数体和类内进行同步,唯一遗憾的是实现起来比较复杂,容易产生一些问题

而wait()和notify(),必须在synchronized锁的代码块内执行,否则系统将会报错。

有了以上基础,就可以很容易的创建后台线程了

 

Private Runnable backgroundRunnable = new Runnable () {

      @Override   

    public   void  run()    {

            if(isFinish){

                //.....

               break;

            }

            for(;;){

                   synchronized(this){

                      //....写耗时过程

                     wait();

                    } 

          }

   }

}

UI线程中,就是一般的创建线程过程了

  Thread  backgroundThread = newThread (backgroundRunnable);

   backgroundThread.start();

这样,在后台线程中会不断的循环,当执行完一次过程以后就会wait()休眠。然后在OnTouchListener或者OnClickListener内相应的位置执行

synchronized(backgroundRunnable){

     backgroundRunnable.notify();

}

当用户触摸屏幕产生一个event的时候,线程就会被唤醒,执行下一次循环。

最后,还是内存安全问题,必须复写Activity中的OnDestory()方法,将标志量isFinish设为false,并且backgroundThread.stop()







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值