Android 建立线程 Thread详细使用方法
2014-11-04 14:25
696 查看
转载,感谢你原作者
注:建立线程很好学习的教材,本人还是建立采用第二种方法,继承Thread类的方法,这样可以面向对象的方法,使用和灵活性更好
1.创建Android线程
参考官方文档是个好习惯。http://developer.android.com/reference/java/lang/Thread.html
http://developer.android.com/guide/components/processes-and-threads.html
创建线程有两种方式:一是在创建线程的时候传入一个Runnable对象,另一种是继承Thread类,实现run()方法。这两种方法没啥区别嘛。。。
Game start....
(1)用Runnable对象
源码MainActivity.java
[java] view
plaincopy
package com.example.siqi;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/**
* 线程1
*/
new Thread(new Runnable(){
@Override
public void run() {
int cnt = 10;
while(cnt>0) {
Log.d("Thread1", "Thread one cnt: " + cnt--);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}).start();
/**
* 线程2
*/
new Thread(new Runnable(){
@Override
public void run() {
int cnt = 10;
while(cnt>0) {
Log.d("Thread2", "Thread two cnt: " + cnt--);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}).start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
结果:
[java] view
plaincopy
11-07 16:30:07.844: D/Thread1(13237): Thread one cnt: 10
11-07 16:30:07.873: D/Thread2(13237): Thread two cnt: 10
11-07 16:30:08.043: D/Thread1(13237): Thread one cnt: 9
11-07 16:30:08.173: D/Thread2(13237): Thread two cnt: 9
11-07 16:30:08.244: D/Thread1(13237): Thread one cnt: 8
11-07 16:30:08.443: D/Thread1(13237): Thread one cnt: 7
11-07 16:30:08.483: D/Thread2(13237): Thread two cnt: 8
11-07 16:30:08.680: D/Thread1(13237): Thread one cnt: 6
11-07 16:30:08.818: D/Thread2(13237): Thread two cnt: 7
11-07 16:30:08.887: D/Thread1(13237): Thread one cnt: 5
11-07 16:30:09.095: D/Thread1(13237): Thread one cnt: 4
11-07 16:30:09.164: D/Thread2(13237): Thread two cnt: 6
11-07 16:30:09.303: D/Thread1(13237): Thread one cnt: 3
11-07 16:30:09.528: D/Thread2(13237): Thread two cnt: 5
11-07 16:30:09.528: D/Thread1(13237): Thread one cnt: 2
11-07 16:30:09.735: D/Thread1(13237): Thread one cnt: 1
11-07 16:30:09.875: D/Thread2(13237): Thread two cnt: 4
11-07 16:30:10.217: D/Thread2(13237): Thread two cnt: 3
11-07 16:30:10.558: D/Thread2(13237): Thread two cnt: 2
11-07 16:30:10.904: D/Thread2(13237): Thread two cnt: 1
从结果我们可以看出,这两个线程的确是并行运行的。
(2)定义一个Thread
MainActivity.java
[java] view
plaincopy
package com.example.siqi;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {
/**
*定义一个简单的线程SimpleThread
*/
public class SimpleThread extends Thread {
@Override
public void run() {
int cnt = 10;
while(cnt>0) {
Log.d("Thread", "Thread cnt: " + cnt--);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SimpleThread thread1 = new SimpleThread();
SimpleThread thread2 = new SimpleThread();
thread1.start();
thread2.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
运行结果,突然发现截图比较不错:
可以看到是有两个线程14912和14913都在运行。
接下来,我们需要了解一下,为什么需要线程。
2.线程啊线程
Android中有一个UI线程,这个线程专门负责用户可以看到的和接触到的内容,比如图片啊,Button等。Google为了提高界面的流畅度和体验,禁止阻塞UI线程。什么意思呢,比如我要在界面上显示一张图片,而这张图片是从网络上下载下来的。源码:
MainActivity.java
[java] view
plaincopy
package com.example.siqi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.widget.ImageView;
public class MainActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView mImageView = (ImageView)findViewById(R.id.imageView1);
Bitmap b = null;
try {
b = BitmapFactory.decodeStream(new URL("http://www.baidu.com/img/baidu_sylogo1.gif").openConnection()
.getInputStream());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mImageView.setImageBitmap(b);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
界面:
activity_main.xml
[html] view
plaincopy
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="@string/hello_world"
tools:context=".MainActivity" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginBottom="90dp" />
</RelativeLayout>
需要的权限:<uses-permission android:name="android.permission.INTERNET"/>
我们希望的结果是:
在Android2.1上面,这段代码是可以运行的,但是在4.xx的模拟器上(我现在机器启动不了4.XX的模拟器,正在想办法解决。。。),因为下载图片是网络交互,会Block阻塞住UI界面,如果这个图片很大或者网络不给力,这个下载需要好几分钟,那么在图片下载完成前,你是做不了任何事情的。你会用这样一个会几分钟不动弹的程序吗?No,估计几秒钟我都等不了了,直接结束掉。。。所以线程的用武之地到了。。。
现在我们就需要把图片的下载放到线程里面去:
MainActivity.java
[java] view
plaincopy
package com.example.siqi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView mImageView;
public class ImageDownloadThread extends Thread {
@Override
public void run() {
Bitmap b = null;
try {
b = BitmapFactory.decodeStream(
new URL("http://www.baidu.com/img/baidu_sylogo1.gif").
openConnection().getInputStream());
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mImageView.setImageBitmap(b);
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView)findViewById(R.id.imageView1);
ImageDownloadThread thread = new ImageDownloadThread();
thread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
运行结果:
报错:android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
在Android里,只有UI线程可以操作界面。用GOOGLE的话说,用其他线程操作界面会造成不可预测的后果。用我们的话说,用其他线程操作UI会报错。。。
所以我们应该将下载图片放在线程里面,把设置图片在UI线程(可以叫主线程吧?)里面完成。
如何在主线程更新UI?Android给我们提供了至少3中方法:
1)View.post(Runnable)
方法
View是什么呢?不需要解释了吧,一个按钮,它的类不是叫ButtonView么,List的叫ListView,都可以这样用。[java] view
plaincopy
package com.example.siqi;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView mImageView;
public class ImageDownloadThread extends Thread {
@Override
public void run() {
try {
final Bitmap b = BitmapFactory.decodeStream(
new URL("http://www.baidu.com/img/baidu_sylogo1.gif").
openConnection().getInputStream());
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
} catch (Exception e) {
return; //报错了直接结束,可能的原因,网络啊,url地址等。
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView)findViewById(R.id.imageView1);
ImageDownloadThread thread = new ImageDownloadThread();
thread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
结果:图片显示正确。
2)
Activity.runOnUiThread(Runnable)方法
[java] view
plaincopy
package com.example.siqi;
import java.net.URL;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.Menu;
import android.widget.ImageView;
public class MainActivity extends Activity {
private ImageView mImageView;
//定义一个线程
public class ImageDownloadThread extends Thread {
@Override
public void run() {
try {
final Bitmap b = BitmapFactory.decodeStream(
new URL("http://www.baidu.com/img/baidu_sylogo1.gif").
openConnection().getInputStream());
MainActivity.this.runOnUiThread(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
} catch (Exception e) {
return; //报错了直接结束,可能的原因,网络啊,url地址等。
}
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView)findViewById(R.id.imageView1);
//实例化一个线程并运行
ImageDownloadThread thread = new ImageDownloadThread();
thread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
感觉不错哦,可以用在很多地方。
3)
View.postDelayed(Runnable,long)
这个跟View.post没多大区别哈,自己参考文档去,后面那个参数是延迟的时间,在这个时间之后才更新UI
相关文章推荐
- Android Tthread 建立线程使用方法
- Android问题—Toast不显示的原因和在子线程中使用方法以及Looper类详细解析
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
- 使用线程创建的三种方法实现j2me联网(PS:我想做android!NND!)
- Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- Android 开发中的 Handler ,Thread ,Message ,Runnable 的综合使用方法
- Android详细的对话框AlertDialog.Builder使用方法
- Android中Handler的使用方法——在子线程中更新界面
- Android 开发中的 Handler ,Thread ,Message ,Runnable 的综合使用方法
- 子线程更新UI会发生android.view.ViewRoot$CalledFromWrongThreadException异常的解决方法
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- 在Android中使用Handler和Thread线程执行后台操作
- Android 线程 thread 两种实现方法!
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android平台在UI Thread中执行非UI线程中定义的代码片段的几种方法
- 关于Android中startActivityForResult()方法的详细使用
- 在Android中使用Handler和Thread线程执行后台操作