2010-04-19 30 views
7

Tôi đang cố gắng để có được một AutoCompleteTextView (ACTV) để hiển thị kết quả tôi nhận được từ một tài nguyên mạng. Tôi đã đặt ngưỡng hoàn thành thành 2 và tôi có thể thấy rằng yêu cầu được kích hoạt khi tôi nhập vào ký tự.AutoCompleteTextView không hiển thị kết quả ngay cả khi ArrayAdapter được cập nhật

Kết quả tôi nhận được là đúng. Cho phép nói rằng tôi viết "ca" và tôi nhận được kết quả "ô tô" dưới dạng tự động hoàn thành. Tôi có một hàm gọi lại nhận kết quả từ AsyncTask và đặt kết quả vào trong ArrayAdapter. Sau đó, tôi gọi .showDropDown() trên ACTV và một dropdown rỗng được hiển thị (một nửa kích thước của một phần tử bình thường). Sau đó, nếu tôi nhập chữ cái cuối cùng "r" và ACTV hiển thị "ô tô", trình đơn thả xuống được hiển thị và kết quả sẽ xuất hiện đột ngột trong danh sách.

Điều tương tự cũng xảy ra nếu tôi đã nhập hai ký tự (trả về kết quả hợp lệ) và xóa chữ cái cuối cùng. Khi thư bị xóa, "ô tô" được hiển thị dưới dạng giá trị tự động hoàn thành.

Có ai gặp sự cố này không? Dường như bộ điều hợp được lấp đầy với kết quả, nhưng kết quả không hiển thị cho đến khi hành động tiếp theo tôi làm. Tôi cũng đã cố gắng chạy .notifyDataSetChanged() sau khi tôi đã thêm kết quả vào bộ điều hợp, nhưng điều đó không cần thiết, hoặc?

+0

Might trợ giúp nếu bạn thêm mã của mình. – Joe

Trả lời

17

Nếu không nhìn thấy mã của bạn, thật khó để biết điều gì có thể xảy ra. Nhưng điều đầu tiên cần lưu ý là yêu cầu mạng của bạn đang xảy ra trên một chuỗi khác nhau và do đó, performFiltering() của bạn có thể trả về kết quả trống sớm. Tại thời điểm đó, publishResults() sẽ trả lại kết quả trống và danh sách thả xuống của bạn trống. Sau đó, AsyncTask của bạn sẽ nhận được kết quả của nó trở lại, và bạn thêm các kết quả vào danh sách của bộ điều hợp, nhưng vì một lý do nào đó, nó không được hiển thị.

Tôi nghĩ bạn có thể nhầm lẫn về nhu cầu về AsyncTask. Đối tượng Filter đã làm một cái gì đó tương tự như AsyncTask: performFiltering() được thực hiện trong một chủ đề nền và publishResults() được gọi từ chuỗi giao diện người dùng, sau khi performFiltering() được hoàn tất. Vì vậy, bạn có thể thực hiện yêu cầu mạng của mình trực tiếp trong performFiltering() và đặt kết quả vào đối tượng FilterResults và bạn sẽ không phải lo lắng về yêu cầu mạng quá chậm và gây ra các sự cố trong giao diện người dùng của mình.

Giải pháp thay thế, phức tạp hơn một chút, nhưng đó là những gì tôi đang làm trong đối tượng Bộ lọc của mình (do kiến ​​trúc hiện có thực hiện cuộc gọi API trong nền, sử dụng gọi lại không đồng bộ thay vì chặn/đồng bộ cần thiết cho performFiltering()), là sử dụng đối tượng đã đồng bộ với wait()/notify() để thực hiện giám sát cross-thread, do đó, hiệu ứng cũng giống như thực hiện yêu cầu mạng trực tiếp trong performFiltering(), nhưng nó thực sự xảy ra nhiều chủ đề:

// in Filter class.. 
protected FilterResults performFiltering(CharSequence constraint) { 

    APIResult response = synchronizer.waitForAPI(constraint); 
    // ... 
} 

// callback invoked after the API call finishes: 
public void onAPIComplete(APIResult results) { 
    synchronizer.notifyAPIDone(results); 
} 

private class Synchronizer { 
    APIResult result; 

    synchronized APIResult waitForAPI(CharSequence constraint) { 
     someAPIObject.startAsyncNetworkRequest(constraint); 
     // At this point, control returns here, and the network request is in-progress in a different thread. 
     try { 
      // wait() is a Java IPC technique that will block execution until another 
      // thread calls the same object's notify() method. 
      wait(); 
      // When we get here, we know that someone else has just called notify() 
      // on this object, and therefore this.result should be set. 
     } catch(InterruptedException e) { } 
     return this.result; 
    } 

    synchronized void notifyAPIDone(APIResult result) { 
     this.result = result; 
     // API result is received on a different thread, via the API callback. 
     // notify() will wake up the other calling thread, allowing it to continue 
     // execution in the performFiltering() method, as usual. 
     notify(); 
    } 
} 

Tuy nhiên, tôi nghĩ bạn có thể thấy yêu cầu mạng của bạn đồng bộ, trực tiếp trong phương thức performFiltering(). Ví dụ mã trên chỉ là một khả năng, nếu bạn đã có kiến ​​trúc tại chỗ cho các cuộc gọi API không đồng bộ/gọi lại, và bạn không muốn thay đổi hành vi đó để có được các kết quả đồng bộ trong performFiltering().

+0

công việc tuyệt vời Joe! Tôi nghĩ rằng bạn đang đúng về nhiệm vụ không đồng bộ trả về dữ liệu SAU KHI lọc peform được thực hiện để có một điều kiện chủng tộc! – reidisaki

+1

cảm ơn bạn đã chỉ rằng performFiltering() được chạy trong một chuỗi nền. –

+0

mát mẻ nhưng khó khăn –

1

Tôi nghĩ câu trả lời của Joe là cách để đi. Tuy nhiên, tôi nghĩ bạn nên sử dụng CountDownLatch thay vì chờ/thông báo.

Lý do là, với việc chờ/thông báo, bạn có nguy cơ một điều kiện chủng tộc nếu API của bạn thực sự trở lại siêu nhanh trước khi bạn bắt đầu "wait()" ... trong trường hợp này, thông báo sẽ không có hiệu lực và chờ đợi () sẽ đợi vô thời hạn. Với Latch, mã sẽ giống như thế này (sao chép từ Joe và sửa đổi):

// in Filter class.. 
protected FilterResults performFiltering(CharSequence constraint) { 
    APIResult response = synchronizer.waitForAPI(constraint); 
    // ... 
} 

// callback invoked after the API call finishes: 
public void onAPIComplete(APIResult results) { 
    synchronizer.notifyAPIDone(results); 
} 

private class Synchronizer { 
    APIResult result; 
    CountDownLatch latch; 

    synchronized APIResult waitForAPI(CharSequence constraint) { 
     latch = new CountDownLatch(1); 
     someAPIObject.startAsyncNetworkRequest(constraint); 
     // At this point, control returns here, and the network request is in-progress in a different thread. 
     try { 
     // Will wait till the count is 0... 
     // If the count is already 0, it'll return immediately. 
     latch.await(); 
     // When we get here, we know that someone else has just called notify() 
     // on this object, and therefore this.result should be set. 
    } catch(InterruptedException e) { } 
    return this.result; 
    } 

    synchronized void notifyAPIDone(APIResult result) { 
    this.result = result; 
    // API result is received on a different thread, via the API callback. 
    // countDown() will wake up the other calling thread, allowing it to continue 
    // execution in the performFiltering() method, as usual. 
    latch.countDown(); 
    } 
} 

Cuối cùng, tôi không có đủ tiền để đăng nhận xét, nếu không tôi sẽ phải ...

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