進程與線程的區別?
在Android中,線程是跑在進程之中的,當手機打開一個APP就相當於打開了一個進程,比如:UI界面的更新,就是在主線程中完成的,我也可以自定義一些子線程來完成所需要的任務.
如何創建線程?創建線程的幾種方式?
1.創建一個類繼承Thread類
2.創建一個類實現Runnable接口
什么是多線程?
線程是程序中一個單一的順序控制流程,在程序中同是運行多個線程完成不同的工作,稱為多線程
ANR的基礎知識及產生?
ANR:application not responding :應用程序無響應
產生的情況:1.主要類型按鍵或觸摸事件在特定的時間(5秒)內無響應
2.BroadcastReceiver在特定事件(10秒)內無法處理完成
3.小概率類型Service在特定事件內無法完成
線程的狀態:
創建(new) ---->就緒(runnable)---->運行(running)---->阻塞(bloocked)----->消亡(dead)
當線程滿足所需要運行的條件時,才能進入就緒狀態
當線程就如就緒狀態后,不能馬上獲得cpu的執行時間,需要CPU進行資源分配
當線程被中斷后執行完畢才會被消亡
線程的生命周期
注意:多線程會導致CPU資源分配的增加導致系統繁忙
多線程示例:售票
package com.hejun.ticket; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { final static String TAG = "MainActivity"; private Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = findViewById(R.id.strat_sale); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SaleTickets saleTickets1 = new SaleTickets(4); SaleTickets saleTickets2 = new SaleTickets(3); SaleTickets saleTickets3 = new SaleTickets(2); SaleTickets saleTickets4 = new SaleTickets(2); saleTickets1.setName("售票窗口1"); saleTickets2.setName("售票窗口2"); saleTickets3.setName("售票窗口3"); saleTickets4.setName("售票窗口4"); saleTickets1.start(); saleTickets2.start(); saleTickets3.start(); saleTickets4.start(); } }); } private class SaleTickets extends Thread{ private int tickets; private SaleTickets(int tickets){ this.tickets = tickets; } @Override public void run() { super.run(); while(tickets>0){ Sale(); } Log.d(TAG, Thread.currentThread().getName()+ "的票售賣完了"); } private void Sale(){ tickets--; Log.d(TAG, Thread.currentThread().getName()+ "正在賣票,還剩下"+ tickets +"張票"); } } }
演示結果
線程間通信的相關組件
1.Message :消息.其中包含了消息ID,消息處理對象以及處理數據,Message有MessagesQueue統一列隊,最終有Handle處理
2.Handle:處理者,負責Message的發送及處理,實現handleMessage(Message msg)方法,對特定的MEssage進行處理
3.MessagesQueue:消息隊列,用來存放Handle發送過來的消息,並按照先進先出規則執行
4.Looper:消息泵,不斷的從MessagesQueue中抽取Message執行,一個MessagesQueue需要一個Looper
5.Thread:線程,輔助調度整個消息循環,即消息循環執行的場所
關系:Handle looper MessagesQueue是簡單的三角關系Looper和MessagesQueue是一一對應的
消息循環
一個Message經由Handle發送到MessagesQueue隊列中,再由Looper不斷的從MessagesQueue抽取,又再一次回到Handle的環抱,實現線程間的通信
線程與更新
在ui線程中,如果創建Handle是不傳入Looper對象,那么將直接使用UI\線程的Looer對象(系統已經幫我們自動創建了),在其他線程創建Handle如果不傳入Looper對象,那么Handle將不能接收處理消息,在這種情況下,通常的做法是:
在創建Handle之前,為該線程准備好一個Looper(Looper.prepare),然后讓這個Looper跑起來(Looper.loop),這樣Handle 才能正常工作;.
注意:Handle處理消息總是在創建Handler的線程中執行,而我們的消息處理,不乏UI的更新操作,不正確的線程直接更新UI將引發異常,因此,我們需要時刻關心Handler是在哪個線程中創建的.
SDk提供四中方式可以從其他線程中訪問UI線程
1.Activity.runOnUiThread(Runnable)
2.View.post(Runnable)
3.View.postDelayed(Runnable,long)
4.Handler
案例,從網上下載圖片並更新進度
package com.hejun.ticket; import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.os.Trace; 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.ImageView; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class DownPicture extends AppCompatActivity { final static String address = "http://img4.imgtn.bdimg.com/it/u=1952016862,1880307894&fm=26&gp=0.jpg"; private static final String TAG = "DownPicture"; private Handler mMainHandler = null; private int progress; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_down_picture); Button button = findViewById(R.id.button); final ImageView imageView = findViewById(R.id.img); button.setOnClickListener(new View.OnClickListener() { @SuppressLint("HandlerLeak") @Override public void onClick(View view) { final ProgressDialog progressDialog = new ProgressDialog(DownPicture.this); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); progressDialog.setMessage("下載中"); progressDialog.setMax(100); progressDialog.show(); new Thread(new Down(),"下載圖片").start(); mMainHandler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case 10010: progressDialog.setProgress(msg.arg1); break; case 10011: progressDialog.dismiss(); Bitmap bitmap = (Bitmap) msg.obj; imageView.setImageBitmap(bitmap); break; } } }; } }); } class Down implements Runnable { String fileName = "dowmPicture"; @Override public void run() { try { URL url = new URL(address); HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(); httpURLConnection.setConnectTimeout(5000); httpURLConnection.setRequestMethod("GET"); if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream inputStream = httpURLConnection.getInputStream(); OutputStream outputStream = openFileOutput(fileName, MODE_PRIVATE); byte[] bytes = new byte[1024*1024]; int s = httpURLConnection.getContentLength(); int d = 0; int curent = 0; while ((d = inputStream.read(bytes)) != -1){ outputStream.write(bytes,0,s); curent += d; progress = (int) ((float)curent/s*100); Log.d(TAG, "當前現在進度為" + progress); SystemClock.sleep(40); Message message = new Message(); message.arg1 = progress; message.what = 10010; mMainHandler.sendMessage(message); } if (progress == 100){ Bitmap bitmap = BitmapFactory.decodeFile(getFileStreamPath(fileName).getAbsolutePath()); Message message = new Message(); message.obj = bitmap; message.what = 10011; mMainHandler.sendMessage(message); } inputStream.close(); outputStream.close(); httpURLConnection.disconnect(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }