您好,登錄后才能下訂單哦!
這篇文章給大家介紹怎么在Android中利用線程池控制并發數,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
Android是一種基于Linux內核的自由及開放源代碼的操作系統,主要使用于移動設備,如智能手機和平板電腦,由美國Google公司和開放手機聯盟領導及開發。
主要實現步奏:
1、定義一個DownUtil類,下載工作基本在此類完成,在構造器中初始化UI線程的Handler。用于子線程和UI線程傳遞下載進度值。
2、所有的下載任務都保存在LinkedList。在init()方法中開啟一個后臺線程,不斷地從LinkedList中取任務交給線程池中的空閑線程執行。
3、每當addTask方法添加一個任務,就向 mPoolThreadHandler發送條消息,就從任務隊列中取出一個任務交給線程池執行。這里使用了使用了Semaphore信號量,也就是說只有當一個任務執行完成之后,release()一個信號量,才能從LinkedList中取出一個任務再去執行,否則acquire()方法會一直阻塞線程,直到上一個任務完成。
public class DownUtil { //定義下載資源的路徑 private String path; //指定下載文件的保存位置 private String targetFile; //定義下載文件的總大小 private int fileSize; //線程池 private ExecutorService mThreadPool; //線程數量 private static final int DEFAULT_THREAD_COUNT = 5; //任務隊列 private LinkedList<Runnable> mTasks; //后臺輪詢線程 private Thread mPoolThread; //后臺線程的handler private Handler mPoolThreadHandler; //UI線程的Handler private Handler mUIThreadHandler; //信號量 private Semaphore semaphore; private Semaphore mHandlerSemaphore = new Semaphore(0); //下載線程數量 private int threadNum; public DownUtil(String path , String targetFile , int threadNum , final ProgressBar bar) { this.path = path; this.targetFile = targetFile; this.threadNum = threadNum; init(); mUIThreadHandler = new Handler() { int sumSize = 0; @Override public void handleMessage(Message msg) { if (msg.what == 0x123) { int size = msg.getData().getInt("upper"); sumSize += size; Log.d("sumSize" , sumSize + ""); bar.setProgress((int) (sumSize * 1.0 / fileSize * 100)); } } }; } private void init() { mPoolThread = new Thread() { public void run() { Looper.prepare(); mPoolThreadHandler = new Handler() { public void handleMessage(Message msg) { if (msg.what == 0x111) { mThreadPool.execute(getTask()); try { semaphore.acquire(); } catch (InterruptedException e) { e.printStackTrace(); } } } }; mHandlerSemaphore.release(); Looper.loop(); } }; mPoolThread.start(); mThreadPool = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNT); mTasks = new LinkedList<>(); semaphore = new Semaphore(DEFAULT_THREAD_COUNT); } public void downLoad() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod("GET"); conn.setRequestProperty( "Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, " + "application/x-shockwave-flash, application/xaml+xml, " + "application/vnd.ms-xpsdocument, application/x-ms-xbap, " + "application/x-ms-application, application/vnd.ms-excel, " + "application/vnd.ms-powerpoint, application/msword, */*"); conn.setRequestProperty("Accept-Language", "zh-CN"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Connection", "Keep-Alive"); //得到文件的大小 fileSize = conn.getContentLength(); conn.disconnect(); int currentPartSize = fileSize / threadNum + 1; RandomAccessFile file = new RandomAccessFile(targetFile , "rw"); file.setLength(fileSize); file.close(); for (int i = 0 ; i < threadNum ; i++) { //計算每條線程下載的開始位置 int startPos = i * currentPartSize; //每條線程使用一個RandomAccessFile進行下載 RandomAccessFile currentPart = new RandomAccessFile(targetFile , "rw"); //定位該線程的下載位置 currentPart.seek(startPos); //將任務添加到任務隊列中 addTask(new DownThread(startPos , currentPartSize , currentPart)); } } catch (IOException e) { e.printStackTrace(); } } private Runnable getTask() { if (!mTasks.isEmpty()) { return mTasks.removeFirst(); } return null; } private synchronized void addTask(Runnable task) { mTasks.add(task); try { if (mPoolThreadHandler == null) { mHandlerSemaphore.acquire(); } } catch (InterruptedException e) { e.printStackTrace(); } mPoolThreadHandler.sendEmptyMessage(0x111); } private class DownThread implements Runnable { //當前線程的下載位置 private int startPos; //定義當前線程負責下載的文件大小 private int currentPartSize; //當前線程需要下載的文件塊 private RandomAccessFile currentPart; //定義該線程已經下載的字節數 private int length; public DownThread(int startPos , int currentPartSize , RandomAccessFile currentPart) { this.startPos = startPos; this.currentPartSize = currentPartSize; this.currentPart = currentPart; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod("GET"); conn.setRequestProperty( "Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, " + "application/x-shockwave-flash, application/xaml+xml, " + "application/vnd.ms-xpsdocument, application/x-ms-xbap, " + "application/x-ms-application, application/vnd.ms-excel, " + "application/vnd.ms-powerpoint, application/msword, */*"); conn.setRequestProperty("Accept-Language", "zh-CN"); conn.setRequestProperty("Charset", "UTF-8"); conn.setRequestProperty("Connection", "Keep-Alive"); InputStream inStream = conn.getInputStream(); //跳過startPos個字節 skipFully(inStream , this.startPos); byte[] buffer = new byte[1024]; int hasRead = 0; while (length < currentPartSize && (hasRead = inStream.read(buffer)) > 0) { currentPart.write(buffer , 0 , hasRead); //累計該線程下載的總大小 length += hasRead; } Log.d("length" , length + ""); //創建消息 Message msg = new Message(); msg.what = 0x123; Bundle bundle = new Bundle(); bundle.putInt("upper" , length); msg.setData(bundle); //向UI線程發送消息 mUIThreadHandler.sendMessage(msg); semaphore.release(); currentPart.close(); inStream.close(); } catch (Exception e) { e.printStackTrace(); } } } public static void skipFully(InputStream in , long bytes) throws IOException { long remaining = bytes; long len = 0; while (remaining > 0) { len = in.skip(remaining); remaining -= len; } } }
以下是MainActivity的代碼:
public class MainActivity extends Activity { EditText url; EditText target; Button downBn; ProgressBar bar; DownUtil downUtil; private String savePath; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //獲取界面中的四個界面控件 url = (EditText) findViewById(R.id.address); target = (EditText) findViewById(R.id.target); try { File sdCardDir = Environment.getExternalStorageDirectory(); savePath = sdCardDir.getCanonicalPath() + "/d.chm"; } catch (Exception e) { e.printStackTrace(); } target.setText(savePath); downBn = (Button) findViewById(R.id.down); bar = (ProgressBar) findViewById(R.id.bar); downBn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { downUtil = new DownUtil(url.getText().toString() , target.getText().toString() , 7 , bar); new Thread() { @Override public void run() { try { downUtil.downLoad(); } catch (Exception e) { e.printStackTrace(); } } }.start(); } }); } }
頁面布局比較簡單這里一并貼出:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/title1"/> <EditText android:id="@+id/address" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/address"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/targetAddress"/> <EditText android:id="@+id/target" android:layout_width="match_parent" android:layout_height="wrap_content"/> <Button android:id="@+id/down" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/down"/> <!-- 定義一個水平進度條,用于顯示下載進度 --> <ProgressBar android:id="@+id/bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:max="100" /> </LinearLayout>
關于怎么在Android中利用線程池控制并發數就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。