1

Я заметил эту проблему, когда обновил версию поддержки-v4 с 23.1.1 до 23.4.0: В основном, isAdded() всегда возвращает false в случаях, когда оно использовалось для возврата true.Fragment.isAdded() ведет себя по-разному в support-v4: 23.4.0, чем в предыдущих версиях

У меня есть активность (FragmentActivity), которая имеет ViewPager, который содержит фрагменты. Каждый фрагмент при запуске запускает асинхронную задачу в onCreate() для загрузки некоторых изображений; для эффективности, в обратном вызове, я проверяю isAdded(), чтобы убедиться, что Фрагмент прикреплен до продолжения обработки.

Если я включаю версию 23.1.1 библиотеки поддержки-v4, мой код работает так, как ожидалось. Однако, когда я обновляюсь до 23.4.0, isAdded() почти всегда возвращает false, что не позволяет даже текущему фрагменту завершить обработку результата async.

Примечание: не имеет значения, если я просматриваю альбом - каждый вызов isAdded(), кажется, возвращает false.

Соответствующий код ниже (примечание: некоторый код упрощен для данного примера):

// note FetchableListener implements onFetchableUpdate() 
public class CameraAlbumItemFragment 
    implements Fetchable.FetchableListener 
{ 
    private static final String CAMERA_ALBUM_ITEM_FRAGMENT_CAMERA_KEY = "camera" ; 

    // Member Variables 
    // 
    @Nullable private Camera m_camera ; 
    @Nullable private ArrayList<CameraViewImageDownloadResult> m_imageDownloads; 

    public static CameraAlbumItemFragment newInstance (@NotNull Camera camera) 
    { 
     final CameraAlbumItemFragment fragment = new CameraAlbumItemFragment(); 
     fragment.setRetainInstance(true); 

     final Bundle bundle = new Bundle(1); 
     bundle.putParcelable(CAMERA_ALBUM_ITEM_FRAGMENT_CAMERA_KEY, camera); 

     fragment.setArguments(bundle); 

     return fragment; 
    } 

    @Override 
    public void onCreate (@Nullable Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     m_camera = getArguments().getParcelable(CAMERA_ALBUM_ITEM_FRAGMENT_CAMERA_KEY); 

     // If the images have not been downloaded, then start background 
     // tasks to retrieve them. Not likely, but make sure our camera is not null 
     // 
     if (m_camera != null && m_imageDownloads == null) 
     { 
      // This will start an async task that will call onFetchableUpdate() when it receives a response from the server 
      m_camera.updateNonCurrentViews(getActivity(), this); 
     } 
    } 

    /** The Fragment's UI */ 
    @Override 
    public View onCreateView (@NotNull LayoutInflater inflater, 
           @Nullable ViewGroup container, 
           @Nullable Bundle savedInstanceState) 
    { 
     final View view = inflater.inflate(R.layout.camera_album_item, container, false); 

     // Set image if already downloaded 
     // 
     // Set the on click listener for the cycle image button 
     // This has to be done here instead of using the android:onClick attribute in the layout 
     // file because this is a fragment, not an activity 
     // 
     final ImageView cameraImageView = (ImageView) view.findViewById(R.id.camera_image_view); 

     return view; 
    } 

    /** 
    * Add an image to the list of downloaded images. Display or hide the cycle images button based on 
    * the number of retrieved images 
    * 
    * @param bitmap An image retrieved by a background process 
    */ 
    public void addImage (@Nullable final Bitmap bitmap, @NotNull final String viewName) 
    { 
     assert m_imageDownloads != null; 
     m_imageDownloads.add(new CameraViewImageDownloadResult(bitmap, viewName)); 
    } 

    @Override 
    public void onFetchableUpdate (@NotNull Fetchable fetchable, @Nullable Object data) 
    { 
     //********************************************************* 
     // NOTE: It is the call here to isAdded() that is returning false nearly 
     //  every time in support-v4:23.4.0 but not in 23.1.1 
     //********************************************************** 
     if (fetchable == m_camera && isAdded()) 
     { 
     final List<CameraView> cameraViews = m_camera.getViews(); 
     m_imageDownloads = new ArrayList<>(cameraViews.size()); 

     // Download camera images 
     for (CameraView cameraView : cameraViews) 
     { 
      if (cameraView.isCurrent()) 
      { 
       final String imageURL = cameraView.getCameraURL(); 

       if (imageURL != null) 
       { 
        new GetCameraImageAsyncTask(this, cameraView.getName()).execute(imageURL); 
       } 
       else 
       { 
        Log.e(LOG_TAG, "No valid image URL for " + cameraView.getName()) ; 
        addImage(null, cameraView.getName()); 
       } 
      } 
      else 
      { 
       addImage(null, cameraView.getName()); 
      } 
     } 

     // We don't need to maintain the observer reference anymore 
     m_camera.removeListener(this); 
     } 
    } 

    /** 
    * Get the image view for displaying a camera view 
    * 
    * @return The camera image view 
    */ 
    @Nullable 
    private ImageView getCameraImageView() 
    { 
     final View v = getView(); 
     if (v != null) 
     { 
     return (ImageView)v.findViewById(R.id.camera_image_view); 
     } 
     else 
     { 
     return null; 
     } 
    } 
} 

И его активность (FragmentActivity), который содержит ViewPager

public class CameraAlbumActivity 
    extends FragmentActivity 
{ 
    // Intent Data Key 
    // 
    public final static String CAMERA_ALBUM_SELECTED_ID_KEY = "selectedId" ; 

    private static final String LOG_TAG = "CameraAlbumActivity" ; 

    @Override 
    protected void onCreate (@Nullable Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 

     final Intent intent = getIntent(); 

     final Object sharedData = SharedDataWrapper.getInstance().getData(); 

     CameraCollection cameraCollection ; 

     if (sharedData != null && sharedData instanceof CameraCollection) 
     { 
      cameraCollection = (CameraCollection) sharedData; 
     } 
     else 
     { 
      // just create an empty collection 
      cameraCollection = new CameraCollection() ; 
     } 

     // Load view 
     setContentView(R.layout.album); 

     // Get references to buttons 
     // 
     m_previousButton = (ImageView)findViewById(R.id.album_previous_btn); 
     m_nextButton = (ImageView)findViewById(R.id.album_next_btn); 

     // Configure view pager 
     // 
     m_viewPager = (ViewPager)findViewById(R.id.album_view_pager); 

     final CameraAlbumPagerAdapter adapter = new CameraAlbumPagerAdapter(getSupportFragmentManager(), cameraCollection); 
     m_viewPager.setAdapter(adapter); 
     m_viewPager.addOnPageChangeListener(new OnCyclingContentAlbumViewScrollListener(this, adapter)); 

     // Set the selected item 
     int selectedId = intent.getIntExtra(CAMERA_ALBUM_SELECTED_ID_KEY, -1); 
     if(selectedId == -1) 
     { 
      return; 
     } 

     List<Camera> models = cameraCollection.getAllModels(); 

     for (int i = 0 ; i < models.size() ; i++) 
     { 
      Camera camera = models.get(i); 
      if (selectedId == camera.getId()) 
      { 
       m_viewPager.setCurrentItem(i, false); 
       break; 
      } 
     } 
    } 

    /** 
     * OnPageChangeListeners should be removed to prevent memory leaks 
     */ 
    @Override 
    public void onDestroy() 
    { 
     m_viewPager.clearOnPageChangeListeners() ; 

     super.onDestroy() ; 
    } 

    /** 
     * Scroll one item to the right, if possible 
     * 
     * @param v the view triggering the event 
     */ 
    public void scrollToNext (@SuppressWarnings("UnusedParameters") View v) 
    { 
     int currentIndex = m_viewPager.getCurrentItem(); 

     if(currentIndex < m_viewPager.getAdapter().getCount() - 1) 
     { 
      m_viewPager.setCurrentItem(currentIndex + 1, true); 
     } 
    } 

    /** 
     * Scroll one item to the left, if possible 
     * 
     * @param v the view triggering the event 
     */ 
    public void scrollToPrevious (@SuppressWarnings("UnusedParameters") View v) 
    { 
     int currentIndex = m_viewPager.getCurrentItem(); 

     if(currentIndex > 0) 
     { 
      m_viewPager.setCurrentItem(currentIndex - 1, true); 
     } 
    } 

    /** 
     * Set the visibility of the previous and next buttons based on view pager contents and position 
     */ 
    public void setPreviousAndNextButtonVisibility() 
    { 
     final int position = m_viewPager.getCurrentItem(); 

     m_previousButton.setVisibility(position == 0 ? View.INVISIBLE : View.VISIBLE); 
     m_nextButton.setVisibility(position < m_viewPager.getAdapter().getCount() - 1 ? View.VISIBLE : View.INVISIBLE); 
    } 

    /** 
     * @return The item fragment which is currently displayed 
     */ 
    @Nullable 
    public Fragment getCurrentItemFragment() 
    { 
     int currentItem = m_viewPager.getCurrentItem(); 
     ModelCollectionAlbumPagerAdapter adapter = (ModelCollectionAlbumPagerAdapter)m_viewPager.getAdapter(); 
     return adapter.getRegisteredFragment(currentItem); 
    } 

} 

Я не уверен, если это выпуски с этой версией библиотеки поддержки (надеюсь) или что-то неправильное в моем коде, которое, наконец, появляется с этой последней версией. Как я уже упоминал, если я просто меняю версии в своем файле gradle, приведенный выше код работает так, как ожидалось, в версии 23.1.1, но когда я перехожу на 23.4.0, он терпит неудачу.

Мысли? Предложения?

Спасибо!

+0

Можете ли вы зарегистрировать ошибку на [b.android.com] (http://b.android.com)? – ianhanniballake

+0

Подано в соответствии с выпуском 211043 –

ответ

1

После дальнейшего изучения обновление в библиотеке поддержки выявило недостаток в существующем коде. Обратите внимание, что начало асинхронной задачи начинается с onCreate(). Если задача async завершилась до завершения команды onCreateView(), текущий вызов Fragment.isAdded() вернет false.

По какой бы то ни было причине в старой библиотеке поддержки этого случая не произошло (или если так, то я редко этого не наблюдал). Обновление к новой библиотеке поддержки вызвало это условие довольно последовательно.

Исправить было перемещение начала задачи async в onActivityCreated(), которое, конечно же, вызывается после добавления фрагмента.

0

Вызов этого перед добавлен() исправил проблему для меня.

getSupportFragmentManager().executePendingTransactions();