线程异步、接口回调


一、线程的实现(异步机制、耗时操作)

Thread:
Runnable:
Handler:
在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,
实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成
Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。
AsyncTask:
(1)首先明确Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),
且UI的更新只能在主线程中完成,因此异步处理是不可避免的。
轻量级的异步类,实现异步操作,可以实现异步请求和主界面更新(线程池+handler)

        package com.itheima.zhbj74.utils;
  import java.io.IOException;
  import java.io.InputStream;
  import java.net.HttpURLConnection;
  import java.net.MalformedURLException;
  import java.net.URL;
  import android.graphics.Bitmap;
  import android.graphics.BitmapFactory;
  import android.os.AsyncTask;
  import android.widget.ImageView;
  /**
  * 网络缓存
  * 
  * @author Kevin
  * @date 2015-10-24
  */
  public class NetCacheUtils {
   private LocalCacheUtils mLocalCacheUtils;
   private MemoryCacheUtils mMemoryCacheUtils;
   public NetCacheUtils(LocalCacheUtils localCacheUtils,
     MemoryCacheUtils memoryCacheUtils) {
    mLocalCacheUtils = localCacheUtils;
    mMemoryCacheUtils = memoryCacheUtils;
   }
   public void getBitmapFromNet(ImageView imageView, String url) {
    // AsyncTask 异步封装的工具, 可以实现异步请求及主界面更新(对线程池+handler的封装)
    new BitmapTask().execute(imageView, url);// 启动AsyncTask
   }
   /**
   * 三个泛型意义: 
   第一个泛型:doInBackground里的参数类型 
   第二个泛型:onProgressUpdate里的参数类型 
   第三个泛型:onPostExecute里的参数类型及doInBackground的返回类型
   * 
   * @author Kevin
   * @date 2015-10-24
   */
   class BitmapTask extends AsyncTask<Object, Integer, Bitmap> {
    private ImageView imageView;
    private String url;
    // 1.预加载, 运行在主线程
    @Override
    protected void onPreExecute() {
     super.onPreExecute();
     // System.out.println("onPreExecute");
    }
    // 2.正在加载, 运行在子线程(核心方法), 可以直接异步请求,
    //通过exccute()方法传入参数
    @Override
    protected Bitmap doInBackground(Object... params) {
     // System.out.println("doInBackground");
     imageView = (ImageView) params[0];
     url = (String) params[1];
     imageView.setTag(url);// 打标记, 将当前imageview和url绑定在了一起
     // 开始下载图片
     Bitmap bitmap = download(url);
     // publishProgress(values) 调用此方法实现进度更新(会回调onProgressUpdate)
     return bitmap;
    }
    // 3.更新进度的方法, 运行在主线程
    @Override
    protected void onProgressUpdate(Integer... values) {
     // 更新进度条
     super.onProgressUpdate(values);
    }
    // 4.加载结束, 运行在主线程(核心方法), 可以直接更新UI
    @Override
    protected void onPostExecute(Bitmap result) {
     // System.out.println("onPostExecute");
     if (result != null) {
      // 给imageView设置图片
      // 由于listview的重用机制导致imageview对象可能被多个item共用,
      // 从而可能将错误的图片设置给了imageView对象
      // 所以需要在此处校验, 判断是否是正确的图片
      String url = (String) imageView.getTag();
      if (url.equals(this.url)) {// 判断图片绑定的url是否就是当前bitmap的url,
             // 如果是,说明图片正确
       imageView.setImageBitmap(result);
       System.out.println("从网络加载图片啦!!!");
       // 写本地缓存
       mLocalCacheUtils.setLocalCache(url, result);
       // 写内存缓存
       mMemoryCacheUtils.setMemoryCache(url, result);
      }
     }
     super.onPostExecute(result);
    }
   }
   // 下载图片
   public Bitmap download(String url) {
    HttpURLConnection conn = null;
    try {
     conn = (HttpURLConnection) new URL(url).openConnection();
     conn.setRequestMethod("GET");
     conn.setConnectTimeout(5000);// 连接超时
     conn.setReadTimeout(5000);// 读取超时
     conn.connect();
     int responseCode = conn.getResponseCode();
     if (responseCode == 200) {
      InputStream inputStream = conn.getInputStream();
      // 根据输入流生成bitmap对象
      Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
      return bitmap;
     }
    } catch (MalformedURLException e) {
     e.printStackTrace();
    } catch (IOException e) {
     e.printStackTrace();
    } finally {
     if (conn != null) {
      conn.disconnect();
     }
    }
    return null;
   }
  }
 
 
 
其他实现:
1、利用Handler发送延时消息
 
new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
    model.executeWork(flowId, runNodeId, executeListener);
    }
   }, 300);
 
 
 
 
2、首先runOnUiThread是Activity内部的方法,在运用的时候最好指明当前环境变(Context).
 
(1) new Thread(new Runnable() {
   @Override
   public void run() {
   System.out.println(Thread.currentThread().getId());
   runOnUiThread(new Runnable() {
   @Override
   public void run() {
   Toast.makeText(RunOnUIThreadActivity.this, "UI操作...", 1000).show(); 
   }
   });
   }
   }).start();
  (2) new Thread(new Runnable() {
    @Override
    public void run() {
     if(isClose)
     return;
     if(i!=0)
     Toast.makeText(RunOnUIThreadActivity.this, i+"", 1000).show(); 
     i++;
     handler.postDelayed(this, 2000);
    }
   }).start(); 
 
 
 
上面两个其实原理一样,runOnUiThread这个会调用父类中的
 
public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
    mHandler.post(action);
    } else {
    action.run();
    }
   }
 
 
首先判断是否是UI线程,不是的话就post,如果是的话就正常运行该线程.
只要经过主线程中的Handler.post或者postDelayed处理线程runnable则都可以将其转为UI主线程.
再说Handler的机制就是来处理线程与UI通讯的.
 
 

二、接口与回调

接口与回调就是传值、通知的过程
1、以内部类的形式
 
class A{
  int i=0;
  //2、声明接口变量
  private Inner inner;
  //1、定义接口(可以新建一个)
  public interface Inner{
   public void method(int i);
  }
  //3、设置回调监听
  public void setInner(Inner inner){
   this.inner=inner;
  }
  //4、回调接口方法
  public void CallBack(){
   inner.method(i);
  }
 }
 class B{
  setInner(new Inner(){
   public void method(int i){
    //根据需求处理变量i
   }
  });
 }
 
 
 
2、各个类的形式

//传递数据的接口
public interface Inner(){
    void method(int i);
}
//持有数据的类
public class A{
    protected Inner inner;
    //给inner赋值
    public void setInner(Inner inner){
        this.inner=inner;
    }
    //给最终的结果赋值
    public void setData(int result){
        inner.method(result);以调用方法接口的形式
    }
}
//想要获取数据的类
public class B implements Inner{
    A a=new A();
    a.setInner(this);
    @Override
    void method(int i){
        ......;//获取到数据i,以重写接口方法的形式
    }
}
 
 

三、同步和异步的区别

1、Java关键字volatile(不稳定):
    在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。
代码示例:

public class TestWithVolatile { 
    private static volatile boolean bChanged; 
 
    public static void main(String[] args) throws InterruptedException { 
        new Thread() { 
 
            @Override 
            public void run() { 
                for (;;) { 
                    if (bChanged == !bChanged) { 
                        System.out.println("!="); 
                        System.exit(0); 
                    }  
                }  
            }  
        }.start(); 
        Thread.sleep(1); 
        new Thread() { 
 
            @Override 
            public void run() { 
                for (;;) { 
                    bChanged = !bChanged; 
                }  
            }  
        }.start(); 
    }  
 
}  
 
 
 
 
 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM