android中的线程

来源:互联网 发布:淘宝旅行网火车 编辑:程序博客网 时间:2024/05/22 06:21

    通常Android运行时只有一个线程,就是UI主线程,负责更新ui,也可以处理一些逻辑工作,但遇到复杂的工作,就不可以直接丢给主线程来处理,不然UI线程就会卡在那,导致系统无响应。

    android中多线程实现主要依靠Handler和AsyncTask。


Hander的例子

首先看一下将复杂操作直接放在UI进程的例子.这里的复杂计算是计算圆周率。

布局文件,界面上只有一个非常嘲讽的Button。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <Button        android:id="@+id/button1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentTop="true"        android:layout_marginRight="20dp"        android:layout_marginTop="30dp"        android:text="求点我!" /></RelativeLayout>


然后看MainActivity

package com.empty.threaddemo;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private Button mButton;private Runnable mRunnable;private Handler mHandler;double result;private int count = 0; private int i = 0; public static final int FINISHED= 0x000001;  private static final String TAG = "ThreadDemo"; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton=(Button)findViewById(R.id.button1);mButton.setOnClickListener(new MyButtonListener());}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}class MyButtonListener implements OnClickListener{   @Override  public void onClick(View v) {result=getPI(100000000);new AlertDialog.Builder(MainActivity.this)  .setTitle("result").setMessage(""+result).setIcon(android.R.drawable.ic_dialog_info).setCancelable(true) .show();}  } public double getPI(int time){ float result=0; for(int i=1;i<=time;i++){double value=4.0/(2*i-1);if (i % 2 == 1) result+=value;else result-=value; }return result;}}


编译,运行,点Button,然后发现被坑了...



点击按钮后,UI线程就被阻塞用于计算PI,由于耗时太久,系统直接无响应了。


下面使用Handler来改进,先复习一下Handler的用法:

1)在Activity或Activity的Widget中开发Handler类的对象,并重写handleMessage方法。
2)在新启动的线程中调用sendEmptyMessage或者sendMe ssage方法向Handler发送消息。
3)Handler类的对象用handleMessage方法接收消息,然后根据消息的不同执行不同的操作。

MainActivity改写之后变成这样:

package com.empty.threaddemo;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {private Button mButton;private Runnable mRunnable;private Handler mHandler;double result;private int count = 0; private int i = 0; public static final int FINISHED= 0x000001;  private static final String TAG = "ThreadDemo"; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton=(Button)findViewById(R.id.button1);mButton.setOnClickListener(new MyButtonListener());mHandler =  new Handler(){@Override  public void handleMessage(Message msg) {  if (msg.what == FINISHED) {  new AlertDialog.Builder(MainActivity.this)  .setTitle("Result").setMessage(""+result).setIcon(android.R.drawable.ic_dialog_info).setCancelable(true) .show(); }  super.handleMessage(msg);  }  };new MyThread().start(); }@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}class MyButtonListener implements OnClickListener{   @Override  public void onClick(View v) {new AlertDialog.Builder(MainActivity.this)  .setTitle("爽!").setIcon(android.R.drawable.ic_dialog_info).setCancelable(true) .show();}  } public double getPI(int time){ float result=0; for(int i=1;i<=time;i++){double value=4.0/(2*i-1);if (i % 2 == 1) result+=value;else result-=value; }return result;}public class MyThread extends Thread {  public void run() {  Message msg = new Message(); msg.what = FINISHED;result=getPI(100000000);mHandler.sendMessage(msg); }  }  }


程序运行的过程是:当Activity启动的时候,初始化了一些View,同时创建了一个handler用于处理消息,最后启动了一个Thread,计算PI放在了Thread中而不是占用UI线程,所以Button一直可以与用户进行交互。当计算完成的时候,Handler会接受到来自Thread的Message,Handler处理消息,更新UI,即弹出对话框。

         


使用AsyncTask

先大概认识下Android.os.AsyncTask类:
* android的类AsyncTask对线程间通讯进行了包装,提供了简易的编程方式来使后台线程和UI线程进行通讯:后台线程执行异步任务,并把操作结果通知UI线程。
* AsyncTask是抽象类.AsyncTask定义了三种泛型类型 Params,Progress和Result。
  * Params 启动任务执行的输入参数,比如HTTP请求的URL。
  * Progress 后台任务执行的百分比。
  * Result 后台执行任务最终返回的结果,比如String,Integer等。
* AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,开发者需要实现这些方法。
  * 1) 继承AsyncTask
  * 2) 实现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只能被执行一次,否则多次调用时将会出现异常
doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

修改上面的例子,用AsyncTask来实现。

修改一下布局文件,添加一个进度条。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity" >    <ProgressBar        android:id="@+id/pb"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_below="@+id/button1"        android:layout_marginTop="20dp" />    <Button        android:id="@+id/button1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentLeft="true"        android:layout_alignParentTop="true"        android:layout_marginTop="26dp"        android:text="独孤求点" />    <TextView        android:id="@+id/textView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignBaseline="@+id/button1"        android:layout_alignBottom="@+id/button1"        android:layout_marginLeft="54dp"        android:layout_toRightOf="@+id/button1"        android:text="TextView" /></RelativeLayout>

然后是MainActivity.

package com.empty.threaddemo;import android.os.AsyncTask;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.Intent;import android.util.Log;import android.view.Menu;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {private Button mButton;private Handler mHandler;private ProgressBar pb;private TextView resultView;double result;private int TIME= 10000; private int i = 0; public static final int FINISHED= 0x000001;  private static final String TAG = "ThreadDemo"; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mButton=(Button)findViewById(R.id.button1);mButton.setOnClickListener(new MyButtonListener());pb=(ProgressBar)findViewById(R.id.pb);resultView=(TextView)findViewById(R.id.textView1);CalculateTask dTask = new CalculateTask();           dTask.execute(); }@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.activity_main, menu);return true;}class MyButtonListener implements OnClickListener{   @Override  public void onClick(View v) {new AlertDialog.Builder(MainActivity.this)  .setTitle("爽!").setIcon(android.R.drawable.ic_dialog_info).setCancelable(true) .show();}  }  class CalculateTask extends AsyncTask<Integer, Integer, String>{          //后面尖括号内分别是参数(例子里是线程休息时间),进度(publishProgress用到),返回值 类型                    @Override          protected void onPreExecute() {              //第一个执行方法          Toast.makeText(getApplicationContext(), "Begin calculate!", Toast.LENGTH_SHORT).show();            super.onPreExecute();          }                    @Override          protected String doInBackground(Integer... params) {              //第二个执行方法,onPreExecute()执行完后执行              for(int i=1;i<=TIME;i++){              double value=4.0/(2*i-1);    if (i % 2 == 1) result+=value;    else result-=value;        publishProgress((int) (100*(i*1.0/TIME)));     }             return ""+result;          }            @Override          protected void onProgressUpdate(Integer... progress) {              //这个函数在doInBackground调用publishProgress时触发,虽然调用时只有一个参数              //但是这里取到的是一个数组,所以要用progesss[0]来取值              //第n个参数就用progress[n]来取值          pb.setProgress(progress[0]);           resultView.setText(progress[0]+"%");              super.onProgressUpdate(progress);          }            @Override          protected void onPostExecute(String r) {              //doInBackground返回时触发,换句话说,就是doInBackground执行完后触发              //这里的result就是上面doInBackground执行后的返回值,所以这里是"执行完毕"              //setTitle(result);            resultView.setText(r);            super.onPostExecute(r);          }                }  }

运行结果:

    


运行过程:Activity初始化之后,直接开一个创建一个task在后台跑,一边跑一边通过 onProgressUpdate方法更新UI,与此同时,UI线程还是可以响应Button。

最后当task运行完之后回调onPostExecute方法显示结果。


Thread中的run和start

run()方法相当于调用你那个类的一个方法了,即使你没有实现Runnable接口写个run方法进行调用,与调用run方法是一样的,并不会开启一个线程,就相当于还是在主线程中执行任务,开启线程必须用Start方法,他自己去调run方法。


参考

Android中AsyncTask的简单用法-http://blog.csdn.net/cjjky/article/details/6684959

原创粉丝点击