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
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;
}
}
結果:
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
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
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
<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
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,都可以這樣用。
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)
方法
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
下一篇繼續,這個有點長了。。。