Android IllegalStateException:片段未附加到Activity

时间:2012-06-30 14:56:24

标签: android-fragments android-cursorloader android-loader

我遇到了这个问题,并在这里和其他与此问题相关的帖子中提出了很多帖子。

此应用程序以android 16为目标,但min设置为8.所以我使用Android支持库访问更新的apis。

我有一个活动加载一个ListFragment片段。如果您在横向模式下在平板电脑上运行,则第一个片段(单击列表项时)将以2窗格布局加载第二个片段。如果在手机上,新活动会加载第二个片段。

第二个片段使用CursorLoader访问ContentProvider作为其后备数据存储。当从自己的活动中调用此片段时,没有问题。但是,当它处于2窗格布局时,CursorLoader将因上述异常而失败。

以下是代码:

public class ProgramGroupFragment extends MythtvListFragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final String TAG = ProgramGroupFragment.class.getSimpleName();

    private ProgramCursorAdapter adapter;

    private String programGroup = "*";

    public ProgramGroupFragment() { }

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

        String[] projection = { BaseColumns._ID, ProgramConstants.FIELD_TITLE, ProgramConstants.FIELD_SUB_TITLE };
        String[] selectionArgs = { programGroup };

        CursorLoader cursorLoader = new CursorLoader( getActivity(), ProgramConstants.CONTENT_URI, projection, ProgramConstants.FIELD_TITLE + "=?", selectionArgs, ProgramConstants.FIELD_SUB_TITLE );

        return cursorLoader;
    }

    @Override
    public void onLoadFinished( Loader<Cursor> loader, Cursor cursor ) {
        Log.v( TAG, "onLoadFinished : enter" );

        adapter.swapCursor( cursor );

    }

    @Override
    public void onLoaderReset( Loader<Cursor> loader ) {            
        adapter.swapCursor( null );                 
    }

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

        adapter = new ProgramCursorAdapter(
                getActivity().getApplicationContext(), R.layout.program_row,
                null, new String[] { ProgramConstants.FIELD_SUB_TITLE }, new int[] { R.id.program_sub_title },
                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER );

        setListAdapter( adapter );

        getLoaderManager().initLoader( 0, null, this );
    }

    public void loadPrograms( String name ) {       
        programGroup = name;
        try {
            getLoaderManager().restartLoader( 0, null, this );
        } catch( Exception e ) {
            Log.w( TAG, e.getLocalizedMessage(), e );
        }
    }

    @Override
    public void onListItemClick( ListView l, View v, int position, long id ) {    
        super.onListItemClick( l, v, position, id );

        Intent i = new Intent( getActivity(), VideoActivity.class );
        i.putExtra( VideoActivity.EXTRA_PROGRAM_KEY, id );
        startActivity( i );
    }

    private class ProgramCursorAdapter extends SimpleCursorAdapter {

        public ProgramCursorAdapter( Context context, int layout, Cursor c, String[] from, int[] to, int flags ) {
            super( context, layout, c, from, to, flags );
        }

        @Override
        public View getView( int position, View convertView, ViewGroup parent ) {

            View row =  super.getView( position, convertView, parent );

            getCursor().moveToPosition( position );
            try {
                int idIndex = getCursor().getColumnIndexOrThrow( BaseColumns._ID );
                int titleIndex = getCursor().getColumnIndexOrThrow( ProgramConstants.FIELD_TITLE );
                int subTitleIndex = getCursor().getColumnIndexOrThrow( ProgramConstants.FIELD_SUB_TITLE );

                int id = getCursor().getInt( idIndex );
                String title = getCursor().getString( titleIndex );
                String subTitle = getCursor().getString( subTitleIndex );

                if( row == null ) {
                    LayoutInflater inflater = getActivity().getLayoutInflater();

                    row = inflater.inflate( R.layout.program_row, parent, false );
                }

                TextView t = (TextView) row.findViewById( R.id.program_sub_title );
                t.setText( !"".equals( subTitle ) ? subTitle : title );

            } catch( Exception e ) {
                Log.e( TAG, "getView : error", e );
            }

            return row;
        }

    }

}

问题出现在loadPrograms方法中,特别是行:

getLoaderManager().restartLoader( 0, null, this );

这是抛出IllegalStateException。在查看了文档和大量示例之后,我从未见过这个问题而且必须被抓住才能继续。

我将代码包装在try / catch块中只是为了看看会发生什么,令我惊讶的是,应用程序按预期工作。

编辑: 以下是建立2窗格布局的活动代码:

public class RecordingsActivity extends AbstractRecordingsActivity implements RecordingsFragment.OnProgramGroupListener {

    private static final String TAG = RecordingsActivity.class.getSimpleName();
    private static final int REFRESH_ID = Menu.FIRST + 2;

    private long requestId;
    private BroadcastReceiver requestReceiver;

    private DvrServiceHelper mDvrServiceHelper;

    @Override
    public void onCreate( Bundle savedInstanceState ) {

        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_dvr_recordings );

        RecordingsFragment recordingsFragment = (RecordingsFragment) getSupportFragmentManager().findFragmentById( R.id.fragment_dvr_program_groups );
        recordingsFragment.setOnProgramGroupListener( this );

    }

    @TargetApi( 11 )
    @Override
    public boolean onCreateOptionsMenu( Menu menu ) {
        Log.v( TAG, "onCreateOptionsMenu : enter" );

        MenuItem refresh = menu.add( Menu.NONE, REFRESH_ID, Menu.NONE, "Refresh" );
        if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ) {
            refresh.setShowAsAction( MenuItem.SHOW_AS_ACTION_IF_ROOM );
        }

        return true;
    }

    /* (non-Javadoc)
     * @see org.mythtv.client.ui.dvr.AbstractRecordingsActivity#onOptionsItemSelected(android.view.MenuItem)
     */
    @Override
    public boolean onOptionsItemSelected( MenuItem item ) {

        switch( item.getItemId() ) {
        case REFRESH_ID:

            requestId = mDvrServiceHelper.getRecordingedList();

            return true;
        }

        return super.onOptionsItemSelected( item );
    }

    @Override
    protected void onResume() {
        super.onResume();

        IntentFilter filter = new IntentFilter( DvrServiceHelper.ACTION_REQUEST_RESULT );
        requestReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive( Context context, Intent intent ) {

                long resultRequestId = intent.getLongExtra( DvrServiceHelper.EXTRA_REQUEST_ID, 0 );


                if( resultRequestId == requestId ) {


                    int resultCode = intent.getIntExtra( DvrServiceHelper.EXTRA_RESULT_CODE, 0 );


                    if( resultCode == 200 ) {
                        Log.d( TAG, "Updating UI with new data" );
                    } else {
                        Log.d( TAG, "error occurred" );
                    }
                } else {
                    Log.d( TAG, "Result is NOT for our request ID" );
                }

            }
        };

        mDvrServiceHelper = DvrServiceHelper.getInstance( this );
        registerReceiver( requestReceiver, filter );
    }

    /* (non-Javadoc)
     * @see android.support.v4.app.FragmentActivity#onPause()
     */
    @Override
    public void onPause() {
        super.onPause();

        // Unregister for broadcast
        if( null != requestReceiver ) {
            try {
                unregisterReceiver( requestReceiver );
                requestReceiver = null;
            } catch( IllegalArgumentException e ) {
                Log.e( TAG, e.getLocalizedMessage(), e );
            }
        }

    }

    public void onProgramGroupSelected( String programGroup ) {
        Log.d( TAG, "onProgramGroupSelected : enter" );

        if( null != findViewById( R.id.fragment_dvr_program_group ) ) {
            FragmentManager manager = getSupportFragmentManager();

            ProgramGroupFragment programGroupFragment = (ProgramGroupFragment) manager.findFragmentById( R.id.fragment_dvr_program_group );
            FragmentTransaction transaction = manager.beginTransaction();

            if( null == programGroupFragment ) {
                Log.v( TAG, "onProgramGroupSelected : creating new programGroupFragment" );
                programGroupFragment = new ProgramGroupFragment();

                transaction
                    .add( R.id.fragment_dvr_program_group, programGroupFragment )
                    .setTransition( FragmentTransaction.TRANSIT_FRAGMENT_OPEN )
                    .addToBackStack( null )
                    .commit();
            }

            programGroupFragment.loadPrograms( programGroup );
        } else {

            Intent i = new Intent( this, ProgramGroupActivity.class );
            i.putExtra( ProgramGroupActivity.EXTRA_PROGRAM_GROUP_KEY, programGroup );
            startActivity( i );
        }

    }

}

onProgramGroupSelected上的Listener方法是确定单个vs 2窗格布局的位置。单击左侧疼痛中的列表项时将调用侦听器。

任何人都可以解释为什么会发生这种异常吗?

项目的完整代码位于https://github.com/MythTV-Android/mythtv-for-android

1 个答案:

答案 0 :(得分:1)

我经历过类似的事情。对我来说,在使用上下文时似乎有助于避免使用ApplicationContext。尝试在不使用ProgramCursorAdapter的情况下创建getApplicationContext()