Застрял с переносом с активности на фрагмент

Прошла ровно неделя, как я пытаюсь портировать простое приложение, основанное на действиях, на фрагменты. Я полностью застрял.

Этот зверь представляет собой простое приложение List, Details, Add/Edit с контекстным меню и меню параметров. Я попытался сделать это правильно: фрагменты и действия каждый в своем собственном файле, используя пакет поддержки v4 для телефона и планшета, фрагменты делают все, что должен делать повторно используемый фрагмент, а обратные вызовы (их много) летают, чтобы информировать действия и фрагменты о том, что делать. Преобразование из SQLiteOpenHelper в ContentProvider, преобразование из optionmenu в actionbarmenu, и, и, и,...(почти все, что я использовал, теперь устарело).

Это ужасно. Мое простое и небольшое приложение, основанное на рабочей деятельности, теперь почти в 3 раза больше, и многие вещи еще не работают.

Если потребуется, я могу добавить сюда свой код, но там много всего (вас предупредили).

Мой вопрос: есть ли кто-нибудь, готовый поделиться полным примером с List, Details ANDAdd/Edit? В этом примере должны использоваться отдельные файлы для фрагментов и действий (а не единый пакет от Google).

Пожалуйста, не голосуйте против. Я действительно хотел бы увидеть, как сделать это правильно.

Заранее большое спасибо.

РЕДАКТИРОВАТЬ:

Вот начальное действие с двумя макетами (res/layout для телефона и res/layout-large-land для планшетов) и контекстным меню:

public class ActivityList extends FragmentActivity implements FragmentList.MyContextItemSelectedListener,
                                                      FragmentList.MyDeleteListener,
                                                      FragmentList.MyListItemClickListener,
                                                      FragmentList.MyOptionsItemSelectedListener,
                                                      FragmentDetails.MyDeleteListener,
                                                      FragmentDetails.MyOptionsItemSelectedListener {

    @Override
    public void myContextItemSelected(final int action, final long id) {
        if (action == R.id.men_add) {
            processEdit(0);
        } else if (action == R.id.men_delete) {
            processUpdateList();
        } else if (action == R.id.men_details) {
            processDetails(id);
        } else if (action == R.id.men_edit) {
            processEdit(id);
        }
    }

    @Override
    public void myDelete(final long id) {
        processUpdateList();
    }

    @Override
    public void myListItemClick(final long id) {
        processDetails(id);
    }

    @Override
    public void myOptionsItemSelected(final int action) {
        myOptionsItemSelected(action, 0);
    }

    @Override
    public void myOptionsItemSelected(final int action, final long id) {
        if (action == R.id.men_add) {
            processEdit(0);
        } else if (action == R.id.men_edit) {
            processEdit(id);
        } else if (action == R.id.men_preferences) {
            processPreferences();
        }
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        processUpdateList();
    }

    @Override
    public void onCreate(final Bundle bundle) {
        super.onCreate(bundle);

        setContentView(R.layout.activitylist);
    }

    private void processEdit(final long id) {
        Intent intent = new Intent(this, ActivityEdit.class);
        intent.putExtra("ID", id);
        startActivityForResult(intent, MyConstants.DLG_TABLE1EDIT);
    }

    private void processDetails(final long id) {
        if (Tools.isXlargeLand(getApplicationContext())) {
            Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.right);
            if (fragment == null ||
                    (fragment instanceof FragmentDetails && ((FragmentDetails) fragment).getCurrentId() != id)) {
                fragment = new FragmentDetails(id);

                FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
                transaction.replace(R.id.right, fragment);
                transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                transaction.commit();
            }
        } else {
            Intent intent = new Intent(this, ActivityDetails.class);
            intent.putExtra("ID", id);
            startActivityForResult(intent, MyConstants.DLG_TABLE1SHOW);
        }
    }

    private void processPreferences() {
        Intent intent = new Intent(this, MyPreferenceActivity.class);
        startActivityForResult(intent, MyConstants.DLG_PREFERENCES);
    }

    private void processUpdateList() {
        // TODO:
    }
}

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment 
        class="com.test.app.FragmentList"
        android:id="@+id/fragmentlist"
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:name="com.test.app.FragmentList" />
</LinearLayout>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >

    <fragment 
        class="com.test.app.FragmentList"
        android:id="@+id/fragmentlist"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:layout_width="0dip"
        android:name="com.test.app.FragmentList" />

    <FrameLayout
        android:id="@+id/right"
        android:layout_height="match_parent"
        android:layout_weight="2"
        android:layout_width="0dip" />
</LinearLayout>

Вот ListFragment с макетом строк, меню параметров и contextmenu:

public class FragmentList extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private SimpleCursorAdapter           adapter;
    private AlertDialog                   alertDialog;
    private Context                       context;
    private MyContextItemSelectedListener contextItemSelectedListener;
    private MyDeleteListener              deleteListener;
    private long                          id;
    private MyListItemClickListener       listItemClickListener;
    private ListView                      listView;
    private MyOptionsItemSelectedListener optionsItemSelectedListener;

    public interface MyContextItemSelectedListener {
        public void myContextItemSelected(int action, long id);
    }

    public interface MyDeleteListener {
        public void myDelete(long id);
    }

    public interface MyListItemClickListener {
        public void myListItemClick(long id);
    }

    public interface MyOptionsItemSelectedListener {
        public void myOptionsItemSelected(int action);
    }

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

        context = getActivity().getApplicationContext();

        listView = getListView();

        getActivity().getSupportLoaderManager().initLoader(MyConstants.LDR_TABLE1LIST, null, this);

        adapter = new SimpleCursorAdapter(context,
                                          R.layout.fragmentlist_row,
                                          null,
                                          new String[] { Table1.DESCRIPTION },
                                          new int[] { R.id.fragmentlist_row_description },
                                          CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        setListAdapter(adapter);
        setListShown(false);

        registerForContextMenu(listView);

        if (bundle != null && bundle.containsKey("ID")) {
            id = bundle.getLong("ID");
            listItemClickListener.myListItemClick(id);
        }

        if (Tools.isXlargeLand(context)) {
            listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
        }

        setHasOptionsMenu(true);
    }

    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);

        // Reduced: Check for implemented listeners
    }

    @Override
    public boolean onContextItemSelected(final MenuItem menuItem) {
        AdapterContextMenuInfo adapterContextMenuInfo = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();

        final long id = adapterContextMenuInfo.id;

        if (menuItem.getItemId() == R.id.men_delete) {
            processAlertDialog(id);
            return true;
        } else {
            contextItemSelectedListener.myContextItemSelected(menuItem.getItemId(), adapterContextMenuInfo.id);
        }

        return super.onContextItemSelected(menuItem);
    }

    @Override
    public void onCreateContextMenu(final ContextMenu contextMenu, final View view, final ContextMenuInfo contextMenuInfo) {
        super.onCreateContextMenu(contextMenu, view, contextMenuInfo);

        if (view.getId() == android.R.id.list) {
            getActivity().getMenuInflater().inflate(R.menu.fragmentlist_context, contextMenu);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(final int id, final Bundle bundle) {
        MyCursorLoader loader = null;

        switch (id) {
            case MyConstants.LDR_TABLE1LIST:
                loader = new MyCursorLoader(context,
                                            MySQLiteOpenHelper.TABLE1_FETCH,
                                            null);
                break;
        }

        return loader;
    }

    @Override
    public void onCreateOptionsMenu(final Menu menu, final MenuInflater menuInflater) {
        super.onCreateOptionsMenu(menu, menuInflater);

        menu.clear();

        menuInflater.inflate(R.menu.fragmentlist, menu);
    }

    @Override
    public void onListItemClick(final ListView listView, final View view, final int position, final long id) {
        super.onListItemClick(listView, view, position, id);

        this.id = id;

        if (Tools.isXlargeLand(context)) {
            listView.setItemChecked(position, true);
        }

        listItemClickListener.myListItemClick(id);
    }

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

    @Override
    public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
        adapter.swapCursor(cursor);

        setListShown(true);
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem menuItem) {
        optionsItemSelectedListener.myOptionsItemSelected(menuItem.getItemId());

        return super.onOptionsItemSelected(menuItem);
    }

    @Override
    public void onSaveInstanceState(final Bundle bundle) {
        super.onSaveInstanceState(bundle);

        bundle.putLong("ID", id);
    }

    private void processAlertDialog(final long id) {
        final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
        alertDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(final DialogInterface dialogInterface, final int which) {
                dialogInterface.dismiss();
            }
        } );
        alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(final DialogInterface dialogInterface, final int which) {
                MyApplication.getSqliteOpenHelper().deleteTable1(id);

                alertDialog.dismiss();

                deleteListener.myDelete(id);
            }
        } );
        alertDialogBuilder.setCancelable(false);
        alertDialogBuilder.setMessage(R.string.txt_reallydelete);

        alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }
}

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    android:orientation="horizontal"
    android:paddingBottom="2dip"
    android:paddingTop="2dip" >

    <TextView
        style="@style/TextViewLarge"
        android:id="@+id/fragmentlist_row_description"
        android:textStyle="bold" />
</LinearLayout>


<menu
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:icon="@drawable/ic_menu_add"
        android:id="@+id/men_add"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_add" />

    <item
        android:icon="@drawable/ic_menu_preferences"
        android:id="@+id/men_preferences"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_preferences" />
</menu>

<menu
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/men_details"
        android:title="@string/txt_details" />

    <item
        android:id="@+id/men_edit"
        android:title="@string/txt_edit" />

    <item
        android:id="@+id/men_delete"
        android:title="@string/txt_delete" />
</menu>

Это DetailsActivity:

public class ActivityDetails extends FragmentActivity implements FragmentDetails.MyDeleteListener, 
                                                                    FragmentDetails.MyOptionsItemSelectedListener {

    private long id;

    @Override
    public void myDelete(final long id) {
        setResult(RESULT_OK);
        finish();
    }

    @Override
    public void myOptionsItemSelected(final int action, final long id) {
        if (action == R.id.men_add) {
            processEdit(0);
        } else if (action == R.id.men_edit) {
            processEdit(id);
        } else if (action == R.id.men_preferences) {
            processPreferences();
        }
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) {
        if (requestCode == MyConstants.DLG_PREFERENCES || requestCode == MyConstants.DLG_TABLE1EDIT) {
            finish();

            startActivity(getIntent()); 
        }
    }

    @Override
    protected void onCreate(final Bundle bundle) {
        super.onCreate(bundle);

        if (bundle != null) {
            if (bundle.containsKey("ID")) {
                id = bundle.getLong("ID");
            }
        } else {
            Bundle bundleExtras = getIntent().getExtras();
            if (bundleExtras != null) {
                id = bundleExtras.getLong("ID");
            }

            processDetails(id);
        }
    }

    @Override
    public void onSaveInstanceState(final Bundle bundle) {
        super.onSaveInstanceState(bundle);

        bundle.putLong("ID", id);
    }

    private void processDetails(final long id) {
        FragmentDetails fragment = new FragmentDetails(id);

        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction.replace(android.R.id.content, fragment);
        transaction.commit();
    }

    private void processEdit(final long id) {
        Intent intent = new Intent(this, ActivityEdit.class);
        intent.putExtra("ID", id);
        startActivityForResult(intent, MyConstants.DLG_TABLE1EDIT);
    }

    private void processPreferences() {
        Intent intent = new Intent(this, MyPreferenceActivity.class);
        startActivityForResult(intent, MyConstants.DLG_PREFERENCES);
    }
}

Вот DetailsFragment с макетом и меню:

public class FragmentDetails extends Fragment {

    private AlertDialog                   alertDialog;
    private MyDeleteListener              deleteListener;
    private long                          id;
    private MyOptionsItemSelectedListener optionsItemSelectedListener;
    private TextView                      textViewDescription;
    private TextView                      textViewId;

    public FragmentDetails() {
        id = 0;
    }

    public FragmentDetails(final long id) {
        this.id = id;
    }

    public long getCurrentId() {
        return id;
    }

    public interface MyDeleteListener {
        public void myDelete(long id);
    }

    public interface MyOptionsItemSelectedListener {
        public void myOptionsItemSelected(int action, long id);
    }

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

        if (bundle != null && bundle.containsKey("ID")) {
            id = bundle.getLong("ID");
        }

        setHasOptionsMenu(true);
    }

    @Override
    public void onAttach(final Activity activity) {
        super.onAttach(activity);

        // Reduced
    }

    @Override
    public void onCreateOptionsMenu(final Menu menu, final MenuInflater menuInflater) {
        super.onCreateOptionsMenu(menu, menuInflater);

        menu.clear();

        menuInflater.inflate(R.menu.fragmentdetails, menu);
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup viewGroup, final Bundle bundle) {
        View view = inflater.inflate(R.layout.fragmentdetails, null);

        textViewDescription = (TextView) view.findViewById(R.id.tv_description);
        textViewId = (TextView) view.findViewById(R.id.tv_id);

        if (id != 0) {
            Table1 table1;
            if ((table1 = MyApplication.getSqliteOpenHelper().getTable1(id)) != null) {
                textViewDescription.setText(Tools.defaultString(table1.getDescription()));
                textViewId.setText(Tools.defaultString(String.valueOf(table1.getId())));
            }
        }

        return view;
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem menuItem) {
        if (menuItem.getItemId() == R.id.men_delete) {
            processAlertDialog(id);
            return true;
        } else {
            optionsItemSelectedListener.myOptionsItemSelected(menuItem.getItemId(), id);
        }

        return super.onOptionsItemSelected(menuItem);
    }

    @Override
    public void onSaveInstanceState(final Bundle bundle) {
        super.onSaveInstanceState(bundle);

        bundle.putLong("ID", id);
    }

    private void processAlertDialog(final long id) {
        final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
        alertDialogBuilder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(final DialogInterface dialogInterface, final int which) {
                alertDialog.dismiss();
                alertDialog = null;
            }
        } );
        alertDialogBuilder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {

            @Override
            public void onClick(final DialogInterface dialogInterface, final int which) {
                MyApplication.getSqliteOpenHelper().deleteTable1(id);

                alertDialog.dismiss();
                alertDialog = null;

                deleteListener.myDelete(id);
            }
        } );
        alertDialogBuilder.setCancelable(false);
        alertDialogBuilder.setMessage(R.string.txt_reallydelete);

        alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }
}

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:orientation="horizontal" >

        <TextView
            style="@style/TextViewStandard"
            android:layout_weight="1" 
            android:text="@string/txt_id" />

        <TextView
            style="@style/TextViewStandard"
            android:id="@+id/tv_id"
            android:layout_weight="1" />
    </LinearLayout>

    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:orientation="horizontal" >

        <TextView
            style="@style/TextViewStandard"
            android:layout_weight="1" 
            android:text="@string/txt_description" />

        <TextView
            style="@style/TextViewStandard"
            android:id="@+id/tv_description"
            android:layout_weight="1" />
    </LinearLayout>
</LinearLayout>

<menu
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:icon="@drawable/ic_menu_add"
        android:id="@+id/men_add"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_add" />

    <item
        android:icon="@drawable/ic_menu_edit"
        android:id="@+id/men_edit"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_edit" />

    <item
        android:icon="@drawable/ic_menu_delete"
        android:id="@+id/men_delete"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_delete" />

    <item
        android:icon="@drawable/ic_menu_preferences"
        android:id="@+id/men_preferences"
        android:showAsAction="ifRoom|withText"
        android:title="@string/txt_preferences" />
</menu>

Я не публикую EditActivity, потому что это просто FragmentActivity без фрагмента.

6
задан Harald Wilhelm 4 April 2012 в 15:14
поделиться