2011-10-21 23 views
6

Tôi đang làm việc với một tình huống khá phổ biến ngay bây giờ - tải xuống một số dữ liệu trên web, sau đó cập nhật một chế độ xem để hiển thị nó. Rõ ràng, tôi muốn tải xuống web ở chế độ nền và sau đó cập nhật chế độ xem trên chuỗi giao diện người dùng chính. Bây giờ nhìn vào mã của tôi, tôi hơi lo lắng về Hoạt động của tôi và các yếu tố giao diện người dùng của nó bị giết trước khi tôi cập nhật chúng. Dưới đây là bản chất của những gì tôi có trong tâm trí:Làm cách nào để biết ngữ cảnh của tôi vẫn hợp lệ?

Thread update = new Thread() { 
    public void run() { 
     final Data newData = requestData();      
     if (newData != null) { 
      post(new Runnable() { 
       public void run() { 
        Toast.makeText(MyClass.this, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show(); 
       } 
      }); 
     } 
    } 
}; 
update.start(); 

Có vẻ như thể là trong khi tôi đang tải dữ liệu, hoạt động này có thể bị phá hủy. Chuyện gì xảy ra sau đó? Chuỗi của tôi có tiếp tục thực thi không? Tôi sẽ cố gắng truy cập các vật thể chết?

Thông thường tôi làm điều này bởi AsycTask, nhưng công việc dường như đơn giản, đủ thời gian này để chỉ nội tuyến chủ đề-tung-chủ đề công cụ. Tôi sẽ làm mọi thứ tốt hơn bằng cách sử dụng AsyncTask thay thế?

Trả lời

2

Nếu bạn sử dụng các lớp ẩn danh, chúng sẽ có tham chiếu nội bộ đối với lớp bên ngoài, vì vậy nó không giống như nó không thể truy cập được bất ngờ vì các tham chiếu khác đã bị xóa. AsyncTask thực sự không thay đổi bất cứ điều gì, nó sử dụng cơ chế tương tự để thông báo về kết quả.

Bạn có thể sử dụng loaders, chúng được thiết kế để được đồng bộ hóa với vòng đời hoạt động. Chúng chỉ có sẵn từ Android 3.0, nhưng bạn có thể sử dụng support package để làm việc với chúng trên bất kỳ thiết bị nào có phiên bản 1.6 trở lên.

Thậm chí còn có một giải pháp đơn giản hơn, bạn chỉ có thể sử dụng trường boolean cho biết hoạt động đã biến mất hay chưa. Bạn nên đặt trường này trong onPause() (hoặc bất cứ khi nào bạn nghĩ rằng bạn sẽ không cần các thông báo nữa) và kiểm tra nó khi bạn hiển thị bánh mì nướng. Bạn thậm chí sẽ không phải sử dụng đồng bộ hóa, vì trường này được giới hạn trong chuỗi chính, vì vậy nó hoàn toàn an toàn. Nhân tiện, nếu bạn thay đổi trường này ở một nơi khác ngoài số onDestroy(), đừng quên thêm câu lệnh đặt lại trường của bạn về phương thức đối tác.

public class MyActivity extends Activity { 
    private boolean activityDestroyed = false; 

    @Override 
    protected void onDestroy() { 
     activityDestroyed = true; 
    } 

    private void updateData() { 
     new Thread() { 
      @Override 
      public void run() { 
       final Data newData = requestData();      
       if (newData == null) return;            

       runOnUiThread(new Runnable() { 
        public void run() { 
         if (activityDestroyed) return; 
         Toast.makeText(MyActivity.this, "Blah", 
           Toast.LENGTH_SHORT).show(); 
        } 
       }); 
      } 
     }.start(); 
    } 
} 
+0

Điều này có thể sẽ không biên dịch, bạn cần phải làm cho nó tĩnh, hoặc bạn cần phải thêm vào MyActivity.this. – EboMike

+0

Tôi chủ yếu sao chép mã từ câu hỏi chỉ để đưa ra ý tưởng chung, tôi không có ý định mã trong câu trả lời được sử dụng cho các ứng dụng thực tế. Tôi đã cập nhật mã, bây giờ nó sẽ biên dịch (mặc dù điều này không thực sự quan trọng). – Malcolm

+0

Tôi sẽ thử boolean này ngay bây giờ, vì vậy tôi sẽ cung cấp cho bạn một dấu kiểm. Tuy nhiên, cảm ơn bạn đã trả lời, Kurtis và EboMike. Tất cả tôi thậm chí không nghe nói về Loaders cho đến khi bạn đề cập đến chúng. – MaximumGoat

6

Điều bạn thực sự muốn sử dụng là AsyncTaskLoader. Đây là những lớp học yêu thích mới của tôi trong API Android. Tôi sử dụng chúng mọi lúc và chúng được thực hiện để giải quyết vấn đề như thế này. Bạn sẽ không phải lo lắng về thời điểm dừng tải xuống hoặc bất kỳ thứ gì như thế. Tất cả các luồng logic được đưa về chăm sóc cho bạn, bao gồm nói cho sợi chỉ dừng lại nếu hoạt động đã bị đóng. Chỉ cần nói bạn muốn làm gì trong phương thức loadInBackground(). Lưu ý rằng nếu bạn đang phát triển API thấp hơn 3.0, bạn vẫn có thể truy cập tất cả các trình tải thông qua Android Support Package.

+2

Tuyên bố này về chủ đề thực sự không chính xác, họ không dừng lại hoặc thậm chí bị gián đoạn trừ bạn bảo họ làm như vậy trong bộ nạp của bạn.Điều thực sự xảy ra theo mặc định là người nghe cho các kết quả nhiệm vụ chỉ đơn giản là bị loại bỏ khỏi các trình nạp khi chúng được đặt lại. Đó là lý do tại sao bạn sẽ không nhận được một cuộc gọi lại trong đoạn hoặc hoạt động của bạn sau khi nhiệm vụ được hoàn thành, nhưng nó sẽ không bị hủy bỏ. – Malcolm

+0

Ah, ok. Tốt để biết. –

0

Kurtis là đúng. Tuy nhiên, nếu bạn thực sự muốn giữ nó đơn giản, bạn có thể thử này:

class MyActivity extends Activity { 
    static MyActivity context; 

    @Override 
    public void onCreate(Bundle icicle) { 
     super.onCreate(icicle); 

     MyActivity.context = this; 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 

     MyActivity.context = null; 
    } 
} 

Và sau đó bạn chỉ cần sử dụng MyActivity.context trong lớp học của bạn (và kiểm tra cho null có). Nếu bạn muốn bánh mì nướng không xuất hiện khi ứng dụng của bạn ở chế độ nền, hãy sử dụng onPause/onResume để thay thế.

Một lần nữa, đây là cách tiếp cận nhanh và lười. AsyncTask hoặc AsyncTaskLoader là cách bạn nên làm mọi thứ.

+0

Tôi nghĩ rằng việc kiểm tra [isDestroyed()] (http://developer.android.com/reference/android/app/Activity.html#isDestroyed()) trên ví dụ Hoạt động của bạn thay vì đơn giản hơn? –

+0

điều này sẽ gây rò rỉ bộ nhớ nếu thiết lập tham chiếu tĩnh đến hoạt động –

11

Nếu Context của bạn là một Activity, bạn có thể kiểm tra nếu nó được hoàn thiện hoặc đã hoàn tất với isFinishing() phương pháp:

if (context instanceof Activity) { 
    Activity activity = (Activity)context; 
    if (activity.isFinishing()) { 
     return; 
    } 
} 
Toast.makeText(context, "I'll do things here that depend on my context and views being valid", Toast.LENGTH_SHORT).show(); 
+0

Cảm ơn. Giải pháp hoàn hảo cho tôi. – hybrid

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