进程与线程的区别?
在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(); } } } }