Stuck with transfer from activity to fragment

Now, after a week, I’m trying to transfer a simple application based on actions to fragments. I am completely stuck.

This beast is a simple list, details, adding / editing applications with a context menu and an additional menu. I tried to do everything right: fragments and actions, each in its own file, using the v4 support package for the phone and tablet, fragments do everything that is needed to reuse the fragment, and callbacks (many of them) fly to report actions and fragments on what to do. Conversion from SQLiteOpenHelper to ContentProvider, conversion from optionmenu to actionbarmenu, and, and, and ... (almost everything I used is now deprecated).

This is terrible. My simple and small workplace application is almost 3 times the size, and many things still don't work.

If necessary, I can add my code here, but there are a lot of things (you were warned).

My question is: is there anyone who wants to share a complete example with a list, Details And Add / Modify? This example should use separate files for fragments and actions (rather than Google’s all-in-one package).

Please do not vote. I really would like to see how to do it.

Thank you very much in advance.

EDIT:

Here it starts with two layouts (res / layout for the phone and res / layout-large-land for tablets) and the context menu:

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> 

Here's a ListFragment with its layout, optionsmenu and 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> 

This is 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); } } 

Here's DetailsFragment with layout and menu:

 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> 

I do not post EditActivity because it is just a FragmentActivity without a fragment.

+6
source share
2 answers

This may not be the whole answer, but part of the answer: You still have the main action, in your xml, where you had a listview, now you add a frameelayout. Then in your oncreate actions you add the following:

  mMainFragment = new ListFragment(); FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); fragmentTransaction.replace(R.id.center_container, mMainFragment); fragmentTransaction.commit(); mCurrentFragment = mMainFragment; 

On your list

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // setup view View view = inflater.inflate(R.layout.calendar_list, null); mListAdapter = new CustomAdapter(getActivity(), R.layout.calendar_row, (ArrayList<Item>) mFullList); setListAdapter(mListAdapter); return view; } 

XML for listfragment:

 <somelayout> <ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="match_parent"/> </somelayout> 

Click on the list that runs in the snippet with:

 @Override public void onListItemClick(ListView list, View view, int position, long id) { final Item item = (Item) list.getAdapter().getItem(position); mListener.OnListClick(item); } 

What this listener uses:

public interface OnListItemClickListener {public void OnListClick (position element); }

In the Listfragment should be this on top:

 @Override public void onAttach(Activity activity) { super.onAttach(activity); try { mListener = (OnListItemClickListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnListItemClickListener"); } } 

Then the main action subscribes to this by implementing the interface and launches the fragment of the part when the listener starts.

EDIT: Okay, so your question is much more fundamental :) Remember that oncreate is called up in your activity every time you rotate, so your activity should remember which fragment to show the same way you need to remember which view to show. You also need to add fragments to the back stack, or the back key will not work with them. Think of fragments as representations with a function; they are not actions.

+3
source

I will try to answer one of the questions. You write:

"Now I spin and click the back button. I expect to get back to editing on the Page Details page. In my case, the application ends."

As you can see from your code example, you are not adding transactions to the back stack. Call addToBackStack () immediately before calling commit (), for example:

 transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); transaction.commit(); 
+1
source

Source: https://habr.com/ru/post/912400/


All Articles