AsyncTask 很好
Uncaught handler: thread Thread-9 exiting due to uncaught exception。
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
- public class UIThreadActivity extends BaseActivity {
- /** 标签 */
- private TextView textView;
- /** Runnable */
- private Runnable runnable = new Runnable() {
- @Override
- public void run() {
- logThreadId(); // 打印当前线程ID
- textView.setText(tag + ", I'm Join!"); // 执行UI操作
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ui_thread);
- tag = "UIThreadActivity";
- textView = (TextView) findViewById(R.id.textView);
- }
- /** 1.1 UI线程阻塞 */
- public void blockUi(View v) {
- tag = "blockUi";
- logThreadId(); // 打印当前线程ID
- /* 读取网页内容并显示 */
- textView.setText("开始读取网页!"); // 该步可能未显示,为什么?
- StringBuffer document = loadHtml("http://www.google.com"); // 耗时操作:读取网页源码
- textView.setText(null == document ? "读取失败!" : document.toString()); // 显示网页源码
- /**
- * 1.观察按钮呈按下状态持续时间<br>
- * 2.尝试在按钮呈按下状态时,进行按键和触屏操作<br>
- */
- }
- /** 1.2 非主线程更新UI */
- public void updateUi(View v) {
- tag = "updateUi";
- new Thread(runnable).start();
- }
- /** 2.1 方法1:Handler */
- public void methodOne(View v) {
- tag = "methodOne";
- // Can't create handler inside thread that has not called
- // Looper.prepare();
- final Handler handler = new Handler();
- new Thread(new Runnable() {
- @Override
- public void run() {
- logThreadId(); // 打印当前线程ID
- handler.post(runnable);
- // handler.postDelayed(runnable, 1000);
- }
- }).start();
- }
- /** 2.2 方法2: View.post(Runnable) */
- public void methodTwo(View v) {
- tag = "methodTwo";
- new Thread(new Runnable() {
- @Override
- public void run() {
- logThreadId(); // 打印当前线程ID
- textView.post(runnable);
- // textView.postDelayed(runnable, 1000);
- }
- }).start();
- }
- /** 2.3 方法3:Activity.runOnUiThread(Runnable) */
- public void methodThree(View v) {
- tag = "methodThree";
- new Thread(new Runnable() {
- @Override
- public void run() {
- logThreadId(); // 打印当前线程ID
- runOnUiThread(runnable);
- }
- }).start();
- }
- /**
- * 读取网页源码
- */
- private StringBuffer loadHtml(String urlStr) {
- try {
- StringBuffer doc = new StringBuffer();
- URL url = new URL(urlStr);
- URLConnection conn = url.openConnection();
- BufferedReader reader = new BufferedReader(new InputStreamReader(
- conn.getInputStream()));
- String line = null;
- while ((line = reader.readLine()) != null)
- doc.append(line);
- reader.close();
- return doc;
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- }
- /** 1.1 Thread实现消息循环 */
- public void methodOne(View v) {
- tag = "methodOne";
- // 创建一个LooperThread对象,实现了消息循环
- LooperThread thread = new LooperThread();
- // 必须启动这个线程
- thread.start();
- // 创建一个消息对象并设置信息
- Message msg = new Message();
- Bundle bundle = new Bundle();
- bundle.putString("key", "1.1 Thread实现消息循环");
- msg.setData(bundle);
- // 发送消息对象
- thread.mHandler.sendMessage(msg);
- }
- /** 实现消息循环的线程(在Android索引文档android.os.Looper的概述里有介绍) */
- private class LooperThread extends Thread {
- public Handler mHandler;
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // process incoming messages here
- logThreadId(); // 打印当前线程ID
- Log.e(tag, msg.getData().getString("key"));
- }
- };
- Looper.loop();
- }
- }
- /** 1.2 Handler与Looper相关联 */
- public void methodTwo(View v) {
- tag = "methodTwo";
- // 生成一个HandlerThread对象,使用Looper来处理消息队列
- HandlerThread thread = new HandlerThread("MyThread");
- // 必须启动这个线程
- thread.start();
- // 将一个线程绑定到Handler对象上,则该Handler对象就可以处理线程的消息队列
- MyHandler myhandler = new MyHandler(thread.getLooper());
- // 从Handler中获取消息对象
- Message msg = myhandler.obtainMessage();
- // 设置消息对象信息
- Bundle bundle = new Bundle();
- bundle.putString("key", "1.2 Handler与Looper相关联");
- msg.setData(bundle);
- // 将消息对象发送给目标对象Handler
- msg.sendToTarget();
- }
- /** 重写Handler的消息处理方法 */
- private class MyHandler extends Handler {
- // 带有参数的构造函数
- public MyHandler(Looper looper) {
- super(looper);
- }
- @Override
- public void handleMessage(Message msg) {
- // process incoming messages here
- logThreadId(); // 打印当前线程ID
- Log.e(tag, msg.getData().getString("key"));
- }
- }
- HandlerThread wifiThread = new HandlerThread("WifiService");
- wifiThread.start();
- mWifiHandler = new WifiHandler(wifiThread.getLooper());
- /** 1.3 Hanlder与Thread实现异步 */
- public void methodThree(View v) {
- tag = "methodThree";
- /* 初始化进度条 */
- progressBar.setProgress(0);
- progressBar.setVisibility(View.VISIBLE);
- // 新线程执行某操作
- new ProgressThread(0).start();
- }
- /** 更新UI */
- private Handler myHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- progressBar.setProgress(msg.getData().getInt("key"));
- }
- };
- /** 新线程任务 */
- private class ProgressThread extends Thread {
- private int progress;
- public ProgressThread(int progress) {
- this.progress = progress;
- }
- @Override
- public void run() {
- try {
- while (progress <= 100) {
- progress += 5; // 进度+5
- // doSomething(); // 执行耗时操作
- Thread.sleep(100);
- // 从Handler中获取消息对象
- Message msg = myHandler.obtainMessage();
- // 设置消息对象信息
- Bundle b = new Bundle();
- // 向Handler发送消息,更新UI
- b.putInt("key", progress);
- msg.setData(b);
- myHandler.sendMessage(msg);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
想了解泛型类型的话,可参见我的Java泛型应用浅析一文^^。
- /** 2 Android异步线程——AsyncTask */
- public void methodFour(View v) {
- tag = "methodFour";
- new LoadHtmlTask(this).execute("http://www.baidu.com"); // 执行读取网页任务
- // new LoadHtmlTask(this).execute("http://www.google.com"); // 获取不到内容长度
- // new LoadHtmlTask(this).execute("http://www.sina.com"); // 获取大量网页数据
- }
- /** 读取网页任务 */
- private class LoadHtmlTask extends AsyncTask<String, Integer, String> {
- private Context mContext;
- private ProgressDialog dialog; // 进度框
- public LoadHtmlTask(Context context) {
- this.mContext = context;
- initDialog(); // 初始化进度对话框
- }
- /** 初始化进度对话框 */
- private void initDialog() {
- dialog = new ProgressDialog(mContext);
- dialog.setMax(100); // 设置最大进度值
- dialog.setTitle("Loading..."); // 设置标题
- dialog.setCancelable(false); // 设为返回键不可取消
- dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); // 设为进度条样式
- // 增加取消按钮及其事件
- dialog.setButton("取消", new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int i) {
- dialog.dismiss(); // 取消显示
- cancel(true); // 取消并中断任务
- }
- });
- }
- /** doInBackground之前,在主线程执行 */
- @Override
- protected void onPreExecute() {
- logThreadId("onPreExecute()"); // 打印当前线程ID
- dialog.show(); // 显示进度对话框
- }
- /** onPreExecute()之后,在后台线程执行 */
- @Override
- protected String doInBackground(String... params) {
- logThreadId("doInBackground"); // 打印当前线程ID
- // 未传入参数直接返回
- if (null == params || params.length <= 0) {
- return "请确认输入了网址参数!";
- }
- try {
- // 创建HttpGet对象,params[0]为url
- HttpGet httpGet = new HttpGet(params[0]);
- // 发送Http Get请求,并返回HttpResponse对象
- HttpResponse response = new DefaultHttpClient()
- .execute(httpGet);
- // 判断响应状态,200表示成功响应
- if (response.getStatusLine().getStatusCode() == 200) {
- HttpEntity entity = response.getEntity(); // 获取返回结果
- long length = entity.getContentLength(); // 获取内容长度(google获取不到)
- boolean getLen = length > 0 ? true : false; // 判断是否获取了内容长度
- InputStream is = entity.getContent(); // 获取响应内容
- if (is != null) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buf = new byte[128];
- int ch = -1;
- long count = 0;
- while ((ch = is.read(buf)) != -1 && !isCancelled()) { // 同时还未取消
- baos.write(buf, 0, ch);
- count += ch;
- if (getLen) { // 获取了内容长度时
- // 调用publishProgress()更新进度
- publishProgress((int) ((count / (float) length) * 100));
- }
- }
- is.close();
- baos.close();
- return new String(baos.toByteArray()); // 返回结果
- }
- return "无返回内容!";
- } else {
- return "服务器未响应或失败!";
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "程序异常啦!";
- }
- /** 调用了publishProgress(),在主线程执行 */
- @Override
- protected void onProgressUpdate(Integer... values) {
- // logThreadId("onProgressUpdate"); // 打印当前线程ID
- dialog.setProgress(values[0]);
- }
- /** 未调用了cancel(),doInBackground()结束后,在主线程执行 */
- @Override
- protected void onPostExecute(String result) {
- logThreadId("onPostExecute(result)"); // 打印当前线程ID
- dialog.dismiss(); // 取消显示
- showMsg(result); // 显示结果
- }
- /** 调用了cancel(),doInBackground()结束后,在主线程执行 */
- @Override
- protected void onCancelled() {
- logThreadId("onCancelled"); // 打印当前线程ID
- showMsg("用户取消了该任务!");
- }
- /** 提示框显示消息 */
- private void showMsg(String message) {
- // message内容过多时,提示框显示会延迟,例如sina
- new AlertDialog.Builder(mContext)
- .setTitle("消息")
- .setMessage(message)
- .setNegativeButton("关闭",
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog,
- int which) {
- dialog.dismiss();
- }
- }).show();
- }
- }
- private Handler handler; // Handler
- Override
- public void onCreate() {
- Log.i("onCreate", "==onCreate==");
- super.onCreate();
- handler = new Handler(Looper.getMainLooper()); // 使用应用的主消息循环
- }
- /**
- * Toast提示(service中toast不能直接显示)
- */
- private void showToast(final int resId, final Object... formatArgs) {
- handler.post(new Runnable() {
- public void run() {
- Toast.makeText(getApplicationContext(),
- getString(resId, formatArgs), Toast.LENGTH_SHORT)
- .show();
- }
- });
- // 以下方式只能显示一次
- // Looper.prepare();
- // Toast.makeText(this, resId, Toast.LENGTH_SHORT).show();
- // Looper.loop();
- }
- public class TestPool implements Runnable {
- private static final String TAG = "TestPool"; // 标记
- private ExecutorService service; // 线程池
- public TestPool() {
- // service = Executors.newSingleThreadExecutor(); // 创建一个单任务线程池
- service = Executors.newFixedThreadPool(3); // 创建最多同时运行3个任务线程池
- }
- /** 增加一个线程任务 */
- public void addTask() {
- service.execute(this);
- }
- /** 线程任务 */
- @Override
- public void run() {
- log(1); // 显示日志
- try {
- Thread.sleep(5 * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- log(2); // 显示日志
- }
- /** 显示日志 */
- private void log(int which) {
- String result = 1 == which ? ",任务开始!" : ",任务结束!";
- Log.e(TAG, "线程:" + String.valueOf(Thread.currentThread().getId())
- + result);
- }
- }
- public class TestSync {
- private Product product;
- private Consumer ConsumerA, ConsumerB;
- public TestSync() {
- product = new Product();
- ConsumerA = new Consumer("小怪兽A", product);
- ConsumerB = new Consumer("小怪兽B", product);
- }
- public void produce() {
- synchronized (product) {
- Log.e("TestSync", "\\(^o^)/,投掷一个果冻!");
- product.plus(); // 增加一个产品
- /* 优先使用notifyAll(),更容易让jvm找到最适合被唤醒的线程 */
- // product.notify(); // 唤醒一个线程
- product.notifyAll(); // 唤醒所有线程
- }
- }
- public void start() {
- ConsumerA.start();
- ConsumerB.start();
- }
- public void stop() {
- ConsumerA.stopEating();
- ConsumerB.stopEating();
- synchronized (product) {
- product.notifyAll(); // 唤醒所有线程
- }
- }
- }
- /** 产品 */
- class Product {
- private int count = 0; // 产品数量
- public Product() {
- }
- /** 是否无产品 */
- public boolean isNull() {
- return count <= 0 ? true : false;
- }
- /** 增加产品 */
- public void plus() {
- count++;
- }
- /** 减少产品 */
- public void minus() {
- count--;
- }
- }
- /** 消费者 */
- class Consumer extends Thread {
- private String name; // 消费者
- private Product product; // 产品
- private int count = 0; // 数量
- private boolean waitEating = true; // 标记
- public Consumer(String name, Product product) {
- this.name = name;
- this.product = product;
- }
- @Override
- public void run() {
- while (waitEating) {
- synchronized (product) {
- while (product.isNull() && waitEating) {
- try {
- Log.e(name, "(¯﹃¯),等待果冻中...");
- product.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- if (waitEating) {
- Log.e(name, "~\\(≧▽≦)/~,抢到了果冻!");
- product.minus();
- count++;
- }
- }
- }
- Log.e(name, "(~ o ~)~zZ,吃不下了。计:" + count);
- }
- public void stopEating() {
- waitEating = false;
- }
- }
转载于:https://blog.51cto.com/4610653/840370
AsyncTask 很好相关推荐
- [学习总结]7、Android AsyncTask完全解析,带你从源码的角度彻底理解
我们都知道,Android UI是线程不安全的,如果想要在子线程里进行UI操作,就需要借助Android的异步消息处理机制.之前我也写过了一篇文章从源码层面分析了Android的异步消息处理机制,感兴 ...
- Android AsyncTask源码解析
在开发Android应用时必须遵守单线程模型的原则: Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行.在单线程模型中始终要记住两条法则: 1. 不要阻塞UI线程 2. 确保只 ...
- AsyncTask原理
为什么要用AsyncTask 我们知道,Android应用的主线程(UI 线程,是线程不安全的,负责前台用户界面的绘制以及响应用户的操作)肩负着绘制用户界面和及时响应用户操作的重任,为了避免" ...
- Android高级:内部类的理解,多态,run和start,wait和seelp,线程安全,堆和栈,synchronized 和volatile ,AsyncTask,Binder的机,view的原理
目录 成员内部类.静态内部类.局部内部类和匿名内部类的理解,以及项目中的应用 哪些情况下的对象会被垃圾回收机制处理掉? Java中实现多态的机制是什么? String为什么要设计成不可变的? Obje ...
- Android性能优化典范第五季
原文链接:http://hukai.me/android-performance-patterns-season-5/ 前言 本季内容大致有:多线程并发的性能问题,介绍了AsyncTask,Handl ...
- android系统优化(18)--系统性能优化第5季
1)Threading Performance 在程序开发的实践当中,为了让程序表现得更加流畅,我们肯定会需要使用到多线程来提升程序的并发执行性能.但是编写多线程并发的代码一直以来都是一个相对棘手的问 ...
- Android性能优化典范(五)
作者简介: 胡凯(@胡凯me),腾讯Android工程师,热爱开源与分享,维护Android官方培训课程协作项目,关注Android应用性能优化的总结与分享,推崇Android官方最佳实践.个人博客: ...
- Android面试题线程篇
Android面试题线程篇,由本人整理汇总,后续将推出系列篇,如果喜欢请持续关注和推荐. 开启线程的三种方式? java有三种创建线程的方式,分别是继承Thread类.实现Runable接口和使用线程 ...
- 《疯狂Android讲义》学习笔记一
接触Android一年了,自学了不久就到公司里实习了,在公司的项目毕竟还是模块级的,很多Android基础知识平常接触不到.最近想想通过读一些书,如<疯狂Android讲义>.<An ...
最新文章
- AlarmManager与PendingIntent的联合使用(二)
- activemq配置与启动
- lnmp yum安装mysql_centos5 yum安装lnmp
- CS231n课程笔记5.4:超参数的选择交叉验证
- 用awk 取出ifconfig eth0中IP的方法
- 软件架构-里氏替换原则
- Python学习札记(八) Basic5 循环
- commons-httpclient 实现get和post请求
- word字体放大后只显示一半_word字体显示不全或是显示一半怎么回事如何解决
- Wii 补充运动利器
- 在实时控制系统中使用传感器优化数据可靠性的3个技巧
- minecraft_如何轻松地在Minecraft版本之间切换
- 深度学习 黑白图片 着色
- 四个月宝宝厌奶期症状?
- Java调用用户芝麻信用分
- 通过跟踪源码证明在Java中通过执行Start()方法创建线程
- Android Studio Codota安装
- 最新代千元机!Redmi Note 9正式发布:性能提升100% 1299元起售!
- 快手+中科大 | 全曝光推荐数据集KuaiRec 2.0版本
- java实现蒲丰投针求_蒲丰投针问题