Handler vs AsyncTask vs Thread [đã đóng]


382

Tôi đã hơi bối rối về sự khác biệt giữa Handlers, AsyncTaskThreadstrong Android. Tôi đã đọc khá nhiều blog và câu hỏi ở đây trong StackOverflow.

Handlerlà các chủ đề nền cung cấp cho bạn để giao tiếp với giao diện người dùng. Cập nhật một thanh tiến trình, ví dụ, nên được thực hiện thông qua Handler. Sử dụng Trình xử lý bạn có lợi thế MessagingQueues, vì vậy nếu bạn muốn lên lịch tin nhắn hoặc cập nhật nhiều thành phần UI hoặc có các tác vụ lặp lại.

AsyncTasktrên thực tế, chúng tương tự nhau, nhưng chúng sử dụng Handler, nhưng không chạy trong luồng UI, vì vậy tốt cho việc tìm nạp dữ liệu, ví dụ như tìm nạp các dịch vụ web. Sau này bạn có thể tương tác với UI.

Threadtuy nhiên không thể tương tác với giao diện người dùng, cung cấp luồng "cơ bản" hơn và bạn bỏ lỡ tất cả các tóm tắt của AsyncTask.

Tuy nhiên, tôi muốn có một kết nối ổ cắm chạy trong dịch vụ. Điều này nên được chạy trong một xử lý hoặc một chủ đề, hoặc thậm chí một AsyncTask? Tương tác UI không cần thiết chút nào. Liệu nó có làm nên sự khác biệt về hiệu suất mà tôi sử dụng không?

Trong khi đó, các tài liệu đã được cải thiện lớn.



9
"Người xử lý là chủ đề nền" - Một số câu trả lời được bình chọn hàng đầu dường như cũng đi theo hướng đó. Nhưng đó là một quan niệm sai lầm. A Handlerkhông phải là một chủ đề, và nó không thực hiện bất cứ điều gì. Nó chỉ là một phương tiện để chuyển các tin nhắn từ một luồng này sang hàng đợi tin nhắn của một luồng khác một cách an toàn . Vì vậy, thông thường, (ít nhất) hai luồng vẫn phải được tạo, sau đó có thể sử dụng trình xử lý, nhưng trình xử lý không thể tự thực hiện bất cứ điều gì.
JimmyB

Câu trả lời:


57

Như Hướng dẫn về xử lý nền Android với Trình xử lý, AsyncTask và Trình tải trên trang Vogella đặt:

Các Handlerlớp có thể được sử dụng để đăng ký to a thread và cung cấp một kênh đơn giản để gửi dữ liệu đến chủ đề này.

Các AsyncTasklớp học gói gọn việc tạo ra một tiến trình nền và đồng bộ hóa với các chủ đề chính. Nó cũng hỗ trợ báo cáo tiến độ của các nhiệm vụ đang chạy.

Và a Threadvề cơ bản là yếu tố cốt lõi của đa luồng mà nhà phát triển có thể sử dụng với nhược điểm sau:

Nếu bạn sử dụng các luồng Java, bạn phải xử lý các yêu cầu sau trong mã của riêng bạn:

  • Đồng bộ hóa với luồng chính nếu bạn gửi lại kết quả cho giao diện người dùng
  • Không có mặc định để hủy chủ đề
  • Không có nhóm chủ đề mặc định
  • Không có mặc định để xử lý các thay đổi cấu hình trong Android

Và liên quan đến AsyncTask, như Tài liệu tham khảo của Nhà phát triển Android đưa ra:

AsyncTaskcho phép sử dụng chủ đề UI thích hợp và dễ dàng. Lớp này cho phép thực hiện các thao tác nền và xuất bản kết quả trên luồng UI mà không phải thao tác với các luồng và / hoặc trình xử lý.

AsyncTaskđược thiết kế để trở thành một lớp trợ giúp xung quanh ThreadHandler không tạo thành một khung phân luồng chung. AsyncT task nên được sử dụng một cách lý tưởng cho các hoạt động ngắn (tối đa vài giây.) Nếu bạn cần giữ các luồng chạy trong thời gian dài, bạn nên sử dụng các API khác nhau được cung cấp bởi gói java.util.conc hiện như Giám đốc điều hành, ThreadPoolExecutor và FutureTask.

Cập nhật tháng 5 năm 2015: Tôi tìm thấy một loạt các bài giảng tuyệt vời về chủ đề này.

Đây là Tìm kiếm của Google: Douglas Schmidt giảng bài đồng thời và đồng bộ hóa android

Đây là video của bài giảng đầu tiên trên YouTube

Tất cả điều này là một phần của CS 282 (2013): Lập trình hệ thống cho Android từ Đại học Vanderbilt . Đây là Danh sách phát YouTube

Douglas Schmidt dường như là một giảng viên xuất sắc

Quan trọng: Nếu bạn đang ở thời điểm mà bạn đang cân nhắc sử dụng AsyncTaskđể giải quyết các vấn đề luồng của mình, trước tiên bạn nên kiểm traReactiveX/RxAndroid một mẫu lập trình phù hợp hơn. Một tài nguyên rất tốt để có được một cái nhìn tổng quan là Học RxJava 2 cho Android chẳng hạn .


4
Trong chuỗi bài giảng đó, liên kết này sẽ đưa bạn vào một số ví dụ về chủ đề: youtu.be/4Vue_KuXfCk?t=19m24s
Kẻ xâm phạm

353

Nếu chúng ta nhìn vào mã nguồn, chúng ta sẽ thấy AsyncTaskHandlerhoàn toàn được viết bằng Java. (Tuy nhiên, có một số trường hợp ngoại lệ. Nhưng đó không phải là một điểm quan trọng)

Vì vậy, không có phép thuật trong AsyncTaskhoặc Handler. Những lớp học này làm cho cuộc sống của chúng tôi dễ dàng hơn như là một nhà phát triển.

Ví dụ: Nếu Chương trình A gọi phương thức A (), phương thức A () có thể chạy trong một luồng khác với Chương trình A. Chúng tôi có thể dễ dàng xác minh bằng mã sau:

Thread t = Thread.currentThread();    
int id = t.getId();

Tại sao chúng ta nên sử dụng một chủ đề mới cho một số nhiệm vụ? Bạn có thể google cho nó. Nhiều lý do, ví dụ: nâng vật nặng, hoạt động lâu dài.

Vì vậy, sự khác nhau giữa là gì Thread, AsyncTaskHandler?

AsyncTaskHandlerđược viết bằng Java (bên trong họ sử dụng a Thread), vì vậy mọi thứ chúng ta có thể làm với Handlerhoặc AsyncTask, chúng ta cũng có thể đạt được bằng cách sử dụng Thread.

Điều gì có thể HandlerAsyncTaskthực sự giúp đỡ?

Lý do rõ ràng nhất là giao tiếp giữa luồng người gọi và luồng worker. ( Chủ đề của người gọi : Một chủ đề gọi Chủ đề công nhân để thực hiện một số tác vụ. Một chủ đề của người gọi không nhất thiết phải là chủ đề UI). Tất nhiên, chúng ta có thể giao tiếp giữa hai luồng theo những cách khác, nhưng có nhiều nhược điểm (và nguy hiểm) vì an toàn của luồng.

Đó là lý do tại sao chúng ta nên sử dụng HandlerAsyncTask. Các lớp này làm hầu hết công việc cho chúng ta, chúng ta chỉ cần biết phương thức nào để ghi đè.

Sự khác biệt giữa HandlerAsyncTasklà: Sử dụng AsyncTaskkhi Chủ đề của Người gọiChủ đề Giao diện người dùng . Đây là những gì tài liệu Android nói:

AsyncTask cho phép sử dụng luồng UI thích hợp và dễ dàng. Lớp này cho phép thực hiện các thao tác nền và xuất bản kết quả trên luồng UI mà không phải thao tác với các luồng và / hoặc trình xử lý

Tôi muốn nhấn mạnh hai điểm:

1) Dễ dàng sử dụng luồng UI (vì vậy, sử dụng khi luồng của người gọi là UI Thread).

2) Không cần thao tác xử lý. (có nghĩa là: Bạn có thể sử dụng Trình xử lý thay vì AsyncTask, nhưng AsyncTask là một tùy chọn dễ dàng hơn).

Có rất nhiều điều trong bài đăng này tôi chưa nói, ví dụ: UI Thread là gì hoặc tại sao nó dễ dàng hơn. Bạn phải biết một số phương thức đằng sau mỗi lớp và sử dụng nó, bạn sẽ hoàn toàn hiểu lý do tại sao.

@: khi bạn đọc tài liệu Android, bạn sẽ thấy:

Handler cho phép bạn gửi và xử lý các đối tượng Message và Runnable được liên kết với MessageQueue của một chủ đề

Mô tả này có vẻ lạ lúc đầu. Chúng ta chỉ cần hiểu rằng mỗi luồng có mỗi hàng đợi tin nhắn (như danh sách việc cần làm) và luồng sẽ nhận từng tin nhắn và thực hiện cho đến khi hàng đợi tin nhắn trống (giống như chúng ta hoàn thành công việc và đi ngủ). Vì vậy, khi Handlergiao tiếp, nó chỉ đưa ra một thông báo cho chuỗi người gọi và nó sẽ chờ xử lý.

Phức tạp? Chỉ cần nhớ rằng Handlercó thể giao tiếp với các chủ đề người gọi một cách an toàn.


4
thực ra asynctask cũng dựa trên handler và futuretask, xem
Sumit

AsyncTask về cơ bản là một lớp trình trợ giúp được xây dựng dựa trên Handler và Thread. developer.android.com/reference/android/os/AsyncTask.html . Nhìn vào tài liệu "AsyncTask được thiết kế để trở thành một lớp trợ giúp xung quanh Thread và Handler". AsyncTask được phát hành trong API3 trong khi Handler tồn tại kể từ API1.
hjchin

52

Sau khi nhìn sâu, nó tiến thẳng về phía trước.

AsyncTask:

Đó là một cách đơn giản để sử dụng một luồng mà không biết gì về mô hình luồng java . AsyncTaskđưa ra các cuộc gọi lại khác nhau tương ứng với luồng công nhân và luồng chính.

Sử dụng cho các hoạt động chờ nhỏ như sau:

  1. Lấy một số dữ liệu từ các dịch vụ web và hiển thị trên bố cục.
  2. Truy vấn cơ sở dữ liệu.
  3. Khi bạn nhận ra rằng hoạt động đang chạy sẽ không bao giờ, bao giờ được lồng nhau.

Handler:

Khi chúng ta cài đặt một ứng dụng trong Android, thì nó sẽ tạo ra một luồng cho ứng dụng đó có tên MAIN UI Thread. Tất cả các hoạt động chạy bên trong chủ đề đó. Theo quy tắc mô hình luồng đơn của Android, chúng tôi không thể truy cập trực tiếp các phần tử UI (bitmap, textview, v.v.) cho một luồng khác được xác định bên trong hoạt động đó.

Handler cho phép bạn liên lạc trở lại với luồng UI từ các luồng nền khác. Điều này rất hữu ích trong Android vì Android không cho phép các luồng khác giao tiếp trực tiếp với luồng UI. Trình xử lý có thể gửi và xử lý các đối tượng Message và Runnable được liên kết với MessageQueue của một luồng. Mỗi phiên bản Handler được liên kết với một luồng và hàng đợi thông báo của luồng đó. Khi một Trình xử lý mới được tạo, nó bị ràng buộc với hàng đợi luồng / thông báo của luồng đang tạo ra nó.

Đó là sự phù hợp nhất cho:

  1. Nó cho phép bạn thực hiện xếp hàng tin nhắn.
  2. Lập lịch nhắn tin.

Thread:

Bây giờ là lúc để nói về chủ đề này.

Chủ đề là cha mẹ của cả hai AsyncTaskHandler. Cả hai đều sử dụng thread trong nội bộ, có nghĩa là bạn cũng có thể tạo ra mô hình thread của riêng bạn như AsyncTaskHandler, nhưng điều đó đòi hỏi phải có một kiến thức tốt về thực hiện Multi-Threading của Java .


1
AsyncTask api, trên thực tế, được viết bằng Futures, Handlers và Executors. Xem mã nguồn: grepcode.com/file_/reposective.grepcode.com/java/ext/iêu
IgorGanapolsky

22

An AsyncTaskđược sử dụng để thực hiện một số tính toán nền và xuất bản kết quả lên luồng UI (với các cập nhật tiến trình tùy chọn). Vì bạn không quan tâm đến UI, nên một Handlerhoặc Threadcó vẻ phù hợp hơn.

Bạn có thể đẻ trứng một nền tảng Threadvà vượt qua các thông điệp trở lại vào chủ đề chính của bạn bằng cách sử dụng Handler's postphương pháp.


9

Chủ đề

Android hỗ trợ Chủ đề Java tiêu chuẩn . Bạn có thể sử dụng Chủ đề tiêu chuẩn và các công cụ từ gói Gói Xiên java.util.concurrentđể đặt các hành động vào nền. Hạn chế duy nhất là bạn không thể cập nhật trực tiếp giao diện người dùng từ quy trình nền.

Nếu bạn cần cập nhật giao diện người dùng từ tác vụ nền, bạn cần sử dụng một số lớp cụ thể của Android. Bạn có thể sử dụng lớp “ android.os.Handler” cho điều này hoặc lớp “ AsyncTask

Xử lý

Các lớp Handlercó thể cập nhật giao diện người dùng. Một tay cầm cung cấp các phương thức để nhận tin nhắn và cho runnables. Để sử dụng trình xử lý, bạn phải phân lớp nó và ghi đè handleMessage()để xử lý tin nhắn. Để xử lý Runable, bạn có thể sử dụng phương thức post();Bạn chỉ cần một phiên bản của trình xử lý trong hoạt động của mình.

Bạn có thể gửi tin nhắn thông qua phương thức sendMessage(Message msg)hoặc sendEmptyMessage.

AsyncTask

Nếu bạn có Activitynhu cầu tải xuống nội dung hoặc thực hiện các thao tác có thể được thực hiện trong nền AsyncTaskcho phép bạn duy trì giao diện người dùng phản hồi và xuất bản tiến trình cho các hoạt động đó cho người dùng.

Để biết thêm thông tin bạn có thể xem qua các liên kết này.

http://mobisys.in/blog/2012/01/android-threads-handlers-and-asynctask-tutorial/

http://www.sl slideshoware.net/HoangNgoBuu/android-thread-handler-and-asynctask


6

Thread:

Bạn có thể sử dụng mới Threadcho các tác vụ nền chạy dài mà không ảnh hưởng đến UI Thread. Từ java Thread, bạn không thể cập nhật UI Thread.

Thread bình thường không hữu ích nhiều cho kiến ​​trúc Android, nên các lớp trợ giúp cho luồng đã được giới thiệu.

Bạn có thể tìm thấy câu trả lời cho các truy vấn của mình trong trang tài liệu hiệu suất Threading .

Xử lý :

A Handlercho phép bạn gửi và xử lý Tin nhắn và Runnablecác đối tượng được liên kết với một chuỗi MessageQueue. Mỗi Handlerphiên bản được liên kết với một luồng và hàng đợi tin nhắn của luồng đó.

Có hai cách sử dụng chính cho Handler:

  1. Để lên lịch các tin nhắn và runnables sẽ được thực hiện như một số điểm trong tương lai;

  2. Để ghi lại một hành động được thực hiện trên một chủ đề khác với chủ đề của bạn.

AsyncTask :

AsyncTaskcho phép sử dụng chủ đề UI thích hợp và dễ dàng. Lớp này cho phép bạn thực hiện các thao tác nền và xuất bản kết quả trên luồng UI mà không phải thao tác với các luồng và / hoặc trình xử lý.

Hạn chế:

  1. Theo mặc định, một ứng dụng sẽ đẩy tất cả các AsyncTaskđối tượng mà nó tạo ra thành một luồng. Do đó, chúng thực thi theo kiểu nối tiếp, và với chủ đề chính là một gói công việc đặc biệt dài có thể chặn hàng đợi. Vì lý do này, sử dụng AsyncTask để xử lý các mục công việc có thời lượng ngắn hơn 5ms .

  2. AsyncTaskđối tượng cũng là những người phạm tội phổ biến nhất cho các vấn đề tham chiếu ngầm. AsyncTaskđối tượng cũng có những rủi ro liên quan đến tài liệu tham khảo rõ ràng.

Xử lý : Đọc :

Bạn có thể cần một cách tiếp cận truyền thống hơn để thực hiện một khối công việc trên một luồng chạy dài ( không giống như AsyncTask, nên được sử dụng cho khối lượng công việc 5ms ) và một số khả năng để quản lý quy trình công việc đó theo cách thủ công. Một xử lý xử lý thực sự là một chủ đề chạy dài, lấy công việc từ hàng đợi và hoạt động trên nó.

ThreadPoolExecutor :

Lớp này quản lý việc tạo ra một nhóm các luồng, đặt mức độ ưu tiên của chúng và quản lý cách phân phối công việc giữa các luồng đó. Khi khối lượng công việc tăng hoặc giảm, lớp sẽ tăng hoặc phá hủy nhiều luồng hơn để điều chỉnh theo khối lượng công việc.

Nếu khối lượng công việc nhiều hơn và HandlerThreadkhông đủ, bạn có thể điThreadPoolExecutor

Tuy nhiên tôi muốn có một kết nối ổ cắm chạy trong dịch vụ. Điều này nên được chạy trong một trình xử lý hoặc một luồng, hoặc thậm chí là AsyncTask? Tương tác UI không cần thiết chút nào. Liệu nó có làm nên sự khác biệt về hiệu suất mà tôi sử dụng không?

Vì tương tác UI không bắt buộc, bạn có thể không đi AsyncTask. Chủ đề bình thường không có nhiều hữu ích và do đó HandlerThreadlà lựa chọn tốt nhất. Vì bạn phải duy trì kết nối ổ cắm, Handler trên luồng chính hoàn toàn không hữu ích. Tạo một HandlerThreadvà nhận được Handlertừ các looper của HandlerThread.

 HandlerThread handlerThread = new HandlerThread("SocketOperation");
 handlerThread.start();
 Handler requestHandler = new Handler(handlerThread.getLooper());
 requestHandler.post(myRunnable); // where myRunnable is your Runnable object. 

Nếu bạn muốn liên lạc trở lại luồng UI, bạn có thể sử dụng thêm một Handler để xử lý phản hồi.

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Foreground task is completed:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

trong của bạn Runnable, bạn có thể thêm

responseHandler.sendMessage(msg);

Thông tin chi tiết về việc thực hiện có thể được tìm thấy ở đây:

Android: Toast trong một chủ đề


5

Theo ý kiến ​​của tôi, các luồng không phải là cách hiệu quả nhất để thực hiện các kết nối ổ cắm nhưng chúng cung cấp nhiều chức năng nhất về các luồng chạy. Tôi nói điều đó bởi vì từ kinh nghiệm, việc chạy các chủ đề trong một thời gian dài khiến các thiết bị trở nên rất nóng và tốn nhiều tài nguyên. Ngay cả một đơn giản while(true)sẽ làm nóng điện thoại trong vài phút. Nếu bạn nói rằng tương tác UI không quan trọng, có lẽ điều AsyncTasknày là tốt vì chúng được thiết kế cho các quy trình dài hạn. Đây chỉ là ý kiến ​​của tôi về nó.

CẬP NHẬT

Xin vui lòng bỏ qua câu trả lời trên của tôi! Tôi đã trả lời câu hỏi này vào năm 2011 khi tôi chưa có nhiều kinh nghiệm về Android so với bây giờ. Câu trả lời của tôi ở trên là sai lệch và được coi là sai. Tôi để nó ở đó vì nhiều người nhận xét về nó bên dưới sửa lỗi cho tôi và tôi đã học được bài học của mình.

Có nhiều câu trả lời khác tốt hơn về chủ đề này, nhưng ít nhất tôi sẽ cho tôi câu trả lời đúng hơn. Không có gì sai khi sử dụng Java thông thường Thread; tuy nhiên, bạn thực sự nên cẩn thận về cách bạn thực hiện nó bởi vì làm sai nó có thể rất nặng bộ xử lý (triệu chứng đáng chú ý nhất có thể là thiết bị của bạn nóng lên). AsyncTasks khá lý tưởng cho hầu hết các tác vụ mà bạn muốn chạy trong nền (ví dụ phổ biến là I / O đĩa, cuộc gọi mạng và cuộc gọi cơ sở dữ liệu). Tuy nhiên, AsyncTaskkhông nên sử dụng cho các quy trình đặc biệt dài có thể cần tiếp tục sau khi người dùng đã đóng ứng dụng của bạn hoặc đặt thiết bị của họ ở chế độ chờ. Tôi sẽ nói trong hầu hết các trường hợp, bất cứ điều gì không thuộc về luồng UI, đều có thể được xử lý trong một AsyncTask.


cảm ơn, có thực sự có lý do tôi nên sử dụng Chủ đề thay vì AsyncT task không? Hoặc nó được khuyến khích để sử dụng nó?
Alx

9
@AeroDroid Trong ví dụ của bạn: "một thời gian đơn giản (đúng)", bạn sẽ chốt CPU ở đây trừ khi bạn thêm trạng thái ngủ trong vòng lặp. Điều này đúng với bất kỳ vòng lặp vô tận. Nếu bạn muốn giảm mức sử dụng CPU do chi phí này, hãy ngủ chuỗi trong vài mili giây ở cuối vòng lặp.
Lỗi 454

1
@Error 454 - thật thú vị! Nếu bạn phải chọn một số thích hợp cho thời gian ngủ, nó sẽ nằm trong khoảng 40-80 mili giây?
Abhijit

6
@Abhijit Từ nội dung trò chơi tôi đã thực hiện trong SDL, chỉ cần thêm một giấc ngủ 10 ms vào vòng lặp là đủ để giảm từ 99% cpu xuống ~ 0 trong trạng thái không hoạt động.
Lỗi 454

15
Trên thực tế developer.android.com/reference/android/os/AsyncTask.html nói: "AsyncT task nên được sử dụng lý tưởng cho các hoạt động NGẮN". Bạn cũng nên sử dụng chúng một cách cẩn thận vì chúng có thể bị hệ thống loại bỏ mà không cần thực thi!
loại-a1pha

5

AsyncTaskđược thiết kế để thực hiện không quá vài giây thao tác được thực hiện ở chế độ nền (không được khuyến nghị cho megabyte tải xuống tệp từ máy chủ hoặc tính toán tác vụ chuyên sâu cpu như hoạt động IO của tệp). Nếu bạn cần thực hiện một hoạt động chạy dài, bạn nên sử dụng các chủ đề gốc java. Java cung cấp cho bạn các lớp liên quan đến luồng khác nhau để làm những gì bạn cần. Sử dụng Handlerđể cập nhật giao diện người dùng.


2
public class RequestHandler {

    public String sendPostRequest(String requestURL,
                                  HashMap<String, String> postDataParams) {

        URL url;

        StringBuilder sb = new StringBuilder();
        try {
            url = new URL(requestURL);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);


            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(os, "UTF-8"));
            writer.write(getPostDataString(postDataParams));

            writer.flush();
            writer.close();
            os.close();
            int responseCode = conn.getResponseCode();

            if (responseCode == HttpsURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                sb = new StringBuilder();
                String response;
                while ((response = br.readLine()) != null){
                    sb.append(response);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");

            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }

        return result.toString();
    }

}

1

Hãy để tôi thử và trả lời câu hỏi ở đây bằng một ví dụ :) - MyImageSearch [Vui lòng tham khảo hình ảnh ở đây của màn hình hoạt động chính - chứa văn bản chỉnh sửa / nút tìm kiếm / chế độ xem lưới]

MyImageSearch

Mô tả về MyImageSearch - Khi người dùng nhập chi tiết vào trường văn bản chỉnh sửa và nhấp vào nút tìm kiếm, chúng tôi sẽ tìm kiếm hình ảnh trên internet thông qua các dịch vụ web được cung cấp bởi flickr (bạn chỉ cần đăng ký tại đó để nhận mã thông báo / khóa bí mật) - để tìm kiếm, chúng tôi gửi lại Yêu cầu HTTP và NHẬN dữ liệu JSON trong phản hồi có chứa url của các hình ảnh riêng lẻ mà sau đó chúng tôi sẽ sử dụng để tải chế độ xem lưới.

Triển khai của tôi - Trong hoạt động chính, tôi sẽ xác định một lớp bên trong mở rộng AsyncTask để gửi Yêu cầu HTTP trong Phương thức doInBackGround và tìm nạp Phản hồi JSON và cập nhật ArrayList cục bộ của tôi về FlickrItems mà tôi sẽ sử dụng để cập nhật GridView của mình thông qua FlickrAd CHƯƠNG (mở rộng BaseAd CHƯƠNG) và gọi bộ điều hợp.notifyDataSetChanged () trong onPostExecute () của AsyncTask để tải lại chế độ xem lưới. Lưu ý rằng ở đây Yêu cầu HTTP là một cuộc gọi chặn vì tôi đã thực hiện nó thông qua AsyncTask. Và, tôi có thể lưu trữ các mục trong bộ điều hợp để tăng hiệu suất hoặc lưu trữ chúng trên SDCard. Lưới mà tôi sẽ thổi phồng trong FlickrAd CHƯƠNG chứa trong triển khai của tôi một thanh tiến trình và chế độ xem hình ảnh. Dưới đây bạn có thể tìm thấy mã cho mainActivity mà tôi đã sử dụng.

Trả lời câu hỏi ngay bây giờ - Vì vậy, khi chúng tôi có dữ liệu JSON để tìm nạp từng Hình ảnh riêng lẻ, chúng tôi có thể triển khai logic lấy hình ảnh ở chế độ nền thông qua Trình xử lý hoặc Chủ đề hoặc AsyncTask. Chúng ta nên lưu ý ở đây rằng vì hình ảnh của tôi sau khi tải xuống phải được hiển thị trên UI / luồng chính, chúng ta không thể đơn giản sử dụng các luồng vì nó không có quyền truy cập vào ngữ cảnh. Trong FlickrAd CHƯƠNG, các lựa chọn tôi có thể nghĩ đến:

  • Lựa chọn 1: Tạo LooperThread [mở rộng chuỗi] - và tiếp tục tải xuống hình ảnh liên tục trong một luồng bằng cách giữ luồng này mở [looper.loop ()]
  • Lựa chọn 2: Sử dụng Nhóm luồng và đăng có thể chạy qua myHandler có chứa tham chiếu đến ImageView của tôi, nhưng vì các chế độ xem trong Chế độ xem lưới được tái chế, một lần nữa vấn đề có thể xuất hiện khi hình ảnh ở chỉ số 4 được hiển thị ở chỉ mục 9 [có thể tải xuống cần thêm thời gian]
  • Lựa chọn 3 [Tôi đã sử dụng cái này]: Sử dụng Thread Pool và gửi tin nhắn đến myHandler, chứa dữ liệu liên quan đến chỉ mục của ImageView và ImageView, vì vậy, trong khi thực hiện xử lýMaxage (), chúng tôi sẽ chỉ cập nhật ImageView phù hợp với chỉ mục của Hình ảnh chúng tôi đã cố tải xuống.
  • Lựa chọn 4: Sử dụng AsyncTask để tải xuống hình ảnh ở chế độ nền, nhưng ở đây tôi sẽ không có quyền truy cập vào số lượng chủ đề tôi muốn trong nhóm chủ đề và nó thay đổi theo phiên bản Android khác nhau, nhưng trong Lựa chọn 3 tôi có thể đưa ra quyết định có ý thức kích thước của nhóm luồng tùy thuộc vào cấu hình thiết bị được sử dụng.

Đây là mã nguồn:

public class MainActivity extends ActionBarActivity {

    GridView imageGridView;
    ArrayList<FlickrItem> items = new ArrayList<FlickrItem>();
    FlickrAdapter adapter;

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

        imageGridView = (GridView) findViewById(R.id.gridView1);
        adapter = new FlickrAdapter(this, items);
        imageGridView.setAdapter(adapter);
    }

    // To avoid a memory leak on configuration change making it a inner class
    class FlickrDownloader extends AsyncTask<Void, Void, Void> {



        @Override
        protected Void doInBackground(Void... params) {
            FlickrGetter getter = new FlickrGetter();

            ArrayList<FlickrItem> newItems = getter.fetchItems();

            // clear the existing array
            items.clear();

            // add the new items to the array
            items.addAll(newItems);

            // is this correct ? - Wrong rebuilding the list view and should not be done in background
            //adapter.notifyDataSetChanged();

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            adapter.notifyDataSetChanged();
        }

    }

    public void search(View view) {
        // get the flickr data
        FlickrDownloader downloader = new FlickrDownloader();
        downloader.execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

Tôi hy vọng câu trả lời của tôi mặc dù lâu sẽ giúp hiểu được một số chi tiết tốt hơn.


Tôi có thể biết lý do tại sao lời giải thích của tôi trên cơ sở một ví dụ cho lợi ích tương tự đã bị bỏ phiếu, để tôi cũng học hỏi từ nó không?
akshaymani

2
trước hết cảm ơn câu trả lời của bạn, mặc dù chủ đề này hơi cũ nhưng các khái niệm cốt lõi vẫn được cập nhật. Câu hỏi ban đầu của tôi hoàn toàn không được trả lời, bạn đang đưa ra một ví dụ và giải thích cách thức hoạt động của nó, nhưng các câu hỏi yêu cầu sự khác biệt giữa xử lý, asynctask và luồng.
Alx

@ 80leaves ok tôi nhận được điểm bây giờ, tôi đã cố gắng giải thích làm thế nào tôi đi đến kết luận về việc chọn cách này hơn cách khác. Dù sao, rất thích nghe quan điểm của bạn / người khác về việc những gì tôi viết là chính xác hay liệu nó có thể được cải thiện hơn nữa.
akshaymani

1

Nó phụ thuộc vào cái nào được chọn dựa trên yêu cầu

Handler chủ yếu được sử dụng để chuyển từ luồng khác sang luồng chính, Handler được gắn vào một kẻ lừa đảo mà nó đăng nhiệm vụ có thể chạy của nó trong hàng đợi. Vì vậy, nếu bạn đã ở trong luồng khác và chuyển sang luồng chính thì bạn cần xử lý thay vì tác vụ không đồng bộ hoặc luồng khác

Nếu Handler được tạo không phải là luồng chính không phải là kẻ lừa đảo thì sẽ không có lỗi vì xử lý được tạo ra luồng, luồng đó cần được tạo thành một phễu

AsyncTask được sử dụng để thực thi mã trong vài giây chạy trên luồng nền và đưa kết quả của nó vào luồng chính ** * Hạn chế AsyncTask 1. Nhiệm vụ Async không được gắn vào vòng đời của hoạt động và nó vẫn chạy ngay cả khi hoạt động của nó bị hủy trong khi trình tải không hoạt động Không có giới hạn này 2. Tất cả các Tác vụ không đồng bộ chia sẻ cùng một luồng nền để thực thi, điều này cũng ảnh hưởng đến hiệu suất ứng dụng

Chủ đề cũng được sử dụng trong ứng dụng cho công việc nền nhưng nó không có bất kỳ cuộc gọi lại nào trên chủ đề chính. Nếu yêu cầu phù hợp với một số luồng thay vì một luồng và cần thực hiện nhiệm vụ nhiều lần thì trình thực thi nhóm luồng là tùy chọn tốt hơn.Eg Yêu cầu tải hình ảnh từ nhiều url như lướt.


0

Chủ đề

Khi bạn khởi động một ứng dụng, một quy trình được tạo để thực thi mã. Để sử dụng hiệu quả tài nguyên điện toán, các luồng có thể được bắt đầu trong quy trình để có thể thực hiện nhiều tác vụ tại thời điểm đó. Vì vậy, các chủ đề cho phép bạn xây dựng các ứng dụng hiệu quả bằng cách sử dụng cpu hiệu quả mà không có thời gian nhàn rỗi.

Trong Android, tất cả các thành phần thực thi trên một luồng duy nhất được gọi là luồng chính. Nhiệm vụ xếp hàng hệ thống Android và thực hiện từng cái một trên luồng chính. Khi các tác vụ chạy dài được thực thi, ứng dụng sẽ không phản hồi.

Để ngăn chặn điều này, bạn có thể tạo các luồng công nhân và chạy các tác vụ nền hoặc chạy dài.

Xử lý

Vì android sử dụng mô hình luồng đơn, các thành phần UI được tạo không an toàn cho luồng chỉ có nghĩa là luồng mà nó tạo nên truy cập vào chúng có nghĩa là thành phần UI chỉ nên được cập nhật trên luồng chính. Khi thành phần UI chạy trên luồng chính, các tác vụ chạy trên luồng công nhân không thể sửa đổi các thành phần UI. Đây là nơi Handler đi vào hình ảnh. Trình xử lý với sự trợ giúp của Looper có thể kết nối với luồng mới hoặc luồng hiện có và chạy mã mà nó chứa trên luồng được kết nối.

Handler làm cho nó có thể cho giao tiếp liên chủ đề. Sử dụng Handler, luồng nền có thể gửi kết quả đến nó và trình xử lý được kết nối với luồng chính có thể cập nhật các thành phần UI trên luồng chính.

AsyncTask

AsyncTask được cung cấp bởi Android sử dụng cả luồng và trình xử lý để giúp chạy các tác vụ đơn giản trong nền và cập nhật kết quả từ luồng nền sang luồng chính dễ dàng.

Vui lòng xem chủ đề android, handler, asynctask và thread pool để biết ví dụ.


-1

Handler- là phương tiện liên lạc giữa các chủ đề. Trong Android, nó chủ yếu được sử dụng để giao tiếp với luồng chính bằng cách tạo và gửi tin nhắn thông qua trình xử lý

AsyncTask- được sử dụng để thực hiện các ứng dụng chạy dài trong một luồng nền. Với n AsyncTaskbạn nhận được có thể thực hiện thao tác trong một luồng nền và nhận kết quả trong luồng chính của ứng dụng.

Thread- là một quá trình trọng lượng nhẹ, để đạt được sự đồng thời và sử dụng cpu tối đa. Trong Android, bạn có thể sử dụng chuỗi để thực hiện các hoạt động không chạm vào giao diện người dùng của ứng dụng

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.