私はこの問題に遭遇し、この問題に関連するここと他の場所の両方で多数の投稿を思いつきました.
このアプリケーションは Android 16 を対象としていますが、min は 8 に設定されています。そのため、Android サポート ライブラリを使用して新しい API にアクセスしています。
ListFragment であるフラグメントをロードするアクティビティがあります。横向きモードのタブレットで実行している場合、リスト項目をクリックすると、最初のフラグメントが 2 番目のフラグメントを 2 ペイン レイアウトでロードします。電話の場合、新しいアクティビティは 2 番目のフラグメントを読み込みます。
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 );
}
}
}
Listener メソッド onProgramGroupSelected は、1 つのペインと 2 つのペインのレイアウトが決定される場所です。左ペインのリスト項目がクリックされると、リスナーが呼び出されます。
この例外が発生する理由を説明できる人はいますか?
プロジェクトの完全なコードは、https://github.com/MythTV-Android/mythtv-for-androidにあります。