目录
1.回顾Java当中的线程概念
提示:Java线程详细解析:点我查看
1.线程两种实现方式:
- 实现线程方法一:定义一个线程类,它继承类 Thread 并复写其中的方法 run(),方法 run( ) 称为“线程体” (由于Java只支 持单继承,用这种方法定义的类不能再继承其他的类)。
注意:如果上面调用的不是 ft.start( )方法,而是执行ft.run( )就不是多线程,而是单线程运行,结果是:先执行 FirstThread ---->0 -100 然后再执行 main---->0 - 100。
运行Text.java,两个线程无规律运行,谁抢占到CPU使用权,就是谁运行:
- 实现线程方法二(常用):提供一个实现接口 Runnable 的类作为线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标 对象提供线程体。
下面采用实例演示:
运行Text.java:
2.线程的声明周期
3.多线程同步
多个线程访问同一资源时,就会出现问题,可以使用同步代码块: synchronized( this ) { } 来进行线程同步。
2.MainThread与Worker Thread
MainThread为主线程,也称为为UI线程。其他都称为Worker Thread。
注意:在主线程之外,是不允许修改UI的属性,但是特殊的控件是可以的,比如:ProgressBar。
3.Android当中的线程的使用
例子:
新建一个应用程序,命名为:S13_myThread1
在布局文件增加一个TextView控件,一个Button控件,一个ProgressBar控件。 代码如下:
<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textViewId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#00ff00"
android:textSize="20dp"
android:text="默认文字" />
<ProgressBar
android:id="@+id/progressBarId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/textViewId"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:progress="0"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"/>
<Button
android:id="@+id/buttonId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="按钮"
android:layout_below="@id/progressBarId"/>
</RelativeLayout>
视图如下:
在MainActivity.java中新建一个线程,实现线程的方式和Java一样,使用上面方式1的方法实现:
然后声明引用,获取控件对象,为button绑定监听器,过程不赘述,详细点击:点我查看:
代码如下:
package com.yuan.s13_mythread1;
import android.app.Activity;
import android.os.Bundle;
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;
public class MainActivity extends Activity {
private TextView textView;
private Button button;
private ProgressBar progressBar;
//Main Thread
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取控件的对象
textView =(TextView)findViewById(R.id.textViewId);
button =(Button)findViewById(R.id.buttonId);
progressBar=(ProgressBar)findViewById(R.id.progressBarId);
//绑定监听器
OnButtonListener listener = new OnButtonListener();
button.setOnClickListener(listener);
}
class OnButtonListener implements OnClickListener{
@Override
public void onClick(View v) {
Thread ft = new MyThread();
ft.start();
}
}
//Work Thread
class MyThread extends Thread{
@Override
public void run() {
try {
Thread.sleep(1*1000); //休眠1s.
} catch (InterruptedException e) {
e.printStackTrace();
}
textView.setText("来自线程的修改");
}
}
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
我们先分析上面的程序:在语法上面是没有错误的, 只要我们按钮一按下,就调用ft.start( )线程就开始运行,运行线程一开始就休眠1s,接着调用外部类textView变量的方法,修改TextView当中的内容,从语法上分析:(MyThread是一个MainActivity的内部类,使用了textView.setText("来自线程的修改");外部类外部类的成员变量和成员变量方法,本身是没有问题的)。
那我们试运行一下这个应用程序,发现竟然出错了,怎么回事:
再去看看错误信息,很明显不能再Work Thread 调用 Main Thread的TextView控件的属性,如果你需要去修改TextView属性的话就只能去主线程去修改(在主线程之外,原则上是不可以去修改UI的属性的):
但是有一些特殊的控件可以在 Work Thread中修改,比如ProgressBar控件,试试:
在MainActivity中的MyThread修改,其他不变,如下:
运行程序:
像出现上面的问题,在Work Thread不能去访问UI,只有Main Tehread 能去访问,那全部只用Main Thread就可以吗?
答案肯定是不行的,我们通过一个例子演示:
如果我们不使用Work Thread ,至使用Main Thread,然后点击按钮之后,之间进去休眠状态10s,如果这样的话系统就会进入阻塞状态,看看会发生什么问题:
运行程序,出现ANR(Application no responding)错误,这就是线程阻塞:
注意:一个应用程序当中,主线程通常用于接收用户的输入,以及运算运算的结果返回给用户,所以主线程是不能阻塞,因为UI是放在主线程内的,用户点击界面,而主线程输入不能被接受到,就会产生ANR错误。
所以对与一些可能产生阻塞的操作,必须放在Worker Thread当中 。
值得注意的问题:
如果把对于一些可能产生阻塞的操作,放在Work Thread当中,虽然说不会让主线程处于完全堵塞的状态,那么你在Work Thread废了那么大的劲,把改获取的数据,该计算的数据计算完了,然后此刻你又不能在(Work Thread)去修改UI的属性,那样做补全都白搭了吗?
这样就引出了一种通讯机制:Handler机制,通过这种通信机制,work Thread 就可以把运算完的数据发送给主线程,然后再主线程去修改UI的属性,和用户进行交互,正是这种巧妙的设计,多线程才有了可能性。
-
Android的通信机制:点我查看
附录:
本博文Demo下载:https://github.com/zGuangYuan/Android-
github的用法:点我查看