0

我正在尝试在此 Android 教程中构建示例联系人应用程序代码:http: //developer.android.com/training/contacts-provider/retrieve-details.html

那里有示例代码,它只显示给定联系人的地址信息。我能够扩展它以提取所有其他字段,但我无法让其他字段以正确的顺序显示在布局中。

我认为这是因为片段为每个部分使用多个加载器,并在 onLoaderFinished() 中对每个加载器进行布局——但它们完成的顺序是不可预测的。

就像联系人的应用程序一样,只有当该部分有数据时,我才需要能够动态显示部分。例如,电话应该放在第一位,但如果联系人没有电话号码,那么电子邮件应该放在第一位,等等。

处理这个问题的最佳方法是什么?我想到了一些可能性(但尝试失败):

  1. 无需在 onLoadFinished 中为每个光标构建布局,而是使用联系人详细信息填充新的 Contact 类对象。我遇到的问题是我无法确定在哪里构建布局并确保 Contact 对象已完全填充。我得到空指针异常。
  2. 创建一个单独的 ContactLoader 类,该片段调用该类来处理所有 Loader 并返回一个指向 Contact 对象的指针。问题:在开始布局之前,如何确定 Contact 对象已完成填充?
  3. 使用一次调用所有数据列的单个查询加载所有联系人数据。我在为查询设置正确的选择和解析光标时遇到了很多麻烦。

有什么想法吗?

以下是一些代码片段---

这是加载器启动的地方,由 onActivityCreated 调用:

public void setContact(Uri contactLookupUri) {

          mContactUri = contactLookupUri;

      // If the Uri contains data, load the contact's image and load contact details.
      if (contactLookupUri != null) {
          // Asynchronously loads the contact image
          mImageLoader.loadImage(mContactUri, mImageView);

          // Shows the contact photo ImageView and hides the empty view
          mImageView.setVisibility(View.VISIBLE);
          mEmptyView.setVisibility(View.GONE);

          // Shows the edit contact action/menu item
          if (mEditContactMenuItem != null) {
              mEditContactMenuItem.setVisible(true);
          }

          // Starts queries to retrieve contact information from the Contacts Provider.
          // restartLoader() is used instead of initLoader() as this method may be called
          // multiple times.
          getLoaderManager().restartLoader(ContactDetailQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactOrgQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactPhoneQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactEmailQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactAddressQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactGroupsQuery.QUERY_ID, null, this);
          getLoaderManager().restartLoader(ContactEventsQuery.QUERY_ID, null, this);

      } 
  }

这里是 onCreateLoader() 加载器开始查询内容提供者的地方:

public Loader<Cursor> onCreateLoader(int id, Bundle args) {

      final Uri uri = Uri.withAppendedPath(mContactUri, Contacts.Data.CONTENT_DIRECTORY);

      switch (id) {
      case ContactDetailQuery.QUERY_ID:
          // This query loads main contact's name
          return new CursorLoader(getActivity(), mContactUri,
                  ContactDetailQuery.PROJECTION,
                  null, null, null);
      case ContactOrgQuery.QUERY_ID:
          // This query loads contact's company and title details.
          return new CursorLoader(getActivity(), uri,
                  ContactOrgQuery.PROJECTION,
                  ContactOrgQuery.SELECTION,
                  null, null);
      case ContactPhoneQuery.QUERY_ID:
          // This query loads contact address details. 
          return new CursorLoader(getActivity(), uri,
                  ContactPhoneQuery.PROJECTION,
                  ContactPhoneQuery.SELECTION,
                  null, null);
      case ContactEmailQuery.QUERY_ID:
          // This query loads contact email details.
          return new CursorLoader(getActivity(), uri,
                  ContactEmailQuery.PROJECTION,
                  ContactEmailQuery.SELECTION,
                  null, null);
      case ContactAddressQuery.QUERY_ID:
          // This query loads contact address details.
          return new CursorLoader(getActivity(), uri,
                  ContactAddressQuery.PROJECTION,
                  ContactAddressQuery.SELECTION,
                  null, null);
      case ContactGroupsQuery.QUERY_ID:
          // This query loads contact groups the contact belongs to.
          return new CursorLoader(getActivity(), uri,
                  ContactGroupsQuery.PROJECTION,
                  ContactGroupsQuery.SELECTION,
                  null, null);
      case ContactEventsQuery.QUERY_ID:
          // This query loads contact events (birthday, etc) the contact belongs to.
          return new CursorLoader(getActivity(), uri,
                  ContactEventsQuery.PROJECTION,
                  ContactEventsQuery.SELECTION,
                  null, null);
      }
      return null;
  }

这是 onLoadFinished(),它使用一个开关为每个加载器加载一个 buildLayout 函数:

 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 

 // If this fragment was cleared while the query was running      
 // eg. from a call like setContact(uri) then don't do 
 // anything.                 

 if (mContactUri == null) { 
            Log.i(TAG, "mContactUri is null"); 
            return;   
 }

  final LinearLayout.LayoutParams layoutParams =      
          new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 
          ViewGroup.LayoutParams.WRAP_CONTENT);

  switch (loader.getId()) {       

  case ContactDetailQuery.QUERY_ID: 

  // Moves to the first row in the Cursor     
  if (data.moveToFirst()) {

          // For the contact details query, fetches the contact display name.
          // ContactDetailQuery.DISPLAY_NAME maps to the appropriate display      
          // name field based on OS version.

  final String contactName = data.getString(ContactDetailQuery.DISPLAY_NAME);

  if (mIsTwoPaneLayout && mContactName != null) {             
                 // In the two pane layout, there is a dedicated TextView             
                 // that holds the contact name.   
                  mContactName.setText(contactName);      
          } else { 
                 // In the single pane layout, sets the activity title 
                 // to the contact name. On HC+ this will be set as 
                 // the ActionBar title text.

      getActivity().setTitle(contactName);        
           } 
  }               
  break;
          case ContactOrgQuery.QUERY_ID:          

          if (data.moveToFirst()) {
         final String company = data.getString(ContactOrgQuery.COMPANY); 
                   final String title = data.getString(ContactOrgQuery.TITLE);

       //TODO Add Company|Title subtitle here to the ActionBar.                                        
          }   
  }   
  break;

  case ContactPhoneQuery.QUERY_ID:                
  // This query loads the contact phone details. Same as addresses above.   

  // Loops through all the rows in the Cursor     
  if (data.moveToFirst()) {

  // Displays the header for this category        
          final FrameLayout headerLayout = addHeaderLayout(ContactPhoneQuery.header); 
          mDetailsLayout.addView(headerLayout, layoutParams);
  do {    
          // Builds the phone layout 
          final LinearLayout layout = buildLayout(    
               data.getInt(ContactPhoneQuery.TYPE),
       data.getString(ContactPhoneQuery.LABEL),
       data.getString(ContactPhoneQuery.NUMBER),
       ContactPhoneQuery.QUERY_ID);       
          // Adds the new address layout to the details layout 
          mDetailsLayout.addView(layout, layoutParams);   
  } while (data.moveToNext());                
  } else {
      // If nothing found, adds an empty layout
          mDetailsLayout.addView(buildEmptyLayout(), layoutParams);     
  } 
  break;  

  // Etc for all the Loaders that were called in setContact() 

}

4

1 回答 1

0

我想到了。我把所有东西都放到了一个 Loader 中,然后用不同的 SELECTION 运行了几个查询。现在好多了!

于 2013-10-25T19:57:43.757 回答