为什么在OrientListFragment中的onCreate方法在方向更改时调用了两次?首次调用应用程序崩溃后,getActivity()
内的onPostExecute
会返回null
,因此我尝试更改:
new HttpTask(this).execute("");
到
if(savedInstanceStata == null)
new HttpTask(this).execute("");
然后在第二次调用时,savedInstanceState为null,因此mActivatedPosition始终为ListView.INVALID_POSITION
。
我正在使用布局别名,因此activity_list被activity_twopane替换。
MainActivity
public class MainActivity extends Activity implements
TabListener, OnNavigationListener {
/**
* Whether or not the activity is in two-pane mode, i.e. running on a tablet
* device.
*/
private boolean mTwoPane = false;
ResourceReservationApp app = (ResourceReservationApp)getApplication();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list);
mTwoPane = getResources().getBoolean(R.bool.has_two_panes);
if(mTwoPane){
// Set up the action bar to show tabs.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
final String[] dropdownValues = getResources().getStringArray(R.array.dropdown);
for (String item : dropdownValues)
actionBar.addTab(actionBar.newTab().setText(item).setTabListener(this));
}else{
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
final String[] dropdownValues = getResources().getStringArray(R.array.dropdown);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(actionBar.getThemedContext(),
android.R.layout.simple_spinner_item, android.R.id.text1,
dropdownValues);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
actionBar.setListNavigationCallbacks(adapter, this);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_item_list, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
if(tab.getText().equals("Resources")){
ResourceListFragment fragment = new ResourceListFragment();
getFragmentManager().beginTransaction()
.replace(R.id.fragment_list, fragment).commit();
}
if(tab.getText().equals("Reservations")){
ReservationListFragment fragment = new ReservationListFragment();
getFragmentManager().beginTransaction()
.replace(R.id.fragment_list, fragment).commit();
}
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
final String[] dropdownValues = getResources().getStringArray(R.array.dropdown);
if(dropdownValues[itemPosition].equals("Resources")){
ResourceListFragment fragment = new ResourceListFragment();
getFragmentManager().beginTransaction()
.replace(R.id.activity_list, fragment).commit();
}
if(dropdownValues[itemPosition].equals("Reservations")){
ReservationListFragment fragment = new ReservationListFragment();
getFragmentManager().beginTransaction()
.replace(R.id.activity_list, fragment).commit();
}
return true;
}
}
activity_list.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
ResourceListFragment
public class ResourceListFragment extends ListFragment {
private boolean mTwoPane =false;
/**
* The serialization (saved instance state) Bundle key representing the
* activated item position. Only used on tablets.
*/
private static final String STATE_ACTIVATED_POSITION = "activated_position";
/**
* The current activated item position. Only used on tablets.
*/
private int mActivatedPosition = ListView.INVALID_POSITION;
public ResourceListFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTwoPane = getResources().getBoolean(R.bool.has_two_panes);
new HttpTask(this).execute("");
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if(mTwoPane){
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
if (savedInstanceState != null
&& savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) {
setActivatedPosition(savedInstanceState
.getInt(STATE_ACTIVATED_POSITION));
}
}
}
@Override
public void onListItemClick(ListView listView, View view, int position,
long id) {
super.onListItemClick(listView, view, position, id);
// Notify the active callbacks interface (the activity, if the
// fragment is attached to one) that an item has been selected.
((ResourceReservationApp)getActivity().getApplication()).setSelectedResource((Resource)(listView.getAdapter().getItem(position)));
if (mTwoPane) {
// In two-pane mode, show the detail view in this activity by
// adding or replacing the detail fragment using a
// fragment transaction.
setActivatedPosition(position);
Bundle arguments = new Bundle();
arguments.putString(ResourceDetailFragment.ARG_ITEM_ID, id+"");
ResourceDetailFragment fragment = new ResourceDetailFragment();
fragment.setArguments(arguments);
getActivity().getFragmentManager().beginTransaction()
.replace(R.id.detail_container, fragment).commit();
} else {
// In single-pane mode, simply start the detail activity
// for the selected item ID.
Intent detailIntent = new Intent(getActivity(), ResourceDetailActivity.class);
detailIntent.putExtra(ResourceDetailFragment.ARG_ITEM_ID, id);
startActivity(detailIntent);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if(mTwoPane) {
// Serialize and persist the activated item position.
outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition);
outState.putParcelable("AS",(Parcelable) getActivity());
}
}
/**
* Turns on activate-on-click mode. When this mode is on, list items will be
* given the 'activated' state when touched.
*/
private void setActivatedPosition(int position) {
if(mTwoPane)
if (position == ListView.INVALID_POSITION) {
getListView().setItemChecked(mActivatedPosition, false);
} else {
getListView().setItemChecked(position, true);
}
mActivatedPosition = position;
}
private class HttpTask extends AsyncTask<String, Void, List<Resource>> {
String message="Received";
ResourceListFragment fragment;
ProgressDialog dialog;
public HttpTask(ResourceListFragment fragment){
this.fragment=fragment;
}
@Override
protected void onPreExecute() {
dialog = ProgressDialog.show(getActivity(), "Loading...", "Please wait...", true);
}
@Override
protected List<Resource> doInBackground(String... credentials) {
List<Resource>resources=null;
try {
resources =ResourceDAO.getResourcesFromService("gataric","gataric");
if(resources== null){
message = "Error occured!";
return resources;
}
} catch (HttpException e) {
message = e.getMessage();
}
return resources;
}
@Override
protected void onPostExecute(List<Resource> result) {
dialog.dismiss();
if(result!=null)
fragment.setListAdapter(new ArrayAdapter<Resource>(getActivity(),
android.R.layout.simple_list_item_activated_1,
android.R.id.text1, result));
fragment.setActivatedPosition(fragment.mActivatedPosition);
//Toast.makeText(getActivity().getBaseContext(), message, Toast.LENGTH_LONG).show();
}
}
}
activity_twopane.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:baselineAligned="false"
android:divider="?android:attr/dividerHorizontal"
android:orientation="horizontal"
android:showDividers="middle"
tools:context="com.example.resourcereservation.ResourceListActivity" >
<FrameLayout
android:id="@+id/fragment_list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<FrameLayout
android:id="@+id/detail_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" />
答案 0 :(得分:1)
当您的方向更改活动被销毁并重新创建但在重新创建之前onSaveInstanceState()
被调用。因此,请使用onSaveInstanceState()
方法保存数据。然后,您可以在onCreate()
或onRestoreInstanceState()
期间恢复状态。
见this
答案 1 :(得分:0)
您原来的问题:
为什么在OrientListFragment中的onCreate方法在方向更改时调用了两次?
是的,我偶尔也见过这个,并想知道为什么。请参阅Ted Hopp的答案(不是公认的答案):
onCreate(...) is called twice after the device is rotated
你的问题:
禁用方向更改不被视为良好做法:
How do I disable orientation change on Android?
我确定你意识到,在inPostExecute中你需要这样的东西
if (getActivity() != null){
...
}