Android笔记(二十九) Android中的异步更新(一) Android中的线程

Java中的线程

1. 线程的两种实现方式

         ①继承Thread类

         ②实现Runnable接口

         两者区别在于,Thread这个类的对象,代表的是一个线程,而Runnable的对象,代表的是线程体(也就是线程要执行的代码)。

2.线程的生命周期

         创建---调用start()进入就绪状态---抢占到CPU就开始进入运行状态---运行过程中被别的线程抢到CPU,或者遇到阻塞,则进入就绪状态---如果执行完线程体,则进入死亡状态

         线程死亡之后,不可能再复活。

3.多线程同步

         如果多个线程访问同一个资源,会产生多个线程竞争一个资源,则会产生多线程错误,这时需要通过同步方式来解决,使用synchronized关键字,采用同步代码块或者同步方法。

         所谓的同步,就是指在一个线程访问资源时,别的线程是无法访问这个资源的。

MainThread和WorkerThread

         Android中可以将线程分为:MainThread和WorkerThread两大类

         MainThread就是主线程,又称为UI线程,所有和UI相关的代码,都是运行在MainThread中的。

         除了MainThread之外的线程,都是WorkerThread,原则上来讲WorkerThread是不允许操作UI组件的。

Android当中线程的使用

         实现一个demo,要求实现点击按钮5秒钟之后,改变TextView的文字。

package cn.lixyz.handlertest;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

    private TextView textView;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        textView = (TextView) findViewById(R.id.text);
        button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        super.run();
                        try {
                            sleep(5000);
                            textView.setText("改变之后的文字");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        });
    }
}
MainActivity.java
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="@string/hello_world"
        android:textSize="50dp" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="点击我改变文字" />

</LinearLayout>
activity_main.xml

      像上面一样编码的话,点击按钮5秒之后,会提示错误:

并抛出异常:

09-15 03:28:33.964    5854-6002/cn.lixyz.handlertest E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-112
    Process: cn.lixyz.handlertest, PID: 5854
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6024)
            at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:820)
......

      上面的代码和异常证明了,Android是不允许非UI线程去修改UI组件的。

      但是也有例外,譬如ProgressBar,看代码

package cn.lixyz.handlertest;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

    private ProgressBar progressBar;
    private Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        button = (Button) findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        for (int i = 0; i < 100; i++) {
                            try {
                                sleep(100);
                                progressBar.setProgress(i);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }.start();
            }
        });
    }
}
MainActivity.java
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/progressBar"
        style="@style/Widget.AppCompat.ProgressBar.Horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="30dp"
        android:text="点击开始加载" />

</LinearLayout>
activity_main.xml

         运行结果:

         所以说:大多数情况下,在WorkerThread中是无法修改UI的,只有少数情况下才可以。

         那么可以不可以把所有修改UI的代码全部放在MainThread中执行呢?答案是否定的。

         在一个应用程序之中,主线程通常用于接收用户的输入,以及将运算的结果反馈给用户,后台运行耗时代码则会导致主线程阻塞,程序无法相应,也就是常见的ANR(application not responding),应用程序没有相应。

         所以说,对于一些可能产生阻塞的操作,必须放到WorkerThread中,这时候就产生了WorkerThread和MainThread的通信问题。

原文地址:https://www.cnblogs.com/xs104/p/4810970.html