Android筆記——初用線程(純筆記埋市,LOW冠桃,無太深個人理解)

三更燈火五更雞,正是男兒讀書時道宅。黑發(fā)不知勤學(xué)早食听,白首方悔讀書遲胸蛛。——顏真卿

因為內(nèi)容還沒學(xué)太深樱报,這篇就是已學(xué)到的知識做個總結(jié)葬项,還沒做太多個人的思考研究,做下記錄留給自己看以后好補充迹蛤。

一民珍、簡單方法在WORK線程中更新UI

學(xué)習一段時間了,漸漸知道網(wǎng)絡(luò)連接盗飒、IO操作之類應(yīng)該放在線程中運行嚷量,而有時候這類操作過程中我們也許在某一步之后獲得數(shù)據(jù)希望將這個數(shù)據(jù)顯示到界面的時候,就會有些問題逆趣,你會發(fā)現(xiàn)若是在線程中使用setText這類影響UI的方法時程序就會產(chǎn)生異常蝶溶,因為我們Android的UI是線程不安全的,所以我們要想更新UI就必須在主線程(UI線程)宣渗。但是正如上面舉例的情況身坐,我們有時必須要在線程中根據(jù)其中運行獲得的數(shù)據(jù)更新UI,這時我們有幾種比較好的解決方案:Handler落包、AsyncTask.....但也許你的線程內(nèi)的操作并不復(fù)雜部蛇,或是只想簡單的把運行結(jié)果顯示到UI上,可以用下面的幾個簡單的方法咐蝇。

Activity.runOnUiThread(Runnable action)

正如這段英文的意思“運行在UI線程”,不用多說啦涯鲁,它的使用方法就是:

new Thread(new Runnable() {
    @Override
    public void run() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mTestTextView.setText("啦啦啦");
            }
        });
    }
}).start();

這樣就簡單的在線程中更新了TextView。當然你可以在runOnUiThread的前后進行其它操作有序。我們可以看看它的源碼:

/**
 * Runs the specified action on the UI thread. If the current thread is the UI
 * thread, then the action is executed immediately. If the current thread is
 * not the UI thread, the action is posted to the event queue of the UI thread.
 *
 * @param action the action to run on the UI thread
 */

public final void runOnUiThread(Runnable action) {
    if (Thread.currentThread() != mUiThread) {
        mHandler.post(action);
    } else {
        action.run();
    }
}

可知該方法會首先判斷現(xiàn)在的線程是不是UI線程抹腿,是則已,不是則實際使用了Handler的post方法來處理了我們寫在runOnUiThread的這段操作旭寿。

⑵View.post(Runnable action)

這個方法很尷尬的警绩,我在做類似runOnUiThread那樣的操作的時候失敗了(因為我是在onCreate方法中寫的線程,下面會說為啥不行)盅称,這個方法是從網(wǎng)上看到的和runOnUiThread一起被列出的肩祥,為啥沒效果呢?我稍微研究了一下缩膝,記錄一下我的錯誤使用混狠,先來看看它的源碼:

/**
 * <p>Causes the Runnable to be added to the message queue.
 * The runnable will be run on the user interface thread.</p>
 *
 * @param action The Runnable that will be executed.
 *
 * @return Returns true if the Runnable was successfully placed in to the
 *         message queue.  Returns false on failure, usually because the
 *         looper processing the message queue is exiting.
 *
 * @see #postDelayed
 * @see #removeCallbacks
 */
public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }
    // Assume that post will succeed later
    ViewRootImpl.getRunQueue().post(action);
    return true;
}

首先可以看到該方法會先判斷AttachInfo對象的內(nèi)容是否為空,若不為空疾层,則同樣是用了Handler方法來處理我們的runnable将饺,若為空,可以看到下面的注釋“假設(shè)post最后能成功”(什么鬼?)首先ViewRootImpl這個類與視圖的繪制有關(guān)——擴展閱讀ViewRootImpl予弧,然后可以看到其利用了其內(nèi)部方法得到運行隊列刮吧,且其post方法是其靜態(tài)最終內(nèi)部類RunQueue中自定義的post方法,而其中也有postDelayed方法掖蛤,參數(shù)為(Runnable action, long delayMillis) 第二個參數(shù)就是延遲毫秒數(shù)皇筛。總之看起來View.post()方法看起來就像Handler的post方法坠七,但為什么我像runOnUiThread那樣使用卻無效呢,我百度了一下查到一句這樣的話“This method can be invoked from outside of the UI thread only when this View is attached to a window.”意思大概是該方法要想影響到UI線程必須等到視圖(view)附加到窗口(window)旗笔。什么鬼彪置?最后參考了一百度了一下這個“attached to a window”了解到Activity中還有個onAttachedToWindow ()方法——擴展閱讀他人博客—onAttachedToWindow ()。我們可以知道我們要使用View.post()這個方法就必須等onAttachedToWindow ()這個方法執(zhí)行過了才行蝇恶,且啟動程序時這個onAttachedToWindow ()運行在onResume()之后拳魁,而我在onCreate中開線程異步操作可能在TextView還沒attached to a window就post了,所以沒有產(chǎn)生絲毫的效果撮弧。有興趣的朋友可以看上面的大佬的博客多了解一下潘懊,我理解的可能不太對。(這個方法我最后實驗成功是把線程寫在一個按鈕的點擊監(jiān)聽器里贿衍,我點擊的時候自然已經(jīng)“attached to a window”了)

LOG

⑶View.postDelayed(Runnable action, long delayMillis)

這個就是上一個方法的延時方法授舟,第二個參數(shù)寫要延時的毫秒數(shù)就行了,1000就是1秒贸辈。

二释树、利用線程進行簡單的下載(就是做個筆記)

直接上代碼吧:
  DownloadActivity.class

import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLConnection;

public class DownloadActivity extends AppCompatActivity {

    public static final String TAG = DownloadActivity.class.getSimpleName() + "-TAG";
    private Button mDownloadButton;
    private ProgressBar mDownloadProgressBar;
    private Handler mHandler = new DownloadHandler(this);
    private TextView mProgressTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_download);
        findViews();
        mDownloadButton.setOnClickListener(myClick);
    }

    private void findViews() {
        mDownloadButton = (Button) findViewById(R.id.btn_download);
        mDownloadProgressBar = (ProgressBar) findViewById(R.id.progressBar_download);
        mProgressTextView = (TextView) findViewById(R.id.textView_progress);
    }

    private View.OnClickListener myClick = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_download:
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                URL url = new URL("http://download.qidian.com/epub/3666197.epub");//下載鏈接
                                URLConnection connection = url.openConnection();
                                InputStream downloadStream = connection.getInputStream();
                                int contentLength = connection.getContentLength();//獲得文件長度
                                Log.i(TAG, "contentLength: " + contentLength);
                                if (contentLength <= 0) {
                                    return;
                                }
                                //文件存放路徑
                                String downloadFolderName = Environment.getExternalStorageDirectory() + File.separator + "qdf" + File.separator;
                                Log.i(TAG, "下載路徑  " + downloadFolderName);
                                File file = new File(downloadFolderName);
                                if (!file.exists()) {
                                    //如果目錄不存在則創(chuàng)建目錄
                                    file.mkdir();
                                }
                                //文件目錄+文件名
                                String fileName = downloadFolderName + "test.txt";
                                File contentFile = new File(fileName);
                                if (contentFile.exists()) {
                                    contentFile.delete();
                                }

                                int downloadSize = 0;

                                byte[] bytes = new byte[1024];
                                int length;

                                //字節(jié)輸出流
                                OutputStream outputStream = new FileOutputStream(fileName);

                                while ((length = downloadStream.read(bytes)) != -1) {
                                    outputStream.write(bytes, 0, length);
                                    downloadSize += length;
                                    int progress = downloadSize * 100 / contentLength;
                                    //更新UI
                                    Message message = mHandler.obtainMessage();
                                    message.what = 0;
                                    message.obj = progress;
                                    mHandler.sendMessage(message);
                                    //ProgressBar可以在線程中操作
                                    mDownloadProgressBar.setProgress(progress);
                                }
                                Log.i(TAG, "download success");
                                downloadStream.close();
                                outputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }

                        }
                    }).start();
                    break;
            }
        }
    };

    public TextView getProgressTextView() {
        return mProgressTextView;
    }


    public static class DownloadHandler extends Handler {

        public final WeakReference<DownloadActivity> mDownloadActivityWeakReference;

        public DownloadHandler(DownloadActivity downloadActivity) {
            mDownloadActivityWeakReference = new WeakReference<>(downloadActivity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            DownloadActivity activity = mDownloadActivityWeakReference.get();

            switch (msg.what) {
                case 0:
                    int progress = (int) msg.obj;
                    String progress2 = progress + "%";
                    activity.getProgressTextView().setText(progress2);
                    if (progress == 100) {
                        Toast.makeText(activity, "下載成功", Toast.LENGTH_SHORT).show();
                    }
                    break;
            }
        }
    }
}

網(wǎng)絡(luò)連接、IO操作自然是要在線程中啦擎淤,連接網(wǎng)絡(luò)后通過URLConnection 對象來獲得輸入流奢啥,并可以利用getContentLength()方法來獲得文件大小。最后利用字節(jié)輸出流輸出文件嘴拢,其中根據(jù)已下載的大小與總大小之比來更新ProgressBar桩盲,因為是在線程中獲取數(shù)據(jù)后立馬更新UI所以使用了Handler。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末席吴,一起剝皮案震驚了整個濱河市赌结,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌孝冒,老刑警劉巖姑曙,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迈倍,居然都是意外死亡伤靠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴合,“玉大人焕梅,你說我怎么就攤上這事∝郧ⅲ” “怎么了贞言?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長阀蒂。 經(jīng)常有香客問我该窗,道長,這世上最難降的妖魔是什么蚤霞? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任酗失,我火速辦了婚禮,結(jié)果婚禮上昧绣,老公的妹妹穿的比我還像新娘规肴。我一直安慰自己,他們只是感情好夜畴,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布拖刃。 她就那樣靜靜地躺著,像睡著了一般贪绘。 火紅的嫁衣襯著肌膚如雪兑牡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天税灌,我揣著相機與錄音发绢,去河邊找鬼。 笑死垄琐,一個胖子當著我的面吹牛边酒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播狸窘,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼墩朦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翻擒?” 一聲冷哼從身側(cè)響起氓涣,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陋气,沒想到半個月后劳吠,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡巩趁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年痒玩,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蠢古,死狀恐怖奴曙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情草讶,我是刑警寧澤洽糟,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站堕战,受9級特大地震影響坤溃,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘱丢,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一薪介、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧屿讽,春花似錦、人聲如沸吠裆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽试疙。三九已至诵棵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祝旷,已是汗流浹背履澳。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留怀跛,地道東北人距贷。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像吻谋,于是被迫代替她去往敵國和親忠蝗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容