Ứng dụng có thể làm quá nhiều việc trên luồng chính của nó


379

Tôi chưa quen với môi trường SDK / API của Android. Đây là lần đầu tiên tôi đang cố gắng vẽ một cốt truyện / biểu đồ. Tôi đã thử chạy các loại mã mẫu khác nhau của trình giả lập bằng 3 thư viện miễn phí khác nhau, không có gì hiển thị trong màn hình bố trí. Logcat đang lặp lại thông báo sau:

 W / Trace (1378): Giá trị không mong đợi từ localGetEnablesTags: 0
 I / Biên đạo múa (1378): Bỏ qua 55 khung hình! Ứng dụng có thể đang làm quá nhiều công việc trên luồng chính của nó.

Vấn đề không tồn tại và biểu đồ đã hoạt động khi tôi chạy mã mẫu liên quan đến bản sao đánh giá của thư viện được cấp phép.


2
Bạn đang vẽ biểu đồ của bạn trên một chủ đề riêng biệt?
Areks

Cảm ơn bình luận của bạn, tôi đã chỉnh sửa câu hỏi để làm cho nó rõ ràng hơn. Hoạt động khi chạy đang hiển thị rằng tôi đang chạy một hoạt động không có thiết kế bố cục của nó => hiển thị màn hình trắng.
2038135

1
@Areks Không, tôi không sử dụng một chủ đề riêng biệt.
2038135

1
Tôi nghĩ rằng bạn hoàn toàn không nên thực hiện các thao tác dài trên luồng chính, vì điều đó đóng băng toàn bộ ứng dụng, bạn có thể đọc cách sử dụng các luồng ở đây: stackoverflow.com/questions/3391272/. Bỏ qua "mã để làm yêu cầu HTTP "và chỉ thực hiện các hoạt động dài tiềm năng của bạn ở đó.
Areks

1
Tại sao bạn không thử tìm kiếm, bạn sẽ tìm thấy thông tin về biên đạo múa. Tôi khuyên bạn nên đọc câu trả lời này: stackoverflow.com/questions/11266535/ Kẻ
Gabriel Esteban

Câu trả lời:


479

lấy từ: Giao diện người dùng Android: Sửa các khung bị bỏ qua

Bất cứ ai bắt đầu phát triển ứng dụng Android đều thấy thông báo này trên logcat của Biên đạo múa (abc): Bỏ qua các khung xx! Ứng dụng này có thể làm quá nhiều việc trên luồng chính của nó. Vì vậy, nó thực sự có nghĩa là gì, tại sao bạn nên quan tâm và làm thế nào để giải quyết nó.

Điều này có nghĩa là mã của bạn mất nhiều thời gian để xử lý và các khung bị bỏ qua vì nó, Có thể do một số xử lý nặng mà bạn đang thực hiện tại trung tâm của ứng dụng hoặc quyền truy cập DB hoặc bất kỳ điều gì khác gây ra luồng Dừng lại một chút.

Dưới đây là một lời giải thích chi tiết hơn:

Biên đạo múa cho phép các ứng dụng tự kết nối với vsync và sắp xếp thời gian hợp lý để cải thiện hiệu suất.

Android xem hoạt hình trong nội bộ sử dụng Biên đạo múa cho cùng một mục đích: để định thời gian cho hoạt ảnh và có thể cải thiện hiệu suất.

Vì Biên đạo được thông báo về mọi sự kiện vsync, tôi có thể biết liệu một trong số các Runnables được biên đạo bởi Choreogograph.post * apis không kết thúc trong một khung hình, khiến các khung hình bị bỏ qua.

Theo hiểu biết của tôi Biên đạo múa chỉ có thể phát hiện bỏ qua khung. Nó không có cách nào để nói tại sao điều này xảy ra.

Tin nhắn Ứng dụng có thể làm quá nhiều việc trên luồng chính của nó. có thể gây hiểu nhầm

nguồn: Ý nghĩa của các thông điệp biên đạo múa trong Logcat

Tại sao bạn nên quan tâm

Khi thông báo này bật lên trên trình giả lập Android và số lượng khung hình bị bỏ qua khá nhỏ (<100) thì bạn có thể đặt cược an toàn cho trình giả lập bị chậm - điều này xảy ra gần như mọi lúc. Nhưng nếu số lượng khung hình bị bỏ qua và lớn và theo thứ tự 300+ thì có thể có một số rắc rối nghiêm trọng với mã của bạn. Các thiết bị Android có rất nhiều phần cứng không giống như các thiết bị ios và windows. RAM và CPU khác nhau và nếu bạn muốn có hiệu suất và trải nghiệm người dùng hợp lý trên tất cả các thiết bị thì bạn cần khắc phục điều này. Khi các khung bị bỏ qua, giao diện người dùng chậm và chậm, đó không phải là trải nghiệm người dùng mong muốn.

Cách khắc phục

Việc sửa lỗi này đòi hỏi phải xác định các nút nơi có hoặc có thể xảy ra trong thời gian dài xử lý. Cách tốt nhất là thực hiện tất cả quá trình xử lý cho dù nhỏ hay lớn trong một luồng tách biệt với luồng UI chính. Vì vậy, nó có thể truy cập vào cơ sở dữ liệu SQLite Database hoặc thực hiện một số phép toán khó hoặc đơn giản là sắp xếp một mảng - Thực hiện trong một luồng khác

Bây giờ có một lưu ý ở đây, Bạn sẽ tạo một Chủ đề mới để thực hiện các thao tác này và khi bạn chạy ứng dụng của mình, nó sẽ gặp sự cố Chỉ có chủ đề ban đầu tạo phân cấp chế độ xem có thể chạm vào chế độ xem của nó. Bạn cần biết thực tế này rằng UI trong Android chỉ có thể được thay đổi bởi luồng chính hoặc luồng UI. Bất kỳ chủ đề nào khác cố gắng để làm như vậy, thất bại và gặp sự cố với lỗi này. Những gì bạn cần làm là tạo một Runnable mới bên trong runOnUiThread và bên trong runnable này, bạn nên thực hiện tất cả các hoạt động liên quan đến UI. Tìm một ví dụ ở đây .

Vậy chúng ta có Thread và Runnable để xử lý dữ liệu ngoài Thread chính, còn gì nữa không? Có AsyncTask trong Android cho phép thực hiện các quy trình thời gian dài trên luồng UI. Điều này hữu ích nhất khi các ứng dụng của bạn được điều khiển dữ liệu hoặc điều khiển api trên web hoặc sử dụng các giao diện người dùng phức tạp giống như các bản dựng sử dụng Canvas. Sức mạnh của AsyncTask là cho phép thực hiện mọi thứ trong nền và sau khi bạn hoàn tất quá trình xử lý, bạn chỉ cần thực hiện các hành động cần thiết trên UI mà không gây ra bất kỳ hiệu ứng trễ nào. Điều này có thể xảy ra vì AsyncTask xuất phát từ luồng UI của Activity - tất cả các thao tác bạn thực hiện trên UI qua AsyncTask đều được thực hiện là một luồng khác với luồng UI chính, Không cản trở tương tác của người dùng.

Vì vậy, đây là những gì bạn cần biết để tạo ra các ứng dụng Android mượt mà và theo tôi biết mọi người mới bắt đầu đều nhận được thông báo này trên bảng điều khiển của mình.


41
Tôi chỉ có một ứng dụng trong đó nếu tôi nhấp vào nút, hình ảnh nền của nút thay đổi và nút không thể xem được. Làm thế nào tôi làm quá nhiều việc :(
Remian8985

1
@ Remian8985 - Việc thay đổi hình nền cho nút (giả sử rằng bạn đang tải xuống hình ảnh này) nên được thực hiện trong AsyncTask - nghĩa là thực hiện thao tác tải xuống nền đó và xuất bản kết quả trên luồng UI (cung cấp lại hình ảnh). Xem liên kết
BenJaminSila

11
@BenJaminSila thay đổi nền trong AsyncTask? Có thật không?
dùng25

11
@ user25 "giả sử rằng bạn đang tải xuống hình ảnh này"
forresthopkinsa

"Khi thông báo này bật lên trên trình giả lập Android và số lượng khung hình bị bỏ qua khá nhỏ (<100) thì bạn có thể đặt cược an toàn cho trình giả lập bị chậm" Điều này có còn áp dụng cho đến ngày hôm nay không? Trình giả lập đang trở nên khá nhanh phải không?
Robin Dijkhof

243

Như những người khác đã trả lời ở trên, "Bỏ qua 55 khung hình!" có nghĩa là một số xử lý nặng trong ứng dụng của bạn.

Đối với trường hợp của tôi, không có quá trình nặng nề trong ứng dụng của tôi. Tôi đã nhân đôi và nhân ba kiểm tra mọi thứ và loại bỏ những quá trình mà tôi nghĩ là hơi nặng nề.

Tôi đã loại bỏ Mảnh vỡ, Hoạt động, Thư viện cho đến khi chỉ còn lại bộ xương. Nhưng vấn đề vẫn không biến mất. Tôi quyết định kiểm tra các tài nguyên và thấy một số biểu tượng và nền tôi sử dụng khá lớn vì tôi quên kiểm tra kích thước của các tài nguyên đó.

Vì vậy, đề nghị của tôi là nếu không có câu trả lời nào ở trên có ích, bạn cũng có thể kiểm tra kích thước tệp tài nguyên của mình.


1
Làm việc cho tôi là tốt. Tôi đã có một ứng dụng làm rất ít việc nhưng chậm và chậm. Tôi tiếp tục bị bỏ qua các bản ghi khung. Khi tôi xóa nền khỏi hoạt động của mình, mọi thứ đều ổn. Cảm ơn!
akrabi

Câu trả lời tuyệt vời, tôi tin rằng đây chính xác là vấn đề của tôi. Tôi đã thử một loạt các giải pháp (khá liên quan) khác và ứng dụng cũng chậm như vậy. Tôi lấy ra tất cả các dịch vụ web và cố gắng tối ưu hóa mã của mình đến tận xương. Không làm việc, sau đó tôi thấy điều này. Ngay sau khi tôi xóa hình nền của mình (hình ảnh lớn nhất tôi có), ứng dụng sẽ hoạt động nhanh như bạn có thể nhấp vào công cụ, ngay cả với mã "chậm" cũ.
M Barbosa

bạn đã làm cho ngày của tôi!
Nicolas Mastromarino

:) Bạn là một thiên tài vô lý.
Metin Ilhan

@batsheva không nhất thiết phải là 1 KB. Nó phụ thuộc vào nhu cầu của bạn, giả sử bạn cần hình ảnh rõ ràng hơn, bạn có thể sử dụng độ phân giải cao hơn, nhưng hãy đảm bảo bạn chia thành các kích cỡ khác nhau vào các thư mục tài nguyên khác nhau.
Sithu

61

Tôi cũng có vấn đề tương tự.
Của tôi là một trường hợp tôi đang sử dụng một hình ảnh nền có thể vẽ được. Hình ảnh cụ thể đó có giá khoảng 130kB và được sử dụng trong màn hình và trang chủ trong ứng dụng Android của tôi.

Giải pháp - Tôi vừa chuyển hình ảnh cụ thể đó sang thư mục drawables-xxx từ drawables và có thể giải phóng rất nhiều bộ nhớ bị chiếm trong nền và các khung hình bị bỏ qua không còn bị bỏ qua.

Cập nhật Sử dụng thư mục tài nguyên có thể vẽ 'gật đầu' để lưu trữ các tệp có thể vẽ nền.
Một mật độ đủ điều kiện có thể vẽ thư mục hoặc drawable-gậtpi được ưu tiên?


7
Tôi đã chuyển hình nền lớn của mình từ drawable sang mimap-xxxhdpi và nó đã làm được điều đó!
bgplaya

Bạn đã giúp rất nhiều. Cảm ơn
N.Droid

2
Giải pháp này là thực hiện các mẹo. Tôi đang sử dụng thư mục drawable-xxxhdpithay vì drawablegiảm đáng kể bộ nhớ đã sử dụng (giảm 70%). Cũng cần biết, màn hình có cùng kích thước khác nhau về kích thước DPI. Tỷ lệ tính theo pixel giữa chúng là ldpi = 1:0.75, mdpi = 1:1, hdpi = 1:1.5, xhdpi = 1:2, xxhdpi = 1:3, xxxhdpi = 1:4. Bằng cách sử dụng drawable-xxxhdpithư mục bạn cho phép thu nhỏ hình ảnh xuống màn hình của thiết bị, điều này làm giảm mức tiêu thụ bộ nhớ và CPU.
Timo Bähr

2
Di chuyển hình ảnh từ drawableđể drawable-nodpingăn chặn ứng dụng nhận được Out of Memory Error.
Shruti

Trời ơi ... cảm ơn! Tôi đã có một hình ảnh trong thư mục drawable và điều này làm cho ứng dụng của tôi chậm như địa ngục (mặc dù hình ảnh chỉ có 100kb !!!). Sau khi tạo các tệp xxx có thể vẽ (tôi đã sử dụng Trình nhập có thể vẽ của Android), ứng dụng của tôi rất nhanh. Cảm ơn rất nhiều!
lỗi1337

20

Một nguyên nhân phổ biến khác của sự chậm trễ trên luồng UI là quyền truy cập SharedPreferences. Khi bạn gọi một PreferenceManager.getSharedPreferencesvà các phương thức tương tự khác lần đầu tiên, tệp .xml được liên kết ngay lập tức được tải và phân tích cú pháp trong cùng một luồng .

Một trong những cách tốt để chống lại vấn đề này là kích hoạt tải SharedPreference đầu tiên từ luồng nền, bắt đầu càng sớm càng tốt (ví dụ: từ onCreatelớp Ứng dụng của bạn). Bằng cách này, đối tượng ưu tiên có thể đã được xây dựng theo thời gian bạn muốn sử dụng nó.

Thật không may, đôi khi đọc một tệp ưu tiên là cần thiết trong các giai đoạn khởi động sớm (ví dụ như trong Hoạt động ban đầu hoặc ngay cả chính Ứng dụng). Trong những trường hợp như vậy, vẫn có thể tránh bị đình trệ giao diện người dùng bằng cách sử dụng MessageQueue.IdleHandler. Làm mọi thứ khác bạn cần để thực hiện trên luồng chính, sau đó cài đặt IdleHandler để thực thi mã khi Hoạt động của bạn đã được vẽ hoàn chỉnh. Trong Runnable đó, bạn sẽ có thể truy cập SharedPreferences mà không trì hoãn quá nhiều thao tác vẽ và làm cho biên đạo múa không hài lòng.


1
Trong trường hợp này, bạn nên thích phương thức áp dụng () thay vì commit (). phương thức áp dụng () không thể chặn UI. Bạn có thể nhìn từ đây developer.android.com/training/data-st
Storage / shared-pferences

16

Cố gắng sử dụng các chiến lược sau để cải thiện hiệu suất ứng dụng của bạn:

  • Sử dụng lập trình đa luồng nếu có thể. Lợi ích hiệu năng là rất lớn, ngay cả khi điện thoại thông minh của bạn có một lõi (các luồng có thể chạy ở các lõi khác nhau, nếu bộ xử lý có hai hoặc nhiều hơn). Thật hữu ích khi làm cho logic ứng dụng của bạn tách khỏi UI. Sử dụng các luồng Java, AsyncTask hoặc IntentService. Kiểm tra này .
  • Đọc và làm theo các mẹo hiệu suất linh tinh của trang web phát triển Android. Kiểm tra tại đây .

3
liên kết đầu tiên của bạn yêu cầu bạn "... có tài khoản được xác thực ..." để truy cập nó.
chornge

9

Tôi đã từng gặp vấn đề tương tự. Trình giả lập Android hoạt động hoàn hảo trên Android <6.0. Khi tôi sử dụng trình giả lập Nexus 5 (Android 6.0), ứng dụng hoạt động rất chậm vớiI/Choreographer: Skipped frames các bản ghi.

Vì vậy, tôi đã giải quyết vấn đề này bằng cách thay đổi hardwareAcceleratedtùy chọn tệp Manifest thành truenhư thế này:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

    <application android:hardwareAccelerated="true">
        ...
    </application>
</manifest>

8

Tôi không phải là một chuyên gia, nhưng tôi đã nhận được thông báo gỡ lỗi này khi tôi muốn gửi dữ liệu từ ứng dụng Android của mình đến một máy chủ web. Mặc dù tôi đã sử dụng lớp AsyncTask và thực hiện chuyển dữ liệu ở chế độ nền, nhưng để lấy lại dữ liệu kết quả từ máy chủ, tôi đã sử dụng phương thức get () của lớp AsyncTask, điều đó làm cho UI đồng bộ hóa, điều đó có nghĩa là UI của bạn sẽ chờ quá lâu. Vì vậy, lời khuyên của tôi là làm cho ứng dụng của bạn thực hiện mọi tác vụ theo định hướng mạng trên một luồng riêng biệt.


6

Tối ưu hóa hình ảnh của bạn ... Không sử dụng hình ảnh lớn hơn 100KB ... Tải hình ảnh tốn quá nhiều CPU và khiến ứng dụng của bạn bị treo.


4
Giảm kích thước hình ảnh bằng mã java hoặc sử dụng photoshop để cắt ảnh .. cũng nén hình ảnh bằng cách sử dụng
nén.io

5

Tôi đã từng gặp vấn đề tương tự. Trong trường hợp của tôi, tôi đã có 2 Bố cục tương đối lồng nhau. RelativeLayout luôn phải thực hiện hai lần đo. Nếu bạn lồng RelativeLayouts, bạn sẽ có được thuật toán đo theo cấp số nhân.


4

điều này thường xảy ra khi bạn đang thực hiện các tiến trình lớn trong luồng chính. Bạn có thể bỏ qua các khung nhỏ hơn 200. nhưng nếu bạn có hơn 200 khung hình bị bỏ qua, nó có thể làm chậm chuỗi UI của ứng dụng. những gì bạn có thể làm là thực hiện các quy trình này trong luồng mới gọi là luồng worker và sau đó, khi bạn muốn truy cập và thực hiện sth với luồng UI (ví dụ: làm gì đó với khung nhìn, findView, v.v.), bạn có thể sử dụng handler hoặc runOnUiThread (Tôi thích điều này hơn) để hiển thị kết quả xử lý. Điều này hoàn toàn giải quyết vấn đề. sử dụng chủ đề worker rất hữu ích hoặc thậm chí phải được sử dụng khi gặp trường hợp này.


1

Tôi đã từng gặp vấn đề tương tự. Khi tôi chạy mã trên một máy tính khác, nó hoạt động tốt. Tuy nhiên, trên máy của tôi, nó hiển thị "Ứng dụng có thể làm quá nhiều việc trên luồng chính".

Tôi đã giải quyết vấn đề của mình bằng cách khởi động lại Android studio [Tệp -> Bộ nhớ cache / Khởi động lại không hợp lệ -> nhấp vào "Không hợp lệ và khởi động lại"].


Tôi không biết tại sao giải pháp của bạn lại hiệu quả. Dù sao cũng cảm ơn.
Bhuvanesh BS

1

Trong trường hợp của tôi, đó là vì tôi đã vô tình thiết lập một điểm dừng trên một phương thức. Khi tôi xóa nó, tin nhắn biến mất và hiệu suất được cải thiện rất nhiều.


0

Ứng dụng của tôi có vấn đề tương tự. Nhưng nó không làm gì ngoài việc hiển thị danh sách các thẻ và văn bản trên đó. Không có gì chạy trong nền. Nhưng sau khi một số điều tra phát hiện ra rằng hình ảnh được đặt cho nền thẻ đã gây ra điều này, mặc dù nó nhỏ (350kb). Sau đó, tôi đã chuyển đổi hình ảnh thành 9patch hình ảnh bằng cách sử dụng http://romannurik.github.io/AndroidAssetStudio/index.html .
Điều này làm việc cho tôi.


0

Sau khi thực hiện nhiều nghiên cứu và phát triển về vấn đề này, tôi đã nhận được Giải pháp,

Trong trường hợp của tôi, tôi đang sử dụng Dịch vụ sẽ chạy mỗi 2 giây và với runonUIThread, tôi đã tự hỏi vấn đề là ở đó nhưng không phải vậy. Vấn đề tiếp theo mà tôi thấy là tôi đang sử dụng Hình ảnh lớn trong ứng dụng may và đó là vấn đề.

Tôi xóa hình ảnh và thiết lập hình ảnh mới.

Kết luận: - Nhìn vào mã của bạn có bất kỳ tệp thô nào bạn đang sử dụng có kích thước lớn.


0

Đầu tiên đọc cảnh báo. Nó nói tải nhiều hơn trên chủ đề chính. Vì vậy, những gì bạn phải làm chỉ là chạy các chức năng với nhiều công việc hơn trong một luồng.


-1

Tôi gặp vấn đề tương tự khi phát triển một ứng dụng sử dụng nhiều tệp png có thể vẽ trên bố cục lưới. Tôi cũng đã cố gắng tối ưu hóa mã của mình càng nhiều càng tốt .. nhưng nó không hiệu quả với tôi .. Sau đó, tôi đã cố gắng giảm kích thước của những png đó .. và đoán nó hoạt động hoàn toàn tốt .. Vì vậy, đề xuất của tôi là giảm kích thước của tài nguyên có thể rút được nếu có ..

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.