To już tydzień dokładnie, gdy próbuję przenieść prostą aplikację opartą na aktywności do fragmentów. Całkowicie utknąłem.Zatrzymany z przeniesieniem z działania do fragmentu
Ta bestia to prosta lista, szczegóły, aplikacja Dodaj/edytuj z menu kontekstowym i menu opcji. Próbowałem to naprawić: Fragmenty i działania każdego w ich własnym pliku, przy użyciu pakietu wsparcia v4 na telefon i tablet, fragmenty robią wszystko, co powinien zrobić fragment wielokrotnego użytku, a wywołania zwrotne (wiele z nich) latają, aby poinformować o działaniach i fragmenty o tym, co robić. Konwersja z SQLiteOpenHelper na ContentProvider, konwersja z menu option na actionbarmenu, oraz, i, and, ... (prawie wszystko, czego użyłem, jest teraz przestarzałe).
To jest okropne. Moja prosta i niewielka aplikacja oparta na aktywności roboczej ma prawie 3 razy większy rozmiar i wiele rzeczy jeszcze nie działa.
Jeśli jest to wymagane, mogę dodać tutaj mój kod - ale jest dużo rzeczy (zostałeś ostrzeżony).
Moje pytanie: Czy jest ktoś chętny do udostępnienia pełnego przykładu z listą, szczegóły ORAZ Dodaj/edytuj? W tym przykładzie należy użyć osobnych plików Fragmentów i Czynności (nie takiego pakietu all-in-one od Google).
Proszę nie głosować w dół. Naprawdę chciałbym zobaczyć, jak to naprawić.
Wielkie dzięki z góry.
EDIT:
Oto aktywność wyjścia z jego dwa układy (res/layout na telefon i res/layout-large-ziemia dla tabletek) i contextmenu:
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>
Oto ListFragment z jego wierszy układ, optionsmenu i 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>
to 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);
}
}
Oto DetailsFragment z układ i 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>
nie opublikować EditActivity bo to po prostu FragmentActivity bez fragmentu.
Moja sugestia bierze jedną rzecz na raz zamiast próbować zrobić całą rzecz na raz. W ten sposób łatwiej go przetestować. – Warpzit
Dzięki. Działa CursorLoader, pasek akcji prawie działa (aktualnie detektory dwóch działań zostają uruchomione, gdy ktoś kliknie w pasek akcji, ponieważ istnieje działanie początkowe i działanie telefonu dla jednego komponentu fragmentu). Największym problemem dla mnie jest to, że nie mam odpowiedniej nawigacji. Chciałbym pokazać tutaj mój kod, ale obawiam się, że ludzie nie polubią tak wiele rzeczy. –
Jeśli chcesz utworzyć link do całego projektu, umieść go na github i podaj link do projektu. – Warpzit