Trang chủ > Phát triển di động > Nội dung chính

Xử lý bất đồng bộ trong phát triển Android và iOS (phần ba) —— Cộng tác giữa nhiều tác vụ bất đồng bộ


Bài viết này là phần tiếp theo của loạt bài viết về: Xử lý bất đồng bộ trong phát triển Android và iOS. Trong phần thứ ba của tác phẩm nàyVSBET, chúng ta sẽ tập trung những vấn đề có thể phát sinh khi thực hiện đồng thời nhiều tác vụ bất đồng bộ. Việc quản lý và xử lý các tác vụ như vậy thường đòi hỏi kỹ năng đặc biệt để đảm bảo hiệu quả và độ tin cậy trong quá trình vận hành.

Thông thườngkết quả bóng đá việt nam hôm nay, chúng ta cần thực hiện nhiều tác vụ bất đồng bộ và khiến chúng phối hợp với nhau để hoàn thành yêu cầu. Bài viết này sẽ phân tích ba mối quan hệ phối hợp giữa các tác vụ bất đồng bộ dựa trên các tình huống sử dụng điển hình trong thực tế: 1. **Mối quan hệ tuần tự (Sequence):** Khi các tác vụ phải được thực hiện theo trình tự nhất định, chẳng hạn như tải dữ liệu từ một nguồn trước khi xử lý tiếp ở bước kế tiếp. 2. **Mối quan hệ song song (Parallel):** Trong trường hợp cần chạy nhiều tác vụ cùng lúc để tối ưu hóa hiệu suất, ví dụ như tải nhiều tệp tin cùng một lúc từ các máy chủ khác nhau. 3. **Mối quan hệ có điều kiện (Conditional):** Các tác vụ chỉ được kích hoạt khi một điều kiện nào đó đã đạt được, chẳng hạn như chờ đợi kết quả từ một tác vụ trước đó để quyết định có nên tiếp tục hay không. Hãy cùng tìm hiểu sâu hơn về từng loại mối quan hệ này nhé!

  • Thực hiện tuần tự sau nhau.
  • Thực hiện song song và hợp nhất kết quả.
  • Thực hiện song song nhưng ưu tiên một bên.

Ba mối quan hệ hợp tác trên sẽ được thảo luận chi tiết qua ba ví dụ ứng dụng cụ thể trong bài viết này. Ba ứng dụng này bao gồm:

  • Đa cấp bộ nhớ đệm.
  • Yêu cầu mạ
  • Bộ nhớ đệm trang web.

yêu cầu mạng song song

Lưu ý: Mã nguồn trong loạt bài viết này đã được tổ chức trên GitHub (liên tục cập nhật)keo banh, đường dẫn kho lưu trữ là:

Trong bài viết nàyVSBET, đoạn mã Java được đề cập nằm trong gói (package) có tên là `com. demos.async. multitask`. Đây là một phần quan trọng của chương trình, giúp người đọc hiểu rõ hơn về cách triển khai lập trình đa nhiệm trong môi trường đồng bộ và bất đồng bộ.


Nhiều nhiệm vụ bất đồng bộ thực hiện tuần tự.

Thực hiện tuần tự

Một ví dụ điển hình là việc đa cấp bộ nhớ đệm cho tài nguyên tĩnhVSBET, trong đó người ta thường nhắc đến nhiều nhất chính là việc đa cấp bộ nhớ đệm cho hình ảnh tĩnh. Khi tải một hình ảnh tĩnh trên client, thông thường sẽ có ít nhất hai cấp bộ nhớ đệm: bộ nhớ đệm đầu tiên là Memory Cache (bộ nhớ cache trong bộ nhớ RAM) và bộ nhớ đệm thứ hai là Disk Cache (bộ nhớ cache trên ổ cứng). Quy trình tải hình ảnh này diễn ra như sau: Trước hết, khi người dùng yêu cầu tải một hình ảnh tĩnh, hệ thống sẽ kiểm tra Memory Cache trước tiên. Nếu hình ảnh đã tồn tại trong bộ nhớ đệm RAM, nó sẽ được trả về ngay lập tức mà không cần truy cập đến ổ đĩa hoặc nguồn gốc ban đầu. Điều này giúp tăng tốc đáng kể quá trình tải, đặc biệt đối với những hình ảnh thường xuyên được sử dụng. Nếu hình ảnh không có sẵn trong bộ nhớ RAM, hệ thống sẽ tiếp tục kiểm tra ở Ở cấp độ này, hình ảnh sẽ được lưu trữ tạm thời trên ổ cứng của thiết bị. Việc kiểm tra Disk Cache nhanh hơn so với việc tải hình ảnh trực tiếp từ máy chủ, vì vậy nó vẫn mang lại hiệu quả cao hơn so với việc tải hoàn toàn mới. Chỉ khi cả Memory Cache và Disk Cache đều không chứa hình ảnh cần tìm, hệ thống mới tiến hành tải hình ảnh từ nguồn gốc ban đầu như một server hoặc API. Điều này giúp tối ưu hóa hiệu suất và giảm thiểu sự phụ thuộc vào băng thông mạng, đồng thời cải thiện trải nghiệm người dùng.

  1. Đầu tiên kiểm tra bộ nhớ đệm Memorykeo banh, nếu trúng, trả về ngay lập tức; nếu không, tiến hành bước tiếp theo.
  2. Kiểm tra bộ nhớ đệm Disk tiếp theokeo banh, nếu trúng, trả về ngay lập tức; nếu không, tiến hành bước tiếp theo.
  3. Phát yêu cầu mạng để tải xuống và giải mã tệp hình ảnh.

thực hiện yêu cầu mạng

tìm kiếm Disk Cache

Trước tiênkết quả bóng đá việt nam hôm nay, chúng ta cần xác định rõ giao diện cho hai tác vụ bất đồng bộ là "Bộ đệm Disk" và "Yêu cầu mạng". Điều này sẽ giúp chúng ta tổ chức mã nguồn một cách có trật tự và dễ bảo trì hơn. Hai tác vụ này đóng vai trò quan trọng trong việc tối ưu hóa hiệu suất ứng dụng của chúng ta.

								
									
										public
									 interface
									 ImageDiskCache
									 {
									
    /** * Lấy đồng bộ hình ảnh Bitmap từ bộ nhớ đệm với khóa được chỉ định. * @param key Chuỗi khóa để tìm kiếm trong bộ nhớ đệm. * @param callback Hàm trả về đối tượng Bitmap được lưu trữ trong bộ nhớ đệm. */
    void
									 getImage
									(
									String
									 key
									,
									 AsyncCallback
									<
									Bitmap
									>
									 callback
									);
									
    /** * Lưu đối tượng Bitmap vào bộ nhớ đệm. * @param key Chuỗi duy nhất để xác định vị trí lưu trữ trong bộ nhớ đệm. * @param bitmap Đối tượng Bitmap cần được lưu giữ. * @param callback Hàm trả về kết quả của hoạt động lưu trữkeo banh, cho biết thành công hay thất bại. */
    void
									 putImage
									(
									String
									 key
									,
									 Bitmap
									 bitmap
									,
									 AsyncCallback
									<
									Boolean
									>
									 callback
									);
									
}
									

								

Giao diện ImageDiskCache được sử dụng để lưu trữ và truy xuất Cache hình ảnh trên đĩakết quả bóng đá việt nam hôm nay, trong đó tham số AsyncCallback là định nghĩa của một giao diện gọi lại bất đồng bộ chung. Mã định nghĩa của nó như sau (sẽ còn được đề cập đến ở phần sau): interface AsyncCallback { void onSuccess(T result); void onFailure(Throwable error); } Hãy cùng khám phá cách mà giao diện này đóng vai trò quan trọng trong việc quản lý hình ảnh trên hệ thống đĩa một cách hiệu quả và linh hoạt.

								
									/**<d>Kiểu dữ liệu tham số trả về từ giao diện bất đồng bộ.</d>
public
									 interface
									 AsyncCallback
									 <
									D
									>
									 {
									
    void
									 onResult
									(
									D
									 data
									);
									
}
									

								

Còn việc tải xuống tệp hình ảnh qua mạngkeo banh, chúng ta có thể gọi trực tiếp từ bài viết trước về: Xử lý bất đồng bộ trong phát triển Android và iOS (phần hai) —— Gọi lại cho tác vụ bất đồng bộ Trong tài liệu đã đề cập đến giao diện Downloader (chú ý: phiên bản của giao diện Downloader có tham số contextData ở cuối).

Phát yêu cầu tải xuống mạng

								
									//Kiểm tra bộ nhớ đệm thứ hai: bộ nhớ đệm Disk
    imageDiskCache
									.
									getImage
									(
									url
									,
									 new
									 AsyncCallback
									<
									Bitmap
									>()
									 {
									
        @Override
									
        public
									 void
									 onResult
									(
									Bitmap
									 bitmap
									)
									 {
									
            if
									 (
									bitmap
									 !=
									 null
									)
									 {
									
                //Đã trúng bộ nhớ đệm DiskVSBET, nhiệm vụ tải về kết thúc sớm.
                imageMemCache
									.
									putImage
									(
									url
									,
									 bitmap
									);
									
                successCallback
									(
									url
									,
									 bitmap
									,
									 contextData
									);
									
            }
									
            else
									 {
									
                //Không trúng cả hai cấp bộ nhớ đệmVSBET, gọi tải về để tải xuống
                downloader
									.
									startDownload
									(
									url
									,
									 getLocalPath
									(
									url
									),
									 contextData
									);
									
            }
									
        }
									
    });
									

								

Ví dụ mã thực hiện callback kết quả thành công của Downloader như sau:

								
									@Override
									
    public
									 void
									 downloadSuccess
									(
									final
									 String
									 url
									,
									 final
									 String
									 localPath
									,
									 final
									 Object
									 contextData
									)
									 {
									
        //Giải mã hình ảnhVSBET, đây là một hoạt động tiêu tốn thời gian, nên làm bất đồng bộ.
        imageDecodingExecutor
									.
									execute
									(
									new
									 Runnable
									()
									 {
									
            @Override
									
            public
									 void
									 run
									()
									 {
									
                final
									 Bitmap
									 bitmap
									 =
									 decodeBitmap
									(
									new
									 File
									(
									localPath
									));
									
                //Sắp xếp lại vào luồng chính.
                mainHandler
									.
									post
									(
									new
									 Runnable
									()
									 {
									
                    @Override
									
                    public
									 void
									 run
									()
									 {
									
                        if
									 (
									bitmap
									 !=
									 null
									)
									 {
									
                            imageMemCache
									.
									putImage
									(
									url
									,
									 bitmap
									);
									
                            imageDiskCache
									.
									putImage
									(
									url
									,
									 bitmap
									,
									 null
									);
									
                            successCallback
									(
									url
									,
									 bitmap
									,
									 contextData
									);
									
                        }
									
                        else
									 {
									
                            //Giải mã thất bại
                            failureCallback
									(
									url
									,
									 ImageLoaderListener
									.
									BITMAP_DECODE_FAILED
									,
									 contextData
									);
									
                        }
									
                    }
									
                });
									
            }
									
        });
									
    }
									

								

Nhiều nhiệm vụ bất đồng bộ thực hiện song song và hợp nhất kết quả.

Thực thi đồng thờikết quả bóng đá việt nam hôm nay, hợp nhất kết quả

Một ví dụ điển hình là khi bạn gửi đồng thời nhiều yêu cầu mạng (các giao diện API từ xa)kết quả bóng đá việt nam hôm nay, sau đó đợi tất cả các phản hồi từ các yêu cầu này và xử lý dữ liệu một cách đồng bộ trước khi cập nhật giao diện người dùng. Cách làm này giúp giảm thiểu tổng thời gian yêu cầu bằng cách tận dụng tính năng đa luồng trong việc gửi yêu cầu mạng. Điều thú vị là, thay vì chờ từng yêu cầu hoàn thành riêng lẻ, việc thực hiện song song không chỉ cải thiện hiệu suất mà còn tạo ra trải nghiệm mượt mà hơn cho người dùng.

Chúng tôi sẽ đưa ra ví dụ mã nguồn dựa trên tình huống đơn giản nhất của hai yêu cầu mạ

Trước tiênkeo banh, vẫn cần định nghĩa trước các giao diện bất đồng bộ cần thiết, tức là định nghĩa giao diện API từ xa.

								
									/**
public
									 interface
									 HttpService
									 {
									
    /** * Gửi yêu cầu HTTP. * @param apiUrl Đường URL yêu cầu * @param request Đối tượng tham số yêu cầu (được biểu diễn bằng Java Bean) * @param listener Bộ xử lý sự kiện * @param contextData Dữ liệu truyền thông giữa các lớp * @param */<t>Kiểu Model yêu cầu<r>Kiểu Model phản hồi</r></t>
    <
									T
									,
									 R
									>
									 void
									 doRequest
									(
									String
									 apiUrl
									,
									 T
									 request
									,
									 HttpListener
									<?
									 super
									 T
									,
									 R
									>
									 listener
									,
									 Object
									 contextData
									);
									
}
									

/**<t>Kiểu Model yêu cầu<r>Kiểu Model phản hồi</r></t>
public
									 interface
									 HttpListener
									 <
									T
									,
									 R
									>
									 {
									
    /** * Giao diện callback được kích hoạt khi yêu cầu kết thúc với trạng thái thành công hoặc thất bại. * @param apiUrl Đường dẫn URL của yêu cầu * @param request Đối tượng chứa thông tin chi tiết về yêu cầu * @param result Kết quả cuối cùng của yêu cầu (bao gồm phản hồi hoặc lý do lỗi) * @param contextData Dữ liệu truyền tải phụ trợ giữ các lần gọi */
    void
									 onResult
									(
									String
									 apiUrl
									,
									 T
									 request
									,
									 HttpResult
									<
									R
									>
									 result
									,
									 Object
									 contextData
									);
									
}
									

								

Điều cần lưu ý là trong giao diện HttpServicekeo banh, tham số yêu cầu request được định nghĩa bằng kiể Nếu có một thực hiện cho giao diện này, mã thực hiện sẽ cần xử lý dựa trên loại thực tế của request (có thể là bất kỳ Java Bean nào), sử dụng cơ chế phản chiếu để chuyển đổi nó thành các tham số yêu cầu HTTP. Tất nhiên, ở đây chúng ta chỉ tập trung vào việc phân tích giao diện, còn việc cụ thể hóa cách triển khai không phải là trọng tâm thảo luận tại thời điểm này.

Tham số kết quả trả về result là kiểu HttpResultkết quả bóng đá việt nam hôm nay, điều này cho phép nó vừa có thể biểu thị kết quả phản hồi thành công, vừa có thể biểu thị kết quả phản hồi thất bại. Định nghĩa của HttpResult như sau: ``` class HttpResult { boolean isSuccess; String message; Object data; HttpResult(boolean isSuccess, String message, Object data) { isSuccess = isSuccess; message = message; data = data; } // Getter và Setter cho các thuộc tính public boolean isSuccess() { return isSuccess; } public void setSuccess(boolean success) { isSuccess = success; } public String getMessage() { return message; } public void setMessage(String message) { message = message; } public Object getData() { return data; } public void setData(Object data) { data = data; } } ``` Với cấu trúc này, HttpResult trở thành một công cụ linh hoạt để xử lý cả hai trường hợp kết quả trả về từ một yêu cầu HTTP.

								
									/** * Lớp HttpResult được thiết kế để đóng gói kết quả của các yêu cầu HTTP. Khi máy chủ phản hồi thành côngVSBET, mã lỗi errorCode sẽ bằng với SUCCESS và nội dung phản hồi từ máy chủ sẽ được chuyển đổi thành đối tượ Ngược lại, nếu máy chủ không thể phản hồi đúng cách, mã lỗi errorCode sẽ khác SUCCESS và giá trị của response sẽ không hợp lệ. */Kiểu Model phản hồi
public
									 class
									 HttpResult
									 <
									R
									>
									 {
									
    /**
    public
									 static
									 final
									 int
									 SUCCESS
									 =
									 0
									;
									//Thành công
    public
									 static
									 final
									 int
									 REQUEST_ENCODING_ERROR
									 =
									 1
									;
									//Lỗi khi mã hóa yêu cầu
    public
									 static
									 final
									 int
									 RESPONSE_DECODING_ERROR
									 =
									 2
									;
									//Lỗi khi giải mã phản hồi
    public
									 static
									 final
									 int
									 NETWORK_UNAVAILABLE
									 =
									 3
									;
									//Mạng không khả dụng
    public
									 static
									 final
									 int
									 UNKNOWN_HOST
									 =
									 4
									;
									//Lỗi phân giải tên miền
    public
									 static
									 final
									 int
									 CONNECT_TIMEOUT
									 =
									 5
									;
									//Hết thời gian kết nối
    public
									 static
									 final
									 int
									 HTTP_STATUS_NOT_OK
									 =
									 6
									;
									//Yêu cầu tải xuống trả về mã khác 200
    public
									 static
									 final
									 int
									 UNKNOWN_FAILED
									 =
									 7
									;
									//Lỗi chưa xác định khác

    private
									 int
									 errorCode
									;
									
    private
									 String
									 errorMessage
									;
									
    /** * Trả về là phản hồi mà máy chủ gửi lại. * Chỉ khi errorCode được gán giá trị SUCCESS thì phản hồi trong response mới có giá trị hợp lệ. */
    private
									 R
									 response
									;
									

    public
									 int
									 getErrorCode
									()
									 {
									
        return
									 errorCode
									;
									
    }
									

    public
									 void
									 setErrorCode
									(
									int
									 errorCode
									)
									 {
									
        this
									.
									errorCode
									 =
									 errorCode
									;
									
    }
									

    public
									 String
									 getErrorMessage
									()
									 {
									
        return
									 errorMessage
									;
									
    }
									

    public
									 void
									 setErrorMessage
									(
									String
									 errorMessage
									)
									 {
									
        this
									.
									errorMessage
									 =
									 errorMessage
									;
									
    }
									

    public
									 R
									 getResponse
									()
									 {
									
        return
									 response
									;
									
    }
									

    public
									 void
									 setResponse
									(
									R
									 response
									)
									 {
									
        this
									.
									response
									 =
									 response
									;
									
    }
									
}
									

								

Kết quả HttpResult cũng bao gồm một kiểu Generic Rkết quả bóng đá việt nam hôm nay, đây chính là kiểu tham số phản hồi được trả về khi yêu cầu thành công. Tương tự, trong việc triển khai có thể của HttpService, cơ chế phản chiếu (reflection) sẽ lại được sử dụng để biến đổi nội dung phản hồi từ yêu cầu (có thể là chuỗi JSON) thành kiểu R (kiểu này có thể là bất kỳ đối tượng Java nào). Điều này giúp tăng tính linh hoạt và khả năng tùy chỉnh cho ứng dụng, đảm bảo rằng dữ liệu nhận được có thể dễ dàng được xử lý theo định dạng mong muốn mà không gặp bất kỳ trở ngại nào trong việc chuyển đổi loại dữ liệu.

Rồikeo banh, bây giờ khi đã có giao diện HttpService, chúng ta có thể trình diễn cách gửi đồng thời hai yêu cầu mạng. Điều này giúp tiết kiệm thời gian và tối ưu hóa hiệu suất, đặc biệt hữu ích khi cần xử lý nhiều tác vụ cùng lúc trên ứng dụng của bạn.

								
									
										public
									 class
									 MultiRequestsDemoActivity
									 extends
									 AppCompatActivity
									 {
									
    private
									 HttpService
									 httpService
									 =
									 new
									 MockHttpService
									();
									
    /**
    private
									 Map
									<
									String
									,
									 Object
									>
									 httpResults
									 =
									 new
									 HashMap
									<
									String
									,
									 Object
									>();
									

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

        //Khởi động đồng thời hai yêu cầu bất đồng bộ
        httpService
									.
									doRequest
									(
									"http://..."
									,
									 new
									 HttpRequest1
									(),
									
                new
									 HttpListener
									<
									HttpRequest1
									,
									 HttpResponse1
									>()
									 {
									
                    @Override
									
                    public
									 void
									 onResult
									(
									String
									 apiUrl
									,
									
                                         HttpRequest1
									 request
									,
									
                                         HttpResult
									<
									HttpResponse1
									>
									 result
									,
									
                                         Object
									 contextData
									)
									 {
									
                        //Lưu trữ kết quả yêu cầu
                        httpResults
									.
									put
									(
									"request-1"
									,
									 result
									);
									
                        if
									 (
									checkAllHttpResultsReady
									())
									 {
									
                            //Cả hai yêu cầu đã kết thúc
                            HttpResult
									<
									HttpResponse1
									>
									 result1
									 =
									 result
									;
									
                            HttpResult
									<
									HttpResponse2
									>
									 result2
									 =
									 (
									HttpResult
									<
									HttpResponse2
									>)
									 httpResults
									.
									get
									(
									"request-2"
									);
									
                            if
									 (
									checkAllHttpResultsSuccess
									())
									 {
									
                                //Cả hai yêu cầu đều thành công
                                processData
									(
									result1
									.
									getResponse
									(),
									 result2
									.
									getResponse
									());
									
                            }
									
                            else
									 {
									
                                //Cả hai yêu cầu không hoàn toàn thành côngkeo banh, xử lý như thất bại
                                processError
									(
									result1
									.
									getErrorCode
									(),
									 result2
									.
									getErrorCode
									());
									
                            }
									
                        }
									
                    }
									
                },
									
                null
									);
									
        httpService
									.
									doRequest
									(
									"http://..."
									,
									 new
									 HttpRequest2
									(),
									
                new
									 HttpListener
									<
									HttpRequest2
									,
									 HttpResponse2
									>()
									 {
									
                    @Override
									
                    public
									 void
									 onResult
									(
									String
									 apiUrl
									,
									
                                         HttpRequest2
									 request
									,
									
                                         HttpResult
									<
									HttpResponse2
									>
									 result
									,
									
                                         Object
									 contextData
									)
									 {
									
                        //Lưu trữ kết quả yêu cầu
                        httpResults
									.
									put
									(
									"request-2"
									,
									 result
									);
									
                        if
									 (
									checkAllHttpResultsReady
									())
									 {
									
                            //Cả hai yêu cầu đã kết thúc
                            HttpResult
									<
									HttpResponse1
									>
									 result1
									 =
									 (
									HttpResult
									<
									HttpResponse1
									>)
									 httpResults
									.
									get
									(
									"request-1"
									);
									
                            HttpResult
									<
									HttpResponse2
									>
									 result2
									 =
									 result
									;
									
                            if
									 (
									checkAllHttpResultsSuccess
									())
									 {
									
                                //Cả hai yêu cầu đều thành công
                                processData
									(
									result1
									.
									getResponse
									(),
									 result2
									.
									getResponse
									());
									
                            }
									
                            else
									 {
									
                                //Cả hai yêu cầu không hoàn toàn thành côngkết quả bóng đá việt nam hôm nay, xử lý như thất bại
                                processError
									(
									result1
									.
									getErrorCode
									(),
									 result2
									.
									getErrorCode
									());
									
                            }
									
                        }
									
                    }
									
                },
									
                null
									);
									
    }
									

    /** * Kiểm tra xem tất cả các yêu cầu đã có kết quả hay chưa * @return */
    private
									 boolean
									 checkAllHttpResultsReady
									()
									 {
									
        int
									 requestsCount
									 =
									 2
									;
									
        for
									 (
									int
									 i
									 =
									 1
									;
									 i
									 <=
									 requestsCount
									;
									 i
									++)
									 {
									
            if
									 (
									httpResults
									.
									get
									(
									"request-"
									 +
									 i
									)
									 ==
									 null
									)
									 {
									
                return
									 false
									;
									
            }
									
        }
									
        return
									 true
									;
									
    }
									

    /** * Kiểm tra xem tất cả các yêu cầu có đều thành công hay không * @return */
    private
									 boolean
									 checkAllHttpResultsSuccess
									()
									 {
									
        int
									 requestsCount
									 =
									 2
									;
									
        for
									 (
									int
									 i
									 =
									 1
									;
									 i
									 <=
									 requestsCount
									;
									 i
									++)
									 {
									
            HttpResult
									<? > result
									 =
									 (
									HttpResult
									<? >) httpResults
									.
									get
									(
									"request-"
									 +
									 i
									);
									
            if
									 (
									result
									 ==
									 null
									 ||
									 result
									.
									getErrorCode
									()
									 !=
									 HttpResult
									.
									SUCCESS
									)
									 {
									
                return
									 false
									;
									
            }
									
        }
									
        return
									 true
									;
									
    }
									

    private
									 void
									 processData
									(
									HttpResponse1
									 data1
									,
									 HttpResponse2
									 data2
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngkeo banh, hiển thị kết quả yêu cầu. Code ở đây bị lược bỏ
    }
									

    private
									 void
									 processError
									(
									int
									 errorCode1
									,
									 int
									 errorCode2
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngkeo banh, hiển thị lỗi. Code ở đây bị lược bỏ
    }
									
}
									

								

Trước tiênVSBET, chúng ta cần chờ cho đến khi cả hai yêu cầu hoàn tất trước khi có thể hợp nhất kết quả của chúng. Để xác định liệu hai yêu cầu bất đồng bộ này đã hoàn thành hay chưa, chúng ta phải kiểm tra xem tất cả các yêu cầu đã trả về hay chưa mỗi khi một trong những yêu cầu nhận được phản hồi. Điều quan trọng cần lưu ý ở đây là chúng ta có thể áp dụng phương pháp kiểm tra này nhờ vào một điều kiện tiên quyết rất quan trọng: onResult của HttpService đã được lên lịch để thực thi trên luồng chính. Trong bài viết trước, " Xử lý bất đồng bộ trong phát triển Android và iOS (phần hai) —— Gọi lại cho tác vụ bất đồng bộ Trong phần “mô hình luồng của hàm callback” trong tài liệukết quả bóng đá việt nam hôm nay, đã có đề cập đến môi trường luồng nơi callback xảy ra. Khi onResult đã được lên lịch để chạy trên luồng chính, thứ tự thực thi của hai callback onResult từ hai yêu cầu sẽ chỉ có hai khả năng: hoặc là thực thi onResult của yêu cầu đầu tiên trước rồi mới đến onResult của yêu cầu thứ hai; hoặc ngược lại, thực thi onResult của yêu cầu thứ hai trước và sau đó mới đến yêu cầu đầu tiên. Dù theo thứ tự nào đi chăng nữa, các câu lệnh kiểm tra bên trong onResult vẫn sẽ hoạt động hiệu quả và chính xác. Điều này đảm bảo rằng việc xử lý dữ liệu không bị ảnh hưởng bởi sự khác biệt trong thứ tự thực thi giữa cá

Tuy nhiênkeo banh, nếu phương thức onResult của HttpService được thực hiện trên các luồng khác nhau, hai callback onResult của các yêu cầu có thể sẽ chạy xen kẽ, dẫn đến các vấn đề đồng bộ bên trong các phép kiểm tra và xử lý. Điều này có thể gây ra sự không ổn định khi dữ liệu từ các yêu cầu khác nhau bị trộn lẫn hoặc xử lý không đúng cách. Vì vậy, việc quản lý trạng thái và đồng bộ hóa giữa các luồng trở nên vô cùng quan trọng để tránh những hậu quả không mong muốn.

thực thi tuần tự

Nhiều nhiệm vụ bất đồng bộ thực hiện song songkeo banh, một bên ưu tiên.

Thực hiện đồng thời với ưu tiên cho một bên

Một ví dụ điển hình là bộ nhớ đệm trang. Chẳng hạnkeo banh, một trang web cần hiển thị danh sách dữ liệu động. Nếu mỗi lần người dùng mở trang đều chỉ lấy danh sách dữ liệu từ máy chủ, thì trong trường hợp không có kết nối mạng hoặc mạng chậm, trang sẽ bị trống trong thời gian dài, khiến trải nghiệm người dùng trở nên tệ hại. Trong những tình huống như vậy, việc hiển thị dữ liệu cũ thường tốt hơn là để trang hoàn toàn trắng. Do đó, chúng ta thường nghĩ đến việc thêm vào cơ chế bộ nhớ đệm cục bộ để lưu trữ dữ liệu danh sách này một cách vĩnh viễn. Việc lưu trữ dữ liệu cục bộ không chỉ giúp cải thiện hiệu suất mà còn giảm tải cho máy chủ. Khi không có kết nối mạng hoặc khi người dùng ở vùng có tốc độ internet yếu, bộ nhớ đệm sẽ tự động cung cấp dữ liệu từ bộ nhớ trước đó. Tuy nhiên, cần phải cân nhắc rằng việc sử dụng bộ nhớ đệm cũng cần được quản lý cẩn thận, chẳng hạn như cập nhật dữ liệu thường xuyên và đảm bảo dữ liệu cũ không làm sai lệch thông tin quan trọng. Điều này giúp duy trì sự chính xác và tính năng động của trang web trong mọi tình huống.

Bộ nhớ đệm cục bộ cũng là một nhiệm vụ bất đồng bộkeo banh, giao diện mã định nghĩa như sau:

								
									
										public
									 interface
									 LocalDataCache
									 {
									
    /** * Lấy đồng bộ đối tượng HttpResponse từ bộ nhớ đệm cục bộ. * @param key Khóa để xác định vị trí của đối tượng trong bộ nhớ đệm * @param callback Hàm trả về đối tượng đã lưu trữ từ bộ nhớ đệm */
    void
									 getCachingData
									(
									String
									 key
									,
									 AsyncCallback
									<
									HttpResponse
									>
									 callback
									);
									

    /** * Lưu đối tượng HttpResponse vào bộ nhớ cache. * @param key Chuỗi duy nhất để xác định vị trí lưu trữ * @param data Đối tượng HttpResponse cần được lưu giữ. * @param callback Hàm trả về kết quả hoạt động lưu trữkết quả bóng đá việt nam hôm nay, cho biết thành công hay thất bại. */
    void
									 putCachingData
									(
									String
									 key
									,
									 HttpResponse
									 data
									,
									 AsyncCallback
									<
									Boolean
									>
									 callback
									);
									
}
									

								

Dữ liệu được lưu trong bộ nhớ cache cục bộ này chính là đối tượng HttpResponse mà trước đó đã được lấy từ máy chủ. Giao diện gọi lại bất đồng bộ AsyncCallbackkeo banh, chúng ta đã đề cập đến điều này ở phần trước. Ngoài ra, việc sử dụng bộ nhớ cache giúp tối ưu hóa hiệu suất, đặc biệt khi dữ liệu cần được truy xuất nhanh chóng mà không cần phải liên tục yêu cầu từ máy chủ.

Khi trang web được mởkeo banh, chúng ta có thể khởi động đồng thời nhiệm vụ đọc từ bộ nhớ đệm cục bộ và nhiệm vụ yêu cầu API từ xa. Trong đó, nhiệm vụ thứ hai sẽ có ưu tiên cao hơn so với nhiệm vụ đầu tiên. Điều này giúp đảm bảo rằng dữ liệu quan trọng từ nguồn bên ngoài sẽ được xử lý nhanh chóng trước khi tiếp tục với các hoạt động khác.

								
									
										public
									 class
									 PageCachingDemoActivity
									 extends
									 AppCompatActivity
									 {
									
    private
									 HttpService
									 httpService
									 =
									 new
									 MockHttpService
									();
									
    private
									 LocalDataCache
									 localDataCache
									 =
									 new
									 MockLocalDataCache
									();
									
    /**
    private
									 boolean
									 dataFromHttpReady
									;
									

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

        //Khởi động đồng thời yêu cầu dữ liệu cục bộ và yêu cầu HTTP từ xa
        final
									 String
									 userId
									 =
									 "xxx"
									;
									
        localDataCache
									.
									getCachingData
									(
									userId
									,
									 new
									 AsyncCallback
									<
									HttpResponse
									>()
									 {
									
            @Override
									
            public
									 void
									 onResult
									(
									HttpResponse
									 data
									)
									 {
									
                if
									 (
									data
									 !=
									 null
									 &&
									 !
									dataFromHttpReady
									)
									 {
									
                    //Có dữ liệu cũ trong bộ nhớ đệm & yêu cầu HTTP từ xa chưa trả vềVSBET, hiển thị dữ liệu cũ trước
                    processData
									(
									data
									);
									
                }
									
            }
									
        });
									
        httpService
									.
									doRequest
									(
									"http://..."
									,
									 new
									 HttpRequest
									(),
									
                new
									 HttpListener
									<
									HttpRequest
									,
									 HttpResponse
									>()
									 {
									
                    @Override
									
                    public
									 void
									 onResult
									(
									String
									 apiUrl
									,
									
                                         HttpRequest
									 request
									,
									
                                         HttpResult
									<
									HttpResponse
									>
									 result
									,
									
                                         Object
									 contextData
									)
									 {
									
                        if
									 (
									result
									.
									getErrorCode
									()
									 ==
									 HttpResult
									.
									SUCCESS
									)
									 {
									
                            dataFromHttpReady
									 =
									 true
									;
									
                            processData
									(
									result
									.
									getResponse
									());
									
                            //Từ HTTP kéo dữ liệu mới nhấtkết quả bóng đá việt nam hôm nay, cập nhật bộ nhớ đệm cục bộ
                            localDataCache
									.
									putCachingData
									(
									userId
									,
									 result
									.
									getResponse
									(),
									 null
									);
									
                        }
									
                        else
									 {
									
                            processError
									(
									result
									.
									getErrorCode
									());
									
                        }
									
                    }
									
                },
									
                null
									);
									
    }
									


    private
									 void
									 processData
									(
									HttpResponse
									 data
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngkết quả bóng đá việt nam hôm nay, hiển thị dữ liệu. Code ở đây bị lược bỏ
    }
									

    private
									 void
									 processError
									(
									int
									 errorCode
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngkết quả bóng đá việt nam hôm nay, hiển thị lỗi. Code ở đây bị lược bỏ
    }
									
}
									

								

Dù việc đọc dữ liệu từ bộ nhớ đệm cục bộ thường nhanh hơn nhiều so với việc lấy dữ liệu từ mạngVSBET, nhưng vì cả hai đều là giao diện bất đồng bộ (asynchronous), hoàn toàn có khả năng logic rằng dữ liệu từ mạng sẽ được trả về trước khi dữ liệu từ bộ nhớ đệm kích hoạt sự kiệ Hơn nữa, trong bài viết trước của chúng ta có đề cập đến chủ đề “... Xin lỗi, tôi đã quên mất tiêu đề chính xác của bài viết đó. Có lẽ bạn có thể giúp nhắc lại tên bài viết không? Điều này sẽ giúp tôi có thêm thông tin để mở rộng ý tưởng trong đoạn tiếp theo một cách phù hợp hơn. [Thêm một chút suy ngẫm] Có lẽ bài viết trước đã đề cập đến cách tối ưu hóa hiệu suất ứng dụng bằng cách cân bằng giữa việc sử dụng bộ nhớ đệm và kết nối mạng. Điều quan trọng ở đây là phải hiểu rõ quy trình hoạt động của cả hai phương thức này để đảm bảo ứng dụng hoạt động trơn tru nhất có thể. Xử lý bất đồng bộ trong phát triển Android và iOS (phần hai) —— Gọi lại cho tác vụ bất đồng bộ Trong phần “thứ tự gọi lại” của tài liệu nàyVSBET, việc đề cập đến “callback kết quả thất bại sớm” và “callback kết quả thành công sớm” đã cung cấp một cơ sở thực tế hơn cho trường hợp này. Điều này không chỉ giúp giải thích rõ ràng hơn về cách hoạt động của quy trình mà còn nhấn mạnh tầm quan trọng của việc xử lý các kịch bản khác nhau trong thời gian thực, từ đó tối ưu hóa hiệu suất và đảm bảo hệ thống vận hành trơn tru ngay cả khi gặp phải các tình huống bất ngờ.

Trong mã nguồn ở trênVSBET, nếu việc lấy dữ liệu từ mạng trả về trước khi dữ liệu từ bộ nhớ cache hoàn tất callback, chúng ta sẽ đánh dấu một biến logic kiểu boolean có tên là Khi nhiệm vụ lấy dữ liệu từ bộ nhớ cache kết thúc, chúng ta sẽ kiểm tra biến này để quyết định bỏ qua dữ liệu từ bộ nhớ cache. Ngoài ra, để tối ưu hóa hiệu suất và tránh tình trạng xung đột dữ liệu, chúng tôi còn thêm một cơ chế kiểm tra thời gian. Dữ liệu từ mạng luôn được ưu tiên hơn nếu nó mới hơn dữ liệu từ bộ nhớ cache ít nhất 5 phút. Điều này giúp đảm bảo rằng ứng dụng luôn hoạt động với thông tin mới nhất mà không bị ảnh hưởng bởi các vấn đề bất thường trong quá trình lưu trữ bộ nhớ cache.

thực hiện đồng thờikeo banh, ưu tiên một bên

thực thi song songVSBET, ưu tiên một bên

Sử dụng RxJava zip để thực hiện yêu cầu mạng song song

đấu vật tay không

Yêu cầu mạng song song

thực hiện yêu cầu mạng song song

Chúng ta có thể xem hai yêu cầu mạng song song như là hai Observablekết quả bóng đá việt nam hôm nay, sau đó sử dụng phép toán zip để kết hợp kết quả của chúng. Điều này làm cho mọi thứ trở nên gọn gàng hơn rất nhiều. Tuy nhiên, trước tiên chúng ta cần giải quyết một vấn đề khác: đóng gói giao diện yêu cầu mạng bất đồng bộ được đại diện bởi HttpService thành mộ Để làm điều này, chúng ta sẽ sử dụng các công cụ có sẵn trong thư viện quan sát để chuyển đổi cách tiếp cận của HttpService từ việc dựa trên callback sang mô hình quan sát. Điều này không chỉ giúp chúng ta dễ dàng tích hợp với các dòng dữ liệu khác mà còn tạo ra một mã nguồn sạch và dễ bảo trì hơn. Chẳng hạn, chúng ta có thể tạo một lớp wrapper bao quanh HttpService, nơi mỗi phương thức sẽ trả về một Observable thay vì thực hiện các thao tác trực tiếp. Điều này không chỉ làm tăng tính linh hoạt mà còn giảm thiểu sự phức tạp khi quản lý các luồng dữ liệu phức tạp trong ứng dụng.

Thông thườngVSBET, việc gói một nhiệm vụ đồng bộ thành Observable khá đơn giản, nhưng khi nói đến việc gói một nhiệm vụ bất đồng bộ sẵn có thành Observable thì lại không còn dễ hiểu như vậy. Trong trường hợp này, chúng ta cần sử dụng AsyncOnSubscribe để xử lý vấn đề. AsyncOnSubscribe cho phép chúng ta kiểm soát các bước của nhiệm vụ bất đồng bộ, từ đó tạo ra luồng dữ liệu theo cách mà Observable yêu cầu. Điều này đặc biệt hữu ích khi bạn muốn tích hợp các hệ thống hoặc API bất đồng bộ vào chuỗi xử lý dữ liệu của mình một cách linh hoạt và hiệu quả. Với sự hỗ trợ của AsyncOnSubscribe, việc chuyển đổi giữa các mô hình lập trình đồng bộ và bất đồng bộ trở nên mượt mà hơn bao giờ hết.

								
									
										public
									 class
									 MultiRequestsDemoActivity
									 extends
									 AppCompatActivity
									 {
									
    private
									 HttpService
									 httpService
									 =
									 new
									 MockHttpService
									();
									

    private
									 TextView
									 apiResultDisplayTextView
									;
									

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

        apiResultDisplayTextView
									 =
									 (
									TextView
									)
									 findViewById
									(
									R
									.
									id
									.
									api_result_display
									);
									

        /** * Trước tiênkết quả bóng đá việt nam hôm nay, sử dụng cơ chế AsyncOnSubscribe để đóng gói hai lần yêu cầu thành hai Observable riêng biệt */

        Observable
									<
									HttpResponse1
									>
									 request1
									 =
									 Observable
									.
									create
									(
									new
									 AsyncOnSubscribe
									<
									Integer
									,
									 HttpResponse1
									>()
									 {
									
            @Override
									
            protected
									 Integer
									 generateState
									()
									 {
									
                return
									 0
									;
									
            }
									

            @Override
									
            protected
									 Integer
									 next
									(
									Integer
									 state
									,
									 long
									 requested
									,
									 Observer
									<
									Observable
									<?
									 extends
									 HttpResponse1
									>>
									 observer
									)
									 {
									
                final
									 Observable
									<
									HttpResponse1
									>
									 asyncObservable
									 =
									 Observable
									.
									create
									(
									new
									 Observable
									.
									OnSubscribe
									<
									HttpResponse1
									>()
									 {
									
                    @Override
									
                    public
									 void
									 call
									(
									final
									 Subscriber
									<?
									 super
									 HttpResponse1
									>
									 subscriber
									)
									 {
									
                        //Khởi động yêu cầu bất đồng bộ đầu tiên
                        httpService
									.
									doRequest
									(
									"http://..."
									,
									 new
									 HttpRequest1
									(),
									
                                new
									 HttpListener
									<
									HttpRequest1
									,
									 HttpResponse1
									>()
									 {
									
                                    @Override
									
                                    public
									 void
									 onResult
									(
									String
									 apiUrl
									,
									 HttpRequest1
									 request
									,
									 HttpResult
									<
									HttpResponse1
									>
									 result
									,
									 Object
									 contextData
									)
									 {
									
                                        //Yêu cầu bất đồng bộ đầu tiên kết thúcVSBET, gửi kết quả vào asyncObservable
                                        if
									 (
									result
									.
									getErrorCode
									()
									 ==
									 HttpResult
									.
									SUCCESS
									)
									 {
									
                                            subscriber
									.
									onNext
									(
									result
									.
									getResponse
									());
									
                                            subscriber
									.
									onCompleted
									();
									
                                        }
									
                                        else
									 {
									
                                            subscriber
									.
									onError
									(
									new
									 Exception
									(
									"request1 failed"
									));
									
                                        }
									
                                    }
									
                                },
									
                                null
									);
									
                    }
									
                });
									
                observer
									.
									onNext
									(
									asyncObservable
									);
									
                observer
									.
									onCompleted
									();
									
                return
									 1
									;
									
            }
									
        });
									

        Observable
									<
									HttpResponse2
									>
									 request2
									 =
									 Observable
									.
									create
									(
									new
									 AsyncOnSubscribe
									<
									Integer
									,
									 HttpResponse2
									>()
									 {
									
            @Override
									
            protected
									 Integer
									 generateState
									()
									 {
									
                return
									 0
									;
									
            }
									

            @Override
									
            protected
									 Integer
									 next
									(
									Integer
									 state
									,
									 long
									 requested
									,
									 Observer
									<
									Observable
									<?
									 extends
									 HttpResponse2
									>>
									 observer
									)
									 {
									
                final
									 Observable
									<
									HttpResponse2
									>
									 asyncObservable
									 =
									 Observable
									.
									create
									(
									new
									 Observable
									.
									OnSubscribe
									<
									HttpResponse2
									>()
									 {
									
                    @Override
									
                    public
									 void
									 call
									(
									final
									 Subscriber
									<?
									 super
									 HttpResponse2
									>
									 subscriber
									)
									 {
									
                        //Khởi động yêu cầu bất đồng bộ thứ hai
                        httpService
									.
									doRequest
									(
									"http://..."
									,
									 new
									 HttpRequest2
									(),
									
                                new
									 HttpListener
									<
									HttpRequest2
									,
									 HttpResponse2
									>()
									 {
									
                                    @Override
									
                                    public
									 void
									 onResult
									(
									String
									 apiUrl
									,
									 HttpRequest2
									 request
									,
									 HttpResult
									<
									HttpResponse2
									>
									 result
									,
									 Object
									 contextData
									)
									 {
									
                                        //Yêu cầu bất đồng bộ thứ hai kết thúckết quả bóng đá việt nam hôm nay, gửi kết quả vào asyncObservable
                                        if
									 (
									result
									.
									getErrorCode
									()
									 ==
									 HttpResult
									.
									SUCCESS
									)
									 {
									
                                            subscriber
									.
									onNext
									(
									result
									.
									getResponse
									());
									
                                            subscriber
									.
									onCompleted
									();
									
                                        }
									
                                        else
									 {
									
                                            subscriber
									.
									onError
									(
									new
									 Exception
									(
									"reques2 failed"
									));
									
                                        }
									
                                    }
									
                                },
									
                                null
									);
									
                    }
									
                });
									
                observer
									.
									onNext
									(
									asyncObservable
									);
									
                observer
									.
									onCompleted
									();
									
                return
									 1
									;
									
            }
									
        });
									

        //Hai Observable đại diện cho requestkeo banh, sử dụng zip để hợp nhất kết quả
        Observable
									.
									zip
									(
									request1
									,
									 request2
									,
									 new
									 Func2
									<
									HttpResponse1
									,
									 HttpResponse2
									,
									 List
									<
									Object
									>>()
									 {
									
            @Override
									
            public
									 List
									<
									Object
									>
									 call
									(
									HttpResponse1
									 response1
									,
									 HttpResponse2
									 response2
									)
									 {
									
                List
									<
									Object
									>
									 responses
									 =
									 new
									 ArrayList
									<
									Object
									>(
									2
									);
									
                responses
									.
									add
									(
									response1
									);
									
                responses
									.
									add
									(
									response2
									);
									
                return
									 responses
									;
									
            }
									
        }).
									subscribe
									(
									new
									 Subscriber
									<
									List
									<
									Object
									>>()
									 {
									
            private
									 HttpResponse1
									 response1
									;
									
            private
									 HttpResponse2
									 response2
									;
									

            @Override
									
            public
									 void
									 onNext
									(
									List
									<
									Object
									>
									 responses
									)
									 {
									
                response1
									 =
									 (
									HttpResponse1
									)
									 responses
									.
									get
									(
									0
									);
									
                response2
									 =
									 (
									HttpResponse2
									)
									 responses
									.
									get
									(
									1
									);
									
            }
									

            @Override
									
            public
									 void
									 onCompleted
									()
									 {
									
                processData
									(
									response1
									,
									 response2
									);
									
            }
									

            @Override
									
            public
									 void
									 onError
									(
									Throwable
									 e
									)
									 {
									
                processError
									(
									e
									);
									
            }
									

        });
									
    }
									

    private
									 void
									 processData
									(
									HttpResponse1
									 data1
									,
									 HttpResponse2
									 data2
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngVSBET, hiển thị dữ liệu. Code ở đây bị lược bỏ
    }
									

    private
									 void
									 processError
									(
									Throwable
									 e
									)
									 {
									
        //TODO: Cập nhật giao diện người dùngkeo banh, hiển thị lỗi. Code ở đây bị lược bỏ
    }
									

								

chuyển HttpService thành Observable

thực hiện song song nhưng ưu tiên một bên

thực thi tuần tự


Bài viết này lần lượt ba loại mối quan hệ hợp tác giữa các tác vụ bất đồng bộkeo banh, và cuối cùng không đi đến kết luận rằng cần chuyển đổi tất cả các tác vụ bất đồng bộ thành kiểu thực hiện tuần tự nối tiếp để làm đơn giản hóa logic xử lý. Việc lựa chọn vẫn nằm ở tay các nhà phát triển. Trong thực tế, mỗi loại hình tác vụ bất đồng bộ đều có những đặc điểm riêng biệt và cách tiếp cận phù hợp. Đôi khi việc chuyển đổi thành tuần tự hóa lại gây ra nhiều rủi ro hơn, chẳng hạn như gia tăng thời gian chờ đợi hoặc giảm hiệu suất tổng thể của ứng dụng. Vì vậy, thay vì áp dụng một quy tắc cứng nhắc, các nhà phát triển cần cân nhắc kỹ lưỡng từng trường hợp cụ thể dựa trên yêu cầu nghiệp vụ và cấu trúc hệ thống. Tóm lại, không có công thức nào áp dụng chung cho mọi tình huống. Điều quan trọng là phải hiểu rõ mục tiêu cuối cùng và ưu tiên hiệu quả trong việc tối ưu hóa mã nguồn. Chọn phương án nào phụ thuộc vào sự am hiểu sâu sắc và kinh nghiệm của người lập trình.

Hơn nữaVSBET, một vấn đề không thể bỏ qua là trong nhiều trường hợp, quyền lựa chọn không nằm trong tay chúng ta. Có thể cấu trúc mã nguồn mà chúng ta nhận được đã tạo ra những mối quan hệ hợp tác phức tạp giữa các tác vụ bất đồng bộ. Điều cần làm ở đây là khi tình huống như vậy xảy ra, chúng ta luôn phải giữ bình tĩnh, từ đó phân tích và xác định rõ ràng tình hình hiện tại thuộc loại nào trong số những tình huống rối rắm của mã nguồn logic. Đôi khi, việc hiểu rõ mọi thứ có vẻ như một nhiệm vụ khó khăn, nhưng nếu nhìn sâu vào từng chi tiết nhỏ nhất, bạn sẽ dần nhận ra rằng mỗi thành phần đều có ý nghĩa riêng của nó. Việc quan trọng hơn cả là phải biết cách kết nối tất cả các mảnh ghép lại với nhau để tạo nên bức tranh hoàn chỉnh. Điều này đòi hỏi sự kiên nhẫn và kỹ năng giải quyết vấn đề tốt. Hãy luôn nhớ rằng, ngay cả khi mọi thứ dường như đang trở nên hỗn loạn, chỉ cần bạn tập trung và phân tích cẩn thận, thì cuối cùng bạn cũng sẽ tìm ra hướng đi đúng đắn.

(Kết thúc)

Các bài viết được chọn lọc khác


Bài viết gốckeo banh, vui lòng ghi rõ nguồn và bao gồm mã QR bên dưới! Nếu không, từ chối tái bản!
Liên kết bài viết này: /9ejfxdmx.html
Hãy theo dõi tài khoản Weibo cá nhân của tôi: Tìm kiếm tên tôi "Trương Thiết Lệ" trên Weibo.
Tài khoản WeChat của tôi: tielei-blog (Trương Thiết Lệ)
Bài trước: Xử lý bất đồng bộ trong phát triển Android và iOS (phần hai) —— Gọi lại cho tác vụ bất đồng bộ
Bài sau: Phép màu của trẻ nhỏ

Bài viết mới nhất