2012-01-26 38 views
17

thể trùng lặp:
AsyncTask block UI threat and show progressbar with delayProgressDialog không được hiển thị khi AsyncTask.get() được gọi

Tôi muốn thể hiện một progressDialog khi lấy JSON từ bất kỳ máy chủ. Vì vậy, tôi đã sử dụng AsyncTask như một giải pháp (không chắc chắn bất kỳ cách nào khác).

Mọi thứ đều ổn, ProgressDialog hoạt động đúng cho đến khi tôi gọi phương thức .get() sử dụng thể hiện AsyncTask. Tôi cho rằng nó chặn giao diện người dùng bằng cách nào đó. Dưới đây là AsyncTask tôi:

public class myAsync extends AsyncTask<String, String, List> { 

    String message; // for dialog message 
    ProgressDialog progress; 
    Intent myIntent; 
    Context ctx; 

    public myAsync(String message, Context ctx) { 
     this.message = message; 
     this.ctx = ctx; 
     progress = new ProgressDialog(ctx); 
    } 

    @Override 
    protected void onPreExecute() { 
     progress.setMessage(message); 
     progress.setIndeterminate(true); 
     progress.setCancelable(false); 
     progress.show();  
    } 

    @Override 
    protected List doInBackground(String... params) { 
     //returns any list after the task 
     return anyList; 
    } 

    @Override 
    protected void onPostExecute(List result) { 
     if(progress.isShowing()) 
      progress.dismiss(); 
    } 
} 

Và đây là myActivity đó là gọi AsyncTask:

myAsync asyncTask = new myAsync("Loading...", this); 
asyncTask.execute("Any string", "Other string"); 
asyncTask.get(); // If I comment out this line, ProgressDialog works 

Sau khi thực hiện, khi tôi cố gắng ghi lại các kết quả từ doInBackground và onPostExecute cả không có vấn đề. Nhưng nếu tôi muốn nhận được với .get() kết quả ProgressDialog không được hiển thị hoặc hiển thị quá ít thời gian (có thể 0,2 giây)

Có vấn đề gì?

+0

bạn có ghét bất kỳ ngoại lệ nào không? – Richie

+0

Không thực sự. Như tôi đã nói, cửa sổ hộp thoại có thể được nhìn thấy quá ít thời gian. Thật vậy nó nên được nhìn thấy ít nhất 2 giây. –

Trả lời

23

Có, get()chờ nếu cần để tính toán hoàn thành và sau đó truy xuất kết quả. Điều này có nghĩa là bạn đang chặn luồng giao diện người dùng của mình, chờ kết quả.

Giải pháp: Đừng gọi get

Thông thường, bạn sẽ gọi một hàm (callback) trong postExecute.

+2

Xem http://stackoverflow.com/questions/3291490/common-class-for-asynctask-in-android để triển khai mẫu – rds

+0

OK! Cảm ơn bạn đã lấy mẫu, giải quyết vấn đề này nhưng vẫn gặp vấn đề với các chủ đề khác nhau. –

+2

nhưng nếu tôi muốn sử dụng giá trị trả về của AsyncTask và trên cơ sở giá trị trả lại i wannt để gọi URL mới vì vậy tôi có thể làm gì cho điều này? tôi nghĩ theo cách này chúng ta phải sử dụng .get không có nó nếu có bất kỳ tùy chọn nào sau đó xin hãy giúp tôi – PankajAndroid

-2

Hãy thử sử dụng runOnUiThread như thế này:

  runOnUiThread(new Runnable(){ 
      public void run() { 
       dialog.show(); 
       }});  

Chạy một cái gì đó trên một AsyncTask có nghĩa là nó bỏ chạy khỏi UIthread nên thường bạn không thể điều hành hoạt động ui từ bên trong các phương pháp async mà không xử lý và các công cụ mà tôi thường tránh xa từ. Tôi cũng xử lý một giải pháp như vậy bằng cách tạo một tiến trìnhDialog như một biến trong lớp của tôi ở trên oncreate của tôi để nó có thể nhìn thấy toàn bộ lớp. Sau đó tôi gọi progressdialog ngay trước khi asynctask của tôi và sau đó kể từ khi nó hiển thị cho cả lớp tôi gọi .dissmiss() trong onPostExecute

+0

Cả hai 'onPreExecute' và' onPostExecute' đều chạy trên chuỗi giao diện người dùng. 'doInBackground' là thứ duy nhất không có. –

+0

@JakeWharton Tôi nghĩ rằng họ chỉ trả lại dữ liệu cho chuỗi giao diện người dùng và không chạy trên nó nhưng tôi có thể sai ..... Tôi không chính xác có dòng tài liệu android được ghi nhớ cho dòng nhưng lol –

+0

Tôi đã thử điều này, không hoạt động . Dù sao cũng cảm ơn bạn. –

4

Nếu tôi hiểu câu hỏi của bạn một cách chính xác, bạn cần cập nhật tiến trình AsyncTask của bạn trong ProgressDialog và điều này hiện không hoạt động. Vì vậy, một vài điều cần lưu ý: Tôi không chắc chắn những gì bạn đang cố gắng để đạt được với .get() nhưng tôi sẽ giả sử bạn muốn hiển thị tiến độ.

Tôi đã sửa đổi chương trình của bạn bên dưới để cập nhật chuỗi giao diện người dùng với tiến trình của AsyncTask. Mỗi lần bạn cần phải cập nhật tiến trình, cập nhật biến số prog trong phương thức doInBackground.

public class myAsync extends AsyncTask<String, Integer, List> { 

    String message; // for dialog message 
    ProgressDialog progress; 
    Intent myIntent; 
    Context ctx; 

    public myAsync(String message, Context ctx) { 
    this.message = message; 
    this.ctx = ctx; 
    progress = new ProgressDialog(ctx); 
    } 

    @Override 
    protected void onPreExecute() { 
    // Runs on the UI thread 
    progress.setMessage(message); 
    progress.setIndeterminate(true); 
    progress.setCancelable(false); 
    progress.show();  
    } 

    @Override 
    protected List doInBackground(String... params) { 
    // Runs in the background thread 
    // publish your progress here!! 
    int prog = 5; // This number will represent your "progress" 
    publishProgress(prog); 
    return anyList; 
    } 


    protected void onProgressUpdate(Integer... progress) { 
    // Runs in the UI thread 
    // This method will fire (on the UI thread) EVERYTIME publishProgress 
    // is called. 
    Log.d(TAG, "Progress is: " +progress); 
    } 

    @Override 
    protected void onPostExecute(List result) { 
    // Runs in the UI thread 

    for (int i=0; i<result.size(); i++) { 
     Log.d(TAG, "List item: " + result.get(i)); 
    } 

    if(progress.isShowing()) 
     progress.dismiss(); 
    } 
} 
+0

Với 'get', anh ta rõ ràng muốn nhận kết quả từ nhiệm vụ, để cập nhật giao diện của mình – rds

+0

@rds Bạn có bao giờ sử dụng' .get' trong ngữ cảnh của AsyncTask không? Do đó tại sao _assumption_ của tôi "Tôi không chắc bạn đang cố gắng đạt được điều gì với ..." và sau đó tôi giải thích câu hỏi của OP. –

+0

@Marvin, trước hết cảm ơn nhận xét của bạn. Đơn giản, tôi lấy json từ một máy chủ web. Trong khi thực hiện giao dịch này, chỉ muốn hiển thị các cửa sổ progressdialog, đó là tất cả. Nếu tôi không gọi .get(), nó ổn. Hộp thoại được hiển thị ngay sau khi nhấp vào nút (nút sẽ kích hoạt không đồng bộ). Nhưng bằng cách này tôi cũng cần kết quả json. Như tôi đã biết .get() trả về kết quả. Khi tôi cố gắng để có được, cửa sổ hộp thoại được hiển thị quá ít thời gian trong giao dịch. Tôi hy vọng nó dễ dàng hơn bây giờ. –

15

Calling .get() thay đổi AsyncTask của bạn thành một hiệu quả "SyncTask" vì nó làm cho thread hiện hành (đó sẽ là thread UI) để chờ cho đến khi AsyncTask đã xử lý xong nó. Vì bạn hiện đang chặn chuỗi giao diện người dùng nên cuộc gọi đến phương thức .show() của ProgressDialog không bao giờ có cơ hội cho phép hộp thoại tự vẽ màn hình.

Xóa cuộc gọi sẽ cho phép cuộc gọi chạy đúng cách trong nền.

Nếu bạn cần xử lý sau khi tác vụ đã hoàn thành, tôi đề nghị bạn nên đặt nó bên trong chính phương thức onPostExecute hoặc sử dụng gọi lại đến Activity từ onPostExecute.

+0

Tôi đoán bạn nói đúng nhưng bạn có thể giải thích thêm không? Bất kỳ đoạn trích nào. Bởi vì tôi không chắc chắn về cách sử dụng gọi lại từ onPostExecute. Cảm ơn. –

Các vấn đề liên quan