2016-08-14 10 views
1

私のアプリケーションには別の問題があります。私は私のContactAdapterからユーザデータをフェッチするためにMainActivityに次のコードを使用します。AsyncCallbackの優先度

private List<String> loadContactData() { 
    ContactAdapter db = new ContactAdapter(getApplicationContext()); 
    // Spinner Drop down elements 
    List<String> contacts = db.getAllContacts();   
    // Creating adapter for spinner 
    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, 
      android.R.layout.simple_spinner_item, contacts); 
    // Drop down layout style - list view with radio button 
dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);   
    Log.d("SPINNER", String.valueOf(contacts)); 
    return contacts; 
} 

そしてContactAdapter:

public List<String> getAllContacts(){ 
    final List<String> contacts_id = new ArrayList<String>(); 
    final List<String> contacts_name = new ArrayList<String>(); 
    Backendless.Data.of(BackendlessUser.class).find(new AsyncCallback<BackendlessCollection<BackendlessUser>>() { 
     public void handleResponse(BackendlessCollection<BackendlessUser> users) { 
      Iterator<BackendlessUser> userIterator = users.getCurrentPage().iterator(); 
      while (userIterator.hasNext()) { 
       BackendlessUser user = userIterator.next(); 
       String user_mail = user.getEmail(); 
       String user_id = user.getUserId(); 
       contacts_name.add(user_mail); 
       contacts_id.add(user_id); 
      } 
      Log.d("getAllContacts: ", String.valueOf(contacts_name)); } 
     public void handleFault(BackendlessFault backendlessFault) { 
      System.out.println("Server reported an error - " + backendlessFault.getMessage());}}); 
    return contacts_name; 
} 

確かに私の問題は、Backendlessクエリが減速するということです...ので、私のLogcatでは、最初に空の "スピナー"と2番目の "getAllContacts"がサーバーからのユーザーデータを参照しています。その結果、loadContactData()からのreturn contacts文も空です。

loadContactData()でユーザーデータを取得するには、getAllContacts()が最初に完了していることをどのように達成できますか?

答えて

1

あなたの問題は、find呼び出しが非同期であることです(これは良いことであり、handleResponse()が新しいスレッドで呼び出されることを意味します)。したがって、return contacts_nameを実行すると、handleResponse()のコードがまだ実行されていないため、新しいスレッドがまだデータベースの応答を待っているため、contacts_nameはまだ空です。

ファイルまたはネットワークIOが含まれる可能性があるため、データベースへの呼び出しに時間がかかります。あなたのビューで動作しているメインスレッドでこれを行うべきではありません。そうしないと、メインスレッドがUIを更新してスピナーアニメーションをペイントしているため、データベースを待っているためアプリケーションは応答しなくなります。データベースのリクエストを非同期にすることで、アプリケーションは応答したままで、UIは「固まっていません」。

あなたはこのようにそれを行うことができます物事をシンプルに保つために:

public class MyActivity extends AppCompatActivity { 

    private List<String> mContactIds = new ArrayList<>(); 

    private Spinner mSpinner; 

    private ProgressDialog mProgressDialog; 

    @Overrride 
    public void onCreate() { 

     this.setContentView(...); 
     this.mSpinner = ...; 

     this.showLoadingDialog(); 

     Backendless.Data.of(BackendlessUser.class).find(new AsyncCallback<BackendlessCollection<BackendlessUser>>() { 
      public void handleResponse(BackendlessCollection<BackendlessUser> users) { 

       List<String> mails = new ArrayList<>(); 
       List<String> ids = new ArrayList<>(); 
       Iterator<BackendlessUser> userIterator = users.getCurrentPage().iterator(); 
       while (userIterator.hasNext()) { 
        BackendlessUser user = userIterator.next(); 
        String mail = user.getEmail(); 
        String id = user.getUserId(); 
        mails.add(user_mail); 
        ids.add(user_id); 
       } 

       Log.d("getAllContacts: ", String.valueOf(contacts_name)); 
       applyData(mails, ids); 

      } 

      public void handleFault(BackendlessFault backendlessFault) { 
       Log.e("error: ", "Something went wrong"); 

      } 
     }); 
    } 

    private void applyData(List<String> mails, List<String> ids) { 
     Log.d("getAllContacts: ", String.valueOf(contacts_name)); 
     this.hideLoadingDialog(); 
     this.mContactIds = ids; 
     this.mSpinner.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mails); 

    } 

    private void showLoadingDialog() { 
     this.mLoadingDialog = new ProgressDialog(this, null, "Loading contacts...", true); 
     this.mLoadingDialog.dismiss(); 

    } 

    private void hideLoadingDialog() { 
     if(this.mLoadingDialog != null) { 
      this.mLoadingDialog().dismiss(); 

     } 
    } 

    private void showErrorDialog() { 
     this.hideLoadingDialog(); 
     new AlertDialog.Builder(this) 
      .setMessage("Something went wrong, try again") 
      .setPositiveButton("Ok", null) 
      .show(); 

    } 
} 
+0

私は、サーバー上の登録ユーザーでMultiSelectionSpinnerを埋めようとしています。そのため、私は、MainActivityのonCreateで次のコードを使用します:List contact_list = loadContactData(); String [] contact_stringArray = contact_list。toArray(新しいString [contact_list.size()]); スピナー=(MultiSelectionSpinner)findViewById(R.id.mySpinner1); spinner.setItems(contact_stringArray); – Timitrov

+0

サンプルコードをいくつか追加しましたが、これは最小限の努力のソリューションでなければなりません。進行中のダイアログを表示して、データを待っている間何かが起きていることをユーザーに知らせるべきです。また、何かが間違っていたらエラーダイアログを表示する必要があります。 – crysxd

1

ここで最良のオプションは、ContactAdapterにリスナーインタフェースを添付しMainActivityが接続されたインタフェースを実装するためになります。したがって、ContactAdapterがデータの取得を完了すると、それはリスナークラスに通知し、をメインアクティビティonRecieveコールバックから呼び出すことができます。

public void getAllContacts(MyListener listener){ 
final List<String> contacts_id = new ArrayList<String>(); 
final List<String> contacts_name = new ArrayList<String>(); 
Backendless.Data.of(BackendlessUser.class).find(new AsyncCallback<BackendlessCollection<BackendlessUser>>() { 
    public void handleResponse(BackendlessCollection<BackendlessUser> users) { 
     Iterator<BackendlessUser> userIterator = users.getCurrentPage().iterator(); 
     while (userIterator.hasNext()) { 
      BackendlessUser user = userIterator.next(); 
      String user_mail = user.getEmail(); 
      String user_id = user.getUserId(); 
      contacts_name.add(user_mail); 
      contacts_id.add(user_id); 
     } 
     Log.d("getAllContacts: ", String.valueOf(contacts_name)); } 
    public void handleFault(BackendlessFault backendlessFault) { 
     System.out.println("Server reported an error - " + backendlessFault.getMessage());}}); 
listener.done(contacts_name); 

}

およびインターフェースはMyListenerインタフェースを実装する必要があり、この

public interface MyListener { 
    void done(List<String> contactList); 
} 

その後MainActivityのように見えるかもしれませんし、あなたがそこにセットアップスピナーをすることができます行わメソッド内。

私はloadContact()があなたのMainActivityMyListenerインタフェースを実装

private void loadContactData() { 
ContactAdapter db = new ContactAdapter(getApplicationContext()); 
// Spinner Drop down elements 
db.getAllContacts(this);   

} 

ノートのようなものにリファクタリングすることができます信じていました。すなわち

class MainActivity ... implements MyListener { 
    @Override 
    public void done(List<String> contacts) { 
     // Creating adapter for spinner 
    ArrayAdapter<String> dataAdapter = new ArrayAdapter<String>(this, 
     android.R.layout.simple_spinner_item, contacts); 
// Drop down layout style - list view with radio button 
    dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);   
    Log.d("SPINNER", String.valueOf(contacts)); 

    } 

これはあなたがここからあなたの方法を見つけることができるはずだと思います。また、コードをリファクタリングしてみてください。

+0

問題をお寄せいただきありがとうございます!私はどのステップがターゲットに必要なのか理解していますが、MainActivity onReceiveコールバックからloadContactData()を呼び出す方法がわかりません...リストを呼び出すとすぐに contact_list = loadContactData(); onCreateで次のようにonCreateのデータをSpinnerに渡すことができます:spinner =(MultiSelectionSpinner)findViewById(R.id.mySpinner1); spinner.setItems(contact_stringArray);私はもう一度私を助けることができれば嬉しいです – Timitrov

+0

あなたの質問から理解しているところによると、主目的はアダプタとスピナーの値を設定する前に 'バックエンドレス'サービスが完了するのを待つことです。私は 'ContactAdapter'が別のクラスにあると推測しているので、私はコールバックの使用を提案しています。 –