Làm cách nào bạn có thể truyền nhiều tham số nguyên thủy cho AsyncTask?


82

Có những câu hỏi liên quan, chẳng hạn như Làm cách nào tôi có thể chuyển 2 tham số vào một lớp AsyncTask? , nhưng tôi đã gặp khó khăn khi cố gắng chuyển nhiều nguyên thủy làm tham số vô ích cho một AsyncTask, vì vậy tôi muốn chia sẻ những gì tôi đã khám phá ra. Sự tinh tế này không được ghi lại trong các câu hỏi và câu trả lời hiện có, vì vậy tôi muốn giúp đỡ bất cứ ai gặp phải vấn đề tương tự như tôi đã làm và cứu họ khỏi nỗi đau.

Câu hỏi đặt ra là: Tôi có nhiều tham số nguyên thủy (ví dụ: hai long) mà tôi muốn chuyển đến một AsyncTask để được thực thi ở chế độ nền - làm cách nào để thực hiện được? (Câu trả lời của tôi ... sau khi vật lộn với điều này một lúc ... có thể được tìm thấy bên dưới.)


Câu trả lời:


153

Chỉ cần bọc các bản gốc của bạn trong một vùng chứa đơn giản và chuyển nó làm tham số AsyncTask, như sau:

private static class MyTaskParams {
    int foo;
    long bar;
    double arple;

    MyTaskParams(int foo, long bar, double arple) {
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
}

private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
    @Override
    protected void doInBackground(MyTaskParams... params) {
        int foo = params[0].foo;
        long bar = params[0].bar;
        double arple = params[0].arple;
        ...
    }
}

Gọi nó như thế này:

MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);

Điều này cũng hoạt động. Nhưng tôi tin rằng các tùy chọn trên đơn giản hơn.
robguinness

10
Điều này làm tôi thực sự đẹp hơn rất nhiều. Tôi đã sử dụng Object ... params để làm điều đó và vì một số lý do nó không cảm thấy tốt hoặc không an toàn khi làm.
Mafro34

1
Làm việc như người bạn quyến rũ..Cảm ơn đã chia sẻ ..!
Deepak S. Gavkar

2
Rất thanh lịch, thích nó.
Sipty

1
@DavidWasser: thanx cho bản cập nhật của bạn, bên cạnh đó giải pháp đã cho hoạt động rất tốt!
Moussa

93

Một cách khác: Bạn chỉ cần thêm phương thức khởi tạo MyTask trong lớp MyTask của mình:

private class MyTask extends AsyncTask<String, Void, Void> {
    int foo;
    long bar;
    double arple;

    MyTask(int foo, long bar, double arple) { 
         // list all the parameters like in normal class define
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
    ......   // Here is doInBackground etc. as you did before
}

Sau đó gọi

new MyTask(int foo, long bar, double arple).execute();

Một cách thứ hai như Câu trả lời của David Wasser.


9
thực sự đây là cách yêu thích của tôi trong ba cách để truyền các đối số thuộc các loại khác nhau. Không có Đối tượng để ép kiểu và không cần tạo một lớp bổ sung.
QuickFix

3
Bạn cần gọi super () trong hàm tạo ghi đè của mình!
zyamys

2
@zyamys tại sao super () lại cần thiết ở đây? Theo tôi hiểu, nó sẽ được gọi tự động. Xem tại đây stackoverflow.com/a/2054040/984263
carthurs

Trong số các tùy chọn trên chủ đề này, tôi thích điều này nhất. Không có lớp trợ giúp nào, lớp này có thể được sử dụng riêng và mô tả các yêu cầu của riêng nó. Không có vật thể bí ẩn nào được chuyển đi xung quanh. Cảm ơn.
Vinnyq12

Những công việc này. Cảm thấy rất bẩn nhưng tôi quá lười để thử bất cứ thứ gì khác. Không thể tin rằng không có một cách bản địa tốt để làm điều này một cách nguyên bản. Có thể hỗ trợ sau này trong Java<(String,Object,int),Void,Void>
Sirens

82

(Nói một cách chính xác) KHÔNG thể chuyển nhiều nguyên mẫu cho AsyncTask. Ví dụ: nếu bạn muốn thực hiện myTask.execute(long1, long2)và cố gắng thiết lập private class myTask extends AsyncTask<long, Void, Void>bằng phương pháp tương ứng:

@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}

IDE của bạn có thể sẽ phàn nàn về việc cần ghi đè phương thức supertype. Lưu ý rằng bạn đang sử dụng cái gọi là chữ ký phương thức Varargs cho doInBackground, nơi(long... params) giống như nói rằng "Tôi chấp nhận một số lượng dài có thể thay đổi, được lưu trữ dưới dạng một mảng có tên là tham số. Tôi không hoàn toàn hiểu nguyên nhân dẫn đến khiếu nại về trình biên dịch / IDE , nhưng tôi nghĩ nó liên quan đến cách Paramsđịnh nghĩa lớp chung .

Trong mọi trường hợp, bạn có thể đạt được những gì bạn muốn mà không có vấn đề gì, miễn là bạn truyền chính xác các nguyên thủy của mình tới các trình bao bọc không nguyên thủy tương ứng của chúng (ví dụ: int => Integer, long => Long, v.v.). Trên thực tế, bạn không cần phải chuyển các nguyên thủy của mình thành không nguyên thủy một cách rõ ràng. Java dường như xử lý điều đó cho bạn. Bạn chỉ cần thiết lập ASyncTask của mình như sau (ví dụ về longs):

private class MyTask extends AsyncTask<Long, Void, Void> {

    @Override
    protected void doInBackground(Long... params) {
        // Do stuff with params, for example:
        long myFirstParam = params[0]
    }
    ...
}

Sau đó, bạn có thể sử dụng lớp này như dự định ban đầu, ví dụ:

MyTask myTask = new MyTask();
myTask.execute(long1, long2);

Hoặc đối với bất kỳ số nguyên thủy nào mà bạn muốn, HÃY CUNG CẤP CHÚNG LÀ LOẠI CÙNG LOẠI. Nếu bạn cần chuyển nhiều loại nguyên thủy, điều này cũng có thể được thực hiện, nhưng bạn sẽ cần sửa đổi những điều trên để:

private class MyTask extends AsyncTask<Object, Void, Void> {

    @Override
    protected void doInBackground(Object... params) {
        // Do stuff with params, for example:
        long myLongParam = (Long) params[0];
        int myIntParam = (Integer) params[1];

    }
    ...
}

Điều này linh hoạt hơn, nhưng nó yêu cầu truyền các tham số một cách rõ ràng đến các kiểu tương ứng của chúng. Nếu không cần sự linh hoạt này (tức là một kiểu dữ liệu duy nhất), tôi khuyên bạn nên chọn tùy chọn đầu tiên, vì nó dễ đọc hơn một chút.


Bạn cũng có thể sử dụng phần sau cho phương thức protected LocationItemizedOverlay doInBackground(Object[] objects) và thêm phần sau cho định nghĩa tác vụ không đồng bộ. private class MyTask extends AsyncTask<Object, Void, Void>
Hany Sakr

8

Phương thức thực thi được tích hợp sẵn chấp nhận một mảng các Tham số , nhưng tất cả chúng đều phải thuộc kiểu được xác định .. vì vậy nếu bạn chỉ cần đặt kiểu PARAM thành OBJECT , thì bạn có thể truyền vào bất cứ thứ gì bạn thích miễn là chúng là con của các đối tượng. ...

private class MyTask extends AsyncTask<Object, Void, Void> {

Sau đó, trong doInBackGround của bạn, bạn chỉ cần truyền từng tham số để trở lại những gì bạn cần:

 @Override
 protected void doInBackground(Object... params) {
     Context t = (Context)params[0];
     String a = (String) params[1];
     List<LatLng> list = (List<LatLng>)params[2];
     .
     .
     .

Và việc thực thi của bạn chỉ đơn giản là:

 new MyTask().execute(context,somestring,list_of_points);

Hình thức không tốt bằng gói nó trong lớp wrapper của riêng bạn, hoặc một bó, hoặc băm hoặc thứ gì đó, bởi vì bạn đặt hàng phụ thuộc vào cả hai bên, nhưng nó sẽ hoạt động. Tất nhiên, bạn chỉ có thể biến mảng của mình thành một tham số của HashMap (,) và về cơ bản bạn đang triển khai một gói tùy chỉnh tại thời điểm đó, nhưng nó sẽ hoạt động.


1
Những người ở đây thật tuyệt vời với rất nhiều kỹ thuật tuyệt vời và đây là niềm yêu thích của tôi!
George Udosen

7

Tôi thích phương pháp của malajisi, nhưng nếu không, bạn không thể sử dụng lớp Bundle?

 Bundle myBundle = new Bundle();
 myBundle.putInt("foo", foo);
 myBundle.putLong("bar", bar);
 myBundle.putDouble("arple", arple);

Sau đó, chỉ cần chuyển gói và giải nén nó bên trong MyTask. Đây có phải là một ý tưởng khủng khiếp? Bạn tránh tạo một lớp tùy chỉnh và sẽ linh hoạt nếu bạn quyết định cần chuyển các tham số bổ sung sau này.

Cập nhật: Đã khá nhiều năm kể từ khi tôi viết câu trả lời này, và tôi thực sự không thích nó bây giờ. Tôi khuyên bạn không nên sử dụng Gói. Nếu bạn cần chuyển nhiều tham số vào một asynctask (hoặc bất cứ thứ gì, thực sự), hãy sử dụng một lớp tùy chỉnh chứa tất cả các tham số của bạn cùng một lúc. Sử dụng một gói là một giải pháp tốt cho một vấn đề mà bạn không nên mắc phải. Không có luật nào chống lại việc tạo một lớp tùy chỉnh để chứa chính xác những gì bạn cần và không có gì khác.

Ngoài ra, tại sao bạn không sử dụng coroutines? Asynctasks là quá 2014.


Tôi nghĩ điều đó thật tuyệt
BQuadra

Ý tưởng tuyệt vời. Tuy nhiên, tôi giả định rằng điều này không hỗ trợ các đối tượng tùy chỉnh được chuyển vào doInBackground ()
John Ward

1

Điều này được giải quyết thông qua phân lớp. Google có một ví dụ để giải quyết vấn đề này (phân lớp) trong Tài liệu Android AsyncTask chính thức:

http://developer.android.com/reference/android/os/AsyncTask.html

Thí dụ:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        for (int i = 0; i < count; i++) {
            totalSize += Downloader.downloadFile(urls[i]);
            publishProgress((int) ((i / (float) count) * 100));
                 // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        return totalSize;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result) {
        showDialog("Downloaded " + result + " bytes");
    }
}
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.