2

I noticed this issue when I upgraded my support-v4 version from 23.1.1 to 23.4.0: Basically, isAdded() is always returning false in cases where it used to return true.

I have an activity (FragmentActivity) that has a ViewPager which contains Fragments. Each fragment when it starts launches an async task in onCreate() to download some images; for efficiency, in the callback, I am checking isAdded() to ensure the Fragment is attached before continuing the processing.

If I include version 23.1.1 of the support-v4 library, my code works as expected. However, when I update to 23.4.0, isAdded() seems to almost always return false which does not allow even the current fragment to finish processing the async result.

Note: It does not matter if I page through the album -- every call to isAdded() seems to return false.

Relevant code below (note: some code simplified for this example):

 // 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;
      }
   }
}

And its Activity (FragmentActivity) which contains a 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 );
     }

 }

I am not sure if it is an issue with this version of the support library (hopefully) or something incorrect in my code that finally surfaces with this latest release. As I mentioned, if I just swap versions in my gradle file, the above code works as expected in v 23.1.1, but when I change to 23.4.0, it fails.

Thoughts? Suggestions?

Thanks!

4

2 回答 2

1

After further investigation, the update to the support library revealed a flaw in the existing code. Note that the start of the async task begins in onCreate(). If the async task were to finish before onCreateView() completes, the current Fragment.isAdded() call would return false.

For whatever reason, with the older support library, this case did not occur (or if so, so rarely I did not observe it). The update to the new support library triggered this condition fairly consistently.

The fix was to move the start of the async task into onActivityCreated() which, of course, is called after the Fragment has been added.

于 2016-05-24T18:04:50.790 回答
0

Calling this before isAdded() fixed the issue for me.

getSupportFragmentManager().executePendingTransactions();
于 2016-12-22T23:17:59.827 回答