美文网首页
Android编程权威指南 - 第10章 使用fragment

Android编程权威指南 - 第10章 使用fragment

作者: JMasche | 来源:发表于2016-12-08 23:33 被阅读487次

    目标

    本章的目标效果是,在列表中点击一项,弹出明细fragment界面。
    此界面可以修改后,并保存返回列表fragment界面。
    类的调用关系如下:

    类调用关系

    启动明细界面CrimeFragment

    CrimeListFragment类中启动调用

    • 启动是在点击列表的某一项之后,所以在onListItemClick函数中启动
    • 和Activity启动另外一个Activity函数一样,通过显示的声明一个Intent对象,对象指定了调用类和被调用类。需要说明的是,仍旧调用的是包含目标fragment的Activity,而不是直接调用fragment。
    • 仍旧通过intent的putExtra来传递信息。由于明细是要显示对应的对象内容的,所以我们传递了具体的Crime对象给被调用者。并且设置了其对应的key为CrimeFragment.EXTRA_CRIME_ID常量。
    • 通过startActivity()来启动

    具体代码如下

    @Override
    public void onListItemClick(ListView a, View v, int position, long id) {    
          Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);    
          Log.d(TAG, c.getTitle() + " was clicked.");    
    
          // Start CrimeActivity    
          Intent i = new Intent(getActivity(), CrimeActivity.class);    
          i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());    
          startActivity(i);
    }
    

    CrimeFragment类的设计

    获取Intent内容

    和Activity一样,通过activity的getSerializableExtra来获得Intent传递的对象

    UUID crimeId = (UUID)this.getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);
    

    获取Intent并处理的设计

    在哪获取Intent传递的消息信息?
    我们可以直接在CrimeFragment类中使用上面的代码获取Intent的内容,并生成具体的Crime对象,然后刷新明细界面。
    但是这样做的问题在于,牺牲了CrimeFragment的封装性,使得其无法再被其他的activity进行调用。
    所以,我们应该在Activity就处理掉Intent信息,并将获取的信息作为参数传递给Fragment。传递此参数的对象就是Bundle。

    用于传递参数的Bundle对象

    • 每一个Fragment都有一个对应的Bundle对象,我们可以将要使用的参数塞进Bundle对象中,需要的时候再取出来使用。
    • Bundle的参数是key-value形式存储的。

    最终的设计

    • CrimeFragment类中创建一个newInstance的静态方法用于生成CrimeFragment实例。最重要的是,这个方法里包含了Bundle对象的生成和参数的设置。
    public static CrimeFragment newInstance(UUID crimeId) {    
          Bundle args = new Bundle();    
          args.putSerializable(EXTRA_CRIME_ID, crimeId);    
          
          CrimeFragment fragment = new CrimeFragment();    
          fragment.setArguments(args);    
    
          return fragment;
    }
    
    • 这时,我们可以在包含fragment的CrimeActivity类中,获取Intent中的参数。然后调用newInstance生成CrimeFragment实例,并且将Intent中的参数设置进Bundle中。
    public class CrimeActivity extends SingleFragmentActivity {    
          @Override    
          protected Fragment createFragment() {        
                UUID crimeId = (UUID)this.getIntent().getSerializableExtra(CrimeFragment.EXTRA_CRIME_ID);        
                
                return CrimeFragment.newInstance(crimeId);    
          }
    }
    
    • 我们再在CrimeFragment类的onCreate函数中,获取Bundle中的参数,并生成刷新界面需要的Crime对象。
    @Override
    public void onCreate(Bundle savedInstanceState) {    
          super.onCreate(savedInstanceState);    
          
          UUID crimeId = (UUID)getArguments().getSerializable(EXTRA_CRIME_ID);    
          mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
    }
    
    • 在CrimeFragment类的onCreateView函数中设置要显示的界面
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
          View v = inflater.inflate(R.layout.fragment_crime, parent, false);
    
          mTitleField = (EditText)v.findViewById(R.id.crime_title);
          mTitleField.setText(mCrime.getTitle());
    
          ..........................................................
    
          mSolvedCheckBox = (CheckBox)v.findViewById(R.id.crime_solved);
          mSolvedCheckBox.setChecked(mCrime.isSolved());
    
          ...........................................................
    
          return v;
    }
    

    最终效果

    选中列表的Cime 4点击,出现如下明细界面

    明细界面

    列表界面显示明细的修改

    • 我们在明细界面可以修改Title这样的参数,点击返回按钮,默认是不会显示修改信息的。如果需要显示,则需要做相关的处理。
    • 我们只需要一行代码就可以实现这样的功能了。
    ((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
    

    这确实挺神奇的,毕竟在明细界面完全没有配置相关代码,Adapter是需要好好研究的类。

    • 实现功能语句放在哪?
      当我们跳转到CrimeFragment(CrimeActiviy)时,CrimeListActivity和CrimeListFragment是处于暂停的状态。所以当返回时,系统会调用onResume来进行恢复。
      也就是说实现显示变化的语句应该放在CrimeListFragment类的onResume函数中。
    @Override
    public void onResume() {    
          super.onResume();        
          ((CrimeAdapter)getListAdapter()).notifyDataSetChanged();
    }
    

    通过fragment获取返回结果

    • 在CrimeListFragment类中,启动时用的是Fragment的startActivityForResult方法,而不是Activity的此方法;获取返回值并处理时,覆写的是Fragment的onActivityResult方法,而不是Activity的此方法。
    public class CrimeListFragment extends ListFragment {
          private ArrayList<Crime> mCrimes;
          private static final String TAG = "CrimeListFragment";
          private static final int REQUEST_CRIME = 1;
    
          @Override
          public void onListItemClick(ListView a, View v, int position, long id) {    
                Crime c = ((CrimeAdapter)getListAdapter()).getItem(position);    
                Log.d(TAG, c.getTitle() + " was clicked.");    
    
                // Start CrimeActivity    
                Intent i = new Intent(getActivity(), CrimeActivity.class);    
                i.putExtra(CrimeFragment.EXTRA_CRIME_ID, c.getId());    
                startActivityForResult(i, REQUEST_CRIME);
          }
    
          @Override
          public void onActivityResult(int requestCode, int resultCode, Intent data) {    
                if (requestCode == REQUEST_CRIME) {       
                      // Handle result    
                }
          }
    }
    
    • Fragment可以获取返回结果,但是不能产生返回结果。只能通知托管其的Activity来设置返回结果。
    public class CrimeFragment extends Fragment {
    
          public void returnResult() {    
                getActivity().setResult(Activity.RESULT_OK, null);
          }
    }
    

    具体的应用在20章才会详细介绍*

    更新后的程序结构图

    更新后的程序结构图

    相关文章

      网友评论

          本文标题:Android编程权威指南 - 第10章 使用fragment

          本文链接:https://www.haomeiwen.com/subject/bgosmttx.html