现在已经一周了,我试图将基于活动的简单应用移植到片段。我完全被卡住了。
这个野兽是一个简单的List,Details,Add / Edit app with contextmenu和optionmenus。我试图做到正确:片段和活动各自在他们自己的文件中,使用v4支持包用于手机和平板电脑,片段执行一个可重复使用的片段应该做的所有事情和回调(很多)飞来通知活动和关于做什么的片段。从SQLiteOpenHelper转换为ContentProvider,从optionmenu转换为actionbarmenu,和,以及......(我现在几乎所有使用的东西都已弃用)。
太可怕了。我的简单和小型基于工作活动的应用程序的大小几乎是现在的3倍,而且许多东西还没有工作。
如果需要,我可以在这里添加我的代码 - 但它有很多东西(你已被警告过)。
我的问题:是否有人愿意与列表分享完整的示例,详情 AND 添加/编辑?此示例应使用片段和活动的单独文件(而不是Google的一体化包)。
请不要投票。我真的很想看看如何做对。
非常感谢提前。
修改
以下是两个布局(电话的res /布局和平板电脑的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的行布局,optionsmenu和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。
答案 0 :(得分:3)
这可能不是答案的全部,而是答案的一部分: 您仍然有一个主要活动,在您曾经拥有listview的xml中,您现在添加了一个framelayout。然后在你的活动中创建你添加以下内容:
mMainFragment = new ListFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.center_container, mMainFragment);
fragmentTransaction.commit();
mCurrentFragment = mMainFragment;
在你的listfragment中
@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;
}
用于listfragment的XML:
<somelayout>
<ListView android:id="@id/android:list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</somelayout>
点击列表在片段中触发:
@Override
public void onListItemClick(ListView list, View view, int position, long id) {
final Item item = (Item) list.getAdapter().getItem(position);
mListener.OnListClick(item);
}
使用此侦听器:
public interface OnListItemClickListener { public void OnListClick(Item item); }
Listfragment需要将其放在最上面:
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnListItemClickListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnListItemClickListener");
}
}
然后主要活动通过实现接口来订阅,并在触发侦听器时启动详细信息片段。
编辑: 好吧,所以你的问题更为基础:)记住每次旋转时你的活动都会调用oncreate,这样你的活动就需要记住要显示的片段,就像它需要记住要显示的视图一样。 您还需要将片段添加到后端堆栈或后端密钥不能使用它们。将片段视为具有功能的视图,它们不是活动。
答案 1 :(得分:1)
我会尝试回答其中一个问题。你写道:
“现在我旋转并点击后退按钮。我希望从编辑到列表页面返回详细信息页面。在我的情况下,应用程序结束。”
从您的代码示例中,您似乎没有将事务添加到后台堆栈。在调用commit()之前调用addToBackStack(),如下所示:
transaction.replace(R.id.fragment_container, newFragment);
transaction.addToBackStack(null);
transaction.commit();