2011-07-11 27 views
15

Tôi có AsyncTask xử lý một số nội dung HTTP nền. AsyncTask chạy theo lịch trình (Báo động/dịch vụ) và đôi khi người dùng thực thi nó theo cách thủ công.Android AsyncTask - tránh nhiều trường hợp đang chạy

Tôi xử lý các bản ghi từ SQLite và tôi nhận thấy các bài đăng đôi trên máy chủ cho biết rằng đôi khi tác vụ được lập lịch sẽ chạy và đồng thời người dùng chạy thủ công để cùng một bản ghi được đọc và xử lý từ DB hai lần. Tôi xóa hồ sơ sau khi chúng được xử lý nhưng vẫn nhận được bản ghi này.

Tôi nên xử lý nó như thế nào? Có thể tổ chức một số loại hàng đợi?

Trả lời

15

Bạn có thể thực hiện AsyncTask của bạn về một Executor sử dụng executeOnExecutor()

Để đảm bảo rằng các chủ đề đang chạy trong một thời trang nối tiếp xin vui lòng sử dụng: SERIAL_EXECUTOR.

Misc: How to use an Executor

Nếu một số hoạt động đang truy cập vào DB của bạn tại sao không tạo ra một loại cơ sở dữ liệu cổng helper và sử dụng các khối synchronized để đảm bảo chỉ có một thread có quyền truy cập vào nó ở ngay lập tức

0

thử có một số giá trị boolean dụ được đặt thành "true" trên chữ ký của asynctask sau đó "false" trên postexecute. Sau đó, có thể trong kiểm tra doinbackground nếu boolean đó là đúng sự thật. nếu có, sau đó gọi hủy trên nhiệm vụ trùng lặp cụ thể đó.

+1

Tôi sợ rằng nếu tôi sử dụng cờ trong ứng dụng và AsyncTask của tôi không thành công vì lý do nào đó - nó sẽ không bao giờ thực hiện lại vì cờ đã cho thấy nó bắt đầu – katit

6

Khởi tạo AsyncTask thành rỗng. Chỉ tạo một cái mới nếu nó là rỗng. Trong onPostExecute, đặt nó thành null một lần nữa, ở cuối. Làm tương tự trong onCancelled, trong trường hợp người dùng hủy bỏ điều này. Dưới đây là một số mã chưa được kiểm chứng để minh họa ý tưởng cơ bản.

import android.app.Activity; 
import android.os.AsyncTask; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.Button; 

public class FooActivity extends Activity { 

    private class MyAsyncTask extends AsyncTask<Foo, Foo, Foo> { 
     @Override 
     protected void onPostExecute(Foo foo) { 
        // do stuff 
      mMyAsyncTask = null; 
     } 

     @Override 
     protected void onCancelled() { 
      // TODO Auto-generated method stub 
      mMyAsyncTask = null; 
     } 

     @Override 
     protected Foo doInBackground(Foo... params) { 
        try { 
         // dangerous stuff       
        } catch (Exception e) { 
         // handle. Now we know we'll hit onPostExecute() 
        } 

      return null; 
     } 
    } 

    private MyAsyncTask mMyAsyncTask = null; 

    @Override 
    public void onCreate(Bundle bundle) { 
     Button button = (Button) findViewById(R.id.b2); 
     button.setOnClickListener(new View.OnClickListener() { 

      public void onClick(View v) { 
       if (mMyAsyncTask == null) { 
        mMyAsyncTask = new MyAsyncTask(); 
        mMyAsyncTask.execute(null); 
       } 
      } 

     }); 
    } 

}

+0

Tôi đã thử mọi giải pháp khác nhưng vẫn nhận được db không mở ngoại lệ trong khi cố gắng truy cập db bên trong AsyncTask và đây là những gì làm việc cho tôi. Cảm ơn –

+0

Cảm ơn bạn đã có giải pháp tốt. –

10

Hoặc, bạn có thể thử này để xem nếu Task hiện đang chạy hay không:

if (katitsAsyncTask.getStatus().equals(AsyncTask.Status.FINISHED)) 
    katitsAsyncTask.execute(); 
else 
    // wait until it's done. 
+0

Sẽ không hoạt động. Tôi không giữ tham chiếu đến AsyncTask của tôi và họ gọi từ các Hoạt động khác nhau và từ Dịch vụ – katit

+0

Thực ra, tôi cũng khai thác Dịch vụ của tôi. Dịch vụ của tôi giữ nguyên tham chiếu và sẽ không bắt đầu dịch vụ mới cho đến khi dịch vụ hiện tại hoàn tất. Tôi chỉ đơn giản là giữ một hàng đợi của các hoạt động mà muốn sử dụng nó và chạy chúng serially thông qua danh sách, nhưng chỉ có một lời gọi duy nhất tại một thời điểm ... nó hoạt động. – BonanzaDriver

+0

Dịch vụ của tôi không chạy mọi lúc, tôi thực hiện nó bằng Báo thức. Tôi có thể sử dụng cờ "cứng" trong Cơ sở dữ liệu nhưng tôi sợ rằng nếu AsyncTask chết vì bất kỳ lý do gì và sẽ không cập nhật cờ này - một cờ khác sẽ không bao giờ chạy. Tôi có thể làm dấu thời gian và tuyên bố AsyncTask "chết" nếu nó chạy trong một khoảng thời gian nhất định nhưng tôi không thích giải pháp này – katit

0

Bạn có thể giữ trạng thái của nhiệm vụ trong tùy chọn chia sẻ. Kiểm tra giá trị (Boolean có lẽ) trước khi bắt đầu nhiệm vụ. Đặt trạng thái để kết thúc (đúng không?) Trong onPostExecute và sai trong onPreExecute hoặc trong constructor

1

Tôi biết điều này đã được một thời gian trước đây, và bạn đã giải quyết vấn đề của bạn. nhưng tôi chỉ có một vấn đề tương tự. Đề nghị của Reno đã đưa tôi đi đúng hướng, nhưng đối với những người đã thấy khó khăn để lấp đầy khoảng trống. Đây là cách tôi vượt qua một vấn đề tương tự như của katit.

Tôi muốn một AsyncTask cụ thể chỉ chạy nếu nó hiện không chạy. Và như một sự chuyển tiếp từ gợi ý của Reno, giao diện AsyncTask đã được tạo ra để xử lý tất cả các quá trình gritty nitty trong việc xử lý đúng đắn các luồng cho Android. Có nghĩa là, Executor được tích hợp. Vì điều này blog gợi ý:

"Khi thực thi (Object .. params) được gọi trên AsyncTask, nhiệm vụ được thực hiện trong một chủ đề nền. Tùy thuộc vào nền tảng AsyncTasks có thể được thực hiện serially (trước 1.6 và có khả năng một lần nữa trong 4+), hoặc đồng thời (1.6-3.2)

Để đảm bảo chạy liên tục hoặc đồng thời như bạn yêu cầu, từ Cấp 11 trở đi, bạn có thể sử dụng executeOnExecutor (Trình thực thi Executor, Object) .. params) thay vào đó, và cung cấp một trình thực thi, nền tảng này cung cấp hai trình thực thi để thuận tiện, có thể truy cập như AsyncTask.SERIAL_EXECUTOR và AsyncTask.THREAD_POOL_EXECUTOR tương ứng. "

Vì vậy, với điều này trong tâm trí, bạn có thể làm chủ đề chặn thông qua giao diện AsyncTask, nó cũng ngụ ý bạn chỉ có thể sử dụng AsyncTasks.getStatus() để xử lý chủ đề chặn, như DeeV gợi ý trên post này.

trong mã của tôi, tôi quản lý này bằng cách:

Tạo một biến toàn cầu định nghĩa là:

private static AsyncTask<String, Integer, String> mTask = null; 

Và trong onCreate, initialising nó như là một thể hiện của AsyncTask tôi gọi CalculateSpecAndDraw:

mTask = new CalculateAndDrawSpec(); 

Bây giờ khi đã bao giờ tôi muốn gọi AsyncTask này tôi bao quanh thực hiện như sau:

if(mTask.getStatus() == AsyncTask.Status.FINISHED){ 
      // My AsyncTask is done and onPostExecute was called 
      mTask = new CalculateAndDrawSpec().execute(Integer.toString(progress)); 
     }else if(mTask.getStatus() == AsyncTask.Status.PENDING){ 
      mTask.execute(Integer.toString(progress)); 
     }else{ 
      Toast.makeText(PlaySpecActivity.this, "Please Wait..", 1000).show(); 

     } 

này sinh ra một chuỗi mới, nếu nó được hoàn tất, hoặc nếu tình trạng chủ đề đang chờ, các thread được định nghĩa nhưng chưa được bắt đầu, chúng ta bắt đầu nó. Nhưng nếu không, nếu thread đang chạy, chúng tôi không chạy lại nó, chúng tôi chỉ đơn giản là thông báo cho người dùng rằng nó không được hoàn thành, hoặc thực hiện những gì bao giờ hành động chúng tôi muốn. Sau đó, nếu bạn muốn lên lịch sự kiện tiếp theo thay vì chỉ chặn sự kiện tiếp theo, hãy xem tài liệu this về cách sử dụng các nhà thi hành.

0

Làm thế nào về chỉ gói của bạn check-gì-để-gửigửi-nó logic trong một phương pháp synchronized? Cách tiếp cận này dường như làm việc cho chúng tôi.

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