Android

Java安卓学习总结(十四)

第十章 使用fragment argument

有关fragment和activity中相似方法的比较

新建Activity

Activity.startActivity()
Fragment.startActivity()

用法没什么不同。都是通过利用有关Intent来创建新Activity。在构造intent时,都是创建了一个新的方法,将构造intent和附加Extra信息绑定到一个方法里。

获取Extra信息

fragment是直接使用activity的getIntent()来获取intent的,需要用getActivity来获取其所在的activity。然后对intent拆包的方法也相同。

getActivity().getIntent()

fragmen argument与bundle

每一个fragment都和activity一样可以附带一个bundle对象以保存一些数据,fragment.setArguments()本身传入的就是一个bundle类型的文件,这与activity的onSaveInstanceState()方法作用相似。bundle绑定键值对的方法也都一样。

//Activity
protected void onSaveInstanceState(Bundle IS){
  ...
  IS.putXXX();
  ...
}
//Fragment
...
Bundle args=new Bundle();
args.putXXX();
fragment.setArguments(args);
...

在获取bundle时也略有不同。Activity是直接对其bundles进行读取,二Fragment是要先获取argument,通过argument来调用bundles的方法。

//Activity
protected void onSaveInstanceState(Bundle IS){
  ...
  IS.putXXX();
  ...
}
protected void onCreate(Bundle IS){
...
XXX=IS.getXXX();
...
}

//Fragment
...
Bundle args=new Bundle();
args.putXXX();
fragment.setArguments(args);
...

...
XXX=getArguments().getXXX();
...

获取返回结果

Activity.startActivityForResult()
Fragment.startActivityForResult()

Activity.OnActivityResult()
Fragment.OnActivityResult()

activity和fragment都有各自的方法(如上),只不过用法实在是相似,调用时只需要覆盖对应的方法即可。

但是fragment没有serResult()方法,因为“fragment自身无法持有返回结果”,所以需要让托管它的activity来返回结果值:

getActivity().setResult()

有关挑战练习 实现高效的RecyclerView刷新

我的想法是给每一个CrimeFragment一个在列表中的位置,当我从托管这个CrimeFragment返回时就可以将其位置返回给CrimeListFragment,然后再有这个位置来刷新RecyclerView。

CrimeListFragment将位置信息传递给CrimeActivity:把位置信息绑定给对应的ViewHolder,ViewHolder启动CrimeActivity的同时将位置信息绑定给CrimeActivity。

private abstract class Holder extends RecyclerView.ViewHolder
    {
        ...
        public void bind(Crime crime,int position){}

    }
    private class CrimeHolder extends Holder implements View.OnClickListener
    {
        ...
        private int fragmentPosition;

        ...

        public void bind(Crime crime,int position)
        {
            ...
            fragmentPosition=position;
        }

        @Override
        public void onClick(View v) {
            Intent intent=new Intent(CrimeActivity.newIntent(getActivity(),mCrime.getId(),fragmentPosition));
            startActivityForResult(intent,REQUEST_CRIME);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode!= Activity.RESULT_OK)
        {
            return;
        }
        if (requestCode==REQUEST_CRIME)
        {
            if (data==null)
            {
                return;
            }
            CrimePosition=CrimeFragment.getPosition(data);
        }
    }

private class CrimeAdapter extends RecyclerView.Adapter<Holder>
    {
        ...

        @Override
        public void onBindViewHolder(Holder holder, int position) {

            Crime crime=mCrimes.get(position);
            //!!!
            holder.bind(crime,position);
        }

        ...
    }

CrimeActivity将位置信息交给CrimeFragment:将获得的位置信息拆包,附加给创建的CrimeFragment作为Arguments。

private static final String EXTRA_CRIME_ID="com.example.a73421.challenge.crime_id";
    //!!!
    private static final String EXTRA_CRIME_POSITION="com.example.a73421.challenge.crime_position";

    public static Intent newIntent(Context context, UUID crimeID,int position)
    {
        Intent intent=new Intent(context,CrimeActivity.class);
        intent.putExtra(EXTRA_CRIME_ID,crimeID);
        //!!!
        intent.putExtra(EXTRA_CRIME_POSITION,position);
        return intent;
    }
    @Override
    protected Fragment createFragment() {
        UUID crimeID=(UUID)getIntent().getSerializableExtra(EXTRA_CRIME_ID);
        //!!!
        int crimePosition=(int)getIntent().getIntExtra(EXTRA_CRIME_POSITION,0);
        return CrimeFragment.newInstance(crimeID,crimePosition);
    }

CrimeFragment获取位置信息并且在修改文本之后返回位置信息:

private  static final String ARG_CRIME_ID="crime_id";
    //!!!
    private static final String CRIME_POSITION="crime_position";
    private static final String FRAGMENT_POSITION="fragment_position";

    private Crime mCrime;
    //!!!
    private int crimePosition;
    ...

    //!!!
    private void returnResult()
    {
        Intent intent=new Intent();
        intent.putExtra(FRAGMENT_POSITION,crimePosition);
        getActivity().setResult(Activity.RESULT_OK,intent);
    }
    //!!!
    public static int getPosition(Intent intent)
    {
        return intent.getIntExtra(FRAGMENT_POSITION,0);
    }
    @Override
    public void onCreate(Bundle saveInstanceState)
    {
        super.onCreate(saveInstanceState);

        UUID crimeID=(UUID)getArguments().getSerializable(ARG_CRIME_ID);
        //!!!
        crimePosition=(int)getArguments().getInt(CRIME_POSITION);
        mCrime=CrimeLab.get(getActivity()).getCrime(crimeID);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveInstanceState)
    {
        ...
        mTitleField.addTextChangedListener(new TextWatcher() {
            ...
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

                mCrime.setTitle(s.toString());
                //!!!
                returnResult();
            }
            ...});
        ...
    }

这个位置信息的传递过程是CrimeListFragment.Adapter->CrimeListFragment.ViewHolder->CrimeActivity->CrimeFragment->(返回后)CrimeListFragment。看上去就很不合理:因为这个位置信息转了一圈又回到起点了。

观察CZT的做法,他是用了一个函数getLayoutPosition()来直接获取此时的ViewHolder的position,所有代码的改动只有两行。草。

有关挑战练习 优化ClimbLab的表现

原来是遍历找crime的,复杂度为O(n),我觉得吧这个也不是不能接受,非要优化就要用到Map,想要优化效果好还要用unordered_map,但是Java只有hash_map,反正都差不多。

public class CrimeLab
{
    private static CrimeLab sCrimeLab;
    private List<Crime>mCrimes;
    //!!!
    private HashMap<UUID,Integer>findCrime=new HashMap<>();

    public static CrimeLab get(Context context)
    {
        if (sCrimeLab==null)
        {
            sCrimeLab=new CrimeLab(context);
        }
        return sCrimeLab;
    }
    private CrimeLab(Context context)
    {
        mCrimes=new ArrayList<>();
        for (int i=0;i<100;i++)
        {
            Crime crime=new Crime();
            crime.setTitle("Crime #"+i);
            //!!!
            findCrime.put(crime.getId(),i);
            crime.setSolved(i%2==0);
            crime.setRequiresPolice(i%3==0);
            mCrimes.add(crime);
        }
    }
    public List<Crime>getCrimes()
    {
        return mCrimes;
    }
    //!!!
    public Crime getCrime(UUID id)
    {
        if (findCrime.get(id)==null)
        {
            return null;
        }
        else
        {
            return mCrimes.get(findCrime.get(id));
        }
    }
}

发表评论