摘要:本文将带你了解Android 开发之线程交互,希望本文对大家学Android有所帮助。
在Android开发过程中,耗时操作是不允许写在主线程(UI线程)中的,以免由于等待时间过长而发生ANR。所以耗时操作需要创建子线程来完成,然而往往这些操作都需要与主线程进行通讯交互(例如更新主线程的UI),但android规定除了UI线程外,其他线程都不可以对UI控件进行访问或操控,所以我们需要通过一些方法来实现这些功能。
1. Handler:
handler是android中专门用来在线程之间传递信息类的工具。
1、在B线程中调用Looper.prepare和Looper.loop。(主线程不需要)
2、编写Handler类,重写其中的handleMessage方法。
3、创建Handler类的实例,并绑定looper
4、调用handler的sentMessage方法发送消息。
· 子线程更新主线程(UI)
因为主线程自带Looper机制,所有我们不用创建Looper:
Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: //do something,refresh UI; break; default: break; } } }; 然后开启一个子线程,在子线程里直接使用Handler发送消息: new Thread() { public void run() { Message message = new Message(); message.what = 1; message.obj = "子线程发送的消息Hi~Hi"; mHandler .sendMessage(message); }; }.start(); · 子线程之间交互 public class ThreadActivity extends AppCompatActivity { private final String TAG = "ThreadActivity"; // 子线程Handler private Handler mSubHandler = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_thread1); new MyThread().start(); createThread(); } /** * 创建子线程,用于发送消息 */ private void createThread() { new Thread() { @Override public void run() { int count = 0; while (count < 10) { Message msg = new Message(); msg.obj = "子线程计时器:" + count; msg.what = 1; // 使用子线程Handler发送消息 mSubHandler.sendMessage(msg); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } count++; } } }.start(); } /** * 用于接收子线程发送过来的消息 */ class MyThread extends Thread { @Override public void run() { Looper.prepare(); mSubHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Log.i(TAG, (String) msg.obj); break; } } }; Looper.loop(); } }} 2. HandlerThread: HandlerThread是一个包含Looper的Thread,我们可以直接使用这个 Looper 创建 Handler。 API参考:https://developer.android.google.cn/reference/android/os/HandlerThread HandlerThread适用于单线程+异步队列模型场景,相对Handler + Thread简洁。 // 也可实现run方法HandlerThread mHandlerThread = new HandlerThread("HandlerThread_Test"); mHandlerThread.start(); Handler mThreadHandler = new Handler(mHandlerThread.getLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: Log.i(TAG, "threadName--" + Thread.currentThread().getName() + (String) msg.obj); break; } } }; // 发送消息至HanderThread mThreadHandler.sendMessage(msg); 3. runOnUiThread Activity 里面的runOnUiThread( Runnable )方法使子线程更新UI更为简洁。另外还有View.Post(Runnable)和View.PostDelayed(Runnabe,long)方法,用法与runOnUiThread基本相同。 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); } runOnUiThread(new Runnable() { @Override public void run() { // 执行UI操作 Toast.makeText(MainActivity.this, "Test", Toast.LENGTH_SHORT).show(); } }); } }).start(); 4. AsyncTask API参考:https://developer.android.google.cn/reference/android/os/AsyncTask AsyncTask是一个抽象类,它是由Android封装的一个轻量级异步类。它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并在主线程中更新UI。AsyncTasks应该用于短操作(最多几秒)。如果您需要保持线程长时间运行,强烈建议您使用java.util.concurrent包提供的各种API,例如Executor,ThreadPoolExecutor和FutureTask。 异步任务由3个泛型类型定义:Params,Progress和Result,以及4个步骤:onPreExecute,doInBackground,onProgressUpdate和onPostExecute组成。 使用AsyncTask时需要继承AsyncTask类并必须实现doInBackground(params...)方法,大多数情况下还需要实现onPostExecute(Result)方法。 private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } 创建成功后执行任务非常简单: new DownloadFilesTask().execute(url1, url2, url3); // Params AsyncTask的泛型类型: · Params:在执行时传递给任务的参数类型; · Progress:异步任务执行过程中,返回执行进度值的类型; · Result:后台任务执行结果类型。 并非所有类型都必须在异步任务中使用,如果不需要使用,则用Void来代替。 rivate class MyTask extends AsyncTask<Void, Void, Void> { ... } 当执行一个异步任务时,需要经历4个步骤: · onPreExecute():在异步任务执行前,在UI主线和中调用。此步骤通常用于设置任务,例如在用记界面中显示进度条。 · doInBackground(Params...):onPreExecute()执行完后,立即在后台线程中调用此方法。此步骤用于执行运行时间可能较长的后台任务,参数由execute(params...)传入。通过此步骤得到结果并返回到最后一步。在计算过程中,可通过调用publishProgress(Progress...)方法,并通过onProgressUpdate(Progress...)更新UI显示任务执行进度。 · onProgressUpdate(Progress...):当publishProgress(Progress...)方法执行后,此步骤在UI主线程中被调用,并更新UI当前任务进度。 · onPostExecute(Result):在后台线程计算完成后在UI线程上调用。 后台线程计算的结果作为参数传递给此步骤。 AsyncTask还提供了cancelled(boolean)方法,它同样在主线程中执行,当异步任务取消时,onCancelled()会被调用,这个时候onPostExecute()则不会被调用,但是要注意的是,AsyncTask中的cancel(boolean)方法并不是真正去取消任务,只是设置这个任务为取消状态,我们需要在doInBackground()判断终止任务。就好比想要终止一个线程,调用interrupt()方法,只是进行标记为中断,需要在线程内部进行标记判断然后中断线程。参数true表示立即取消任务(不一定成功),false则表示允许任务执行完成后再取消。 使用AsyncTask还需要注意以下问题: · 异步任务的实例必须在UI线程中创建,即AsyncTask对象必须在UI线程中创建。 · execute(Params...) 必须在UI线程上执行。 · 不要手动调用onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...)方法。 · 该任务只能执行一次(如果尝试执行第二次,则会引发异常)。 · 不能在doInBackground(Params... params)中更改UI组件的信息。 · AsyncTask不与任何组件绑定生命周期,所以在Activity/或者Fragment中创建执行AsyncTask时,最好在Activity/Fragment的onDestory()调用 cancel(boolean); · 如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。 · 屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask(非静态的内部类)会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。 AsyncTask里面有两种线程池供我们调用,默认使用SERIAL_EXECUTOR。AsyncTask的核心线程是5,队列容量是128,最大线程数是9。 · THREAD_POOL_EXECUTOR, 异步线程池。 · SERIAL_EXECUTOR,同步线程池。 一个简单的AsyncTask例子: 自定义AsyncTask: class TestAsyncTask extends AsyncTask<Integer, Integer, Integer> { @Override protected Integer doInBackground(Integer... integers) { int count = integers[0]; int len = integers[1]; while (count < len) { int pro = 100 * count / len; Log.i(TAG, "----------" + pro + ":" + count + ":" + len); publishProgress(pro); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } count++; } return count; } @Override protected void onProgressUpdate(Integer... values) { mText.setText("Progress:" + values[0] + "%"); } @Override protected void onPostExecute(Integer integer) { mText.setText("Finished:" + integer + "%"); } } 创建TestAsyncTask实例: mAsyncTask.execute(0, 100);
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号