Android 创建模块化接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/DanteStones/article/details/46836177

开发过程中通常会碰到这些问题:Activity越来越臃肿,界面中会有越来越多的业务代码,请求代码,上层的耦合越来越严重,维护起来会相当麻烦。项目开发时如果能有一个好的结构是至关重要的,比如最近的MVP架构主要就可以把Activity中的业务代码抽取出来,使Activity层的代码充分解耦,但是实现起来也需要耗费大量精力。这里介绍一种简单的方法来抽取Activity层的业务代码,就是利用Fragment来创建可以复用的模块。

为什么用Fragment

Fragment拥有和Activity很相似的生命周期,onCreate() , onDestroy() 还有自己的生命周期 onAttach() ,onCreateView 。Fragment本身如果不去重写onCreateView()的话是不会有界面的,从而可以把它当做一个纯粹的数据源,或者一个接口模块来进行复用,同时我们还可以利用FragmentManager来很方便的进行通信。

示例

作为dota爱好者这里简单写一个英雄选择的模块
先来实现数据模块 DataFragment,说道英雄选择肯定要有文字和图片

public class DataFragment extends Fragment {

    public static final String TAG = "data";


    public class DataItem{
        private String title;
        private int resId;

        public DataItem(String title, int resId) {
            this.title = title;
            this.resId = resId;
        }

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public int getResId() {
            return resId;
        }

        public void setResId(int resId) {
            this.resId = resId;
        }
    }

    public static DataFragment newInstance() {
        DataFragment fragment = new DataFragment();
        return fragment;
    }

    public DataFragment() {
        // Required empty public constructor
    }

    private ArrayList<DataItem> dataList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        dataList = new ArrayList<>();
        dataList.add(new DataItem("敌法师",R.mipmap.df));
        dataList.add(new DataItem("冰蛙亲儿子",R.mipmap.fw));
        dataList.add(new DataItem("和谐脸",R.mipmap.hexielian));
    }

    public List<DataItem> getData(){
        return dataList;
    }

DataFragment 声明了一个Dataitem内部类用来保存文字,和图片资源id,并在onCreate()中进行赋值,最后提供了一个获取数据的方法。很好理解

选择英雄列表

选择英雄列表选择用一个 DialogFragment来做,原因纯粹是拿来熟悉一下

public class ChooseFragment extends DialogFragment implements AdapterView.OnItemClickListener{

    //回调接口
    private ItemClick mListener;
    private ArrayAdapter mAdapter;

    //工厂方法给出ChooseFragment的实例
    public static ChooseFragment newInstance() {
        ChooseFragment fragment = new ChooseFragment();
        return fragment;
    }

    public ChooseFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //使用最简单的ArrayAdapter来实现列表
        mAdapter = new ArrayAdapter<DataFragment.DataItem>(getActivity(),android.R.layout.simple_list_item_1){
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if(convertView == null){
                    convertView = LayoutInflater.from(getActivity()).inflate(android.R.layout.simple_list_item_1,parent,false);
                }
        //列表的TextView进行赋值
                DataFragment.DataItem item = getItem(position);
                TextView text = (TextView)convertView.findViewById(android.R.id.text1);
                text.setText(item.getTitle());
                return convertView;
            }
        };
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ListView list = new ListView(getActivity());
        list.setAdapter(mAdapter);
        list.setOnItemClickListener(this);
        return list;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);
        //设置了一个选择框的标题
        dialog.setTitle("请选择你的英雄");
        return dialog;
    }

    @Override
    public void onResume() {
        super.onResume();
        //获得最新的数据
        DataFragment df = (DataFragment)getFragmentManager().findFragmentByTag(DataFragment.TAG);
        if(df != null){
            //更新选择数据
            mAdapter.clear();
            for (DataFragment.DataItem item : df.getData()) {
                mAdapter.add(item);
            }
            mAdapter.notifyDataSetChanged();
        }

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            //将onItemClick事件 回调出去
            mListener.ItemClick((DataFragment.DataItem) mAdapter.getItem(position));
            //如果显示对话框将对话框消失
            if(getShowsDialog()){
                dismiss();
            }
    }

    /**
     *onAttach中连接监听接口 确保Activity支持该接口
     */
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (ItemClick) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    /**
     * onDetach中注销接口
     */
    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    //fragment内部自己声明的回调接口
    public interface ItemClick {
        // TODO: Update argument type and name
        public void ItemClick(DataFragment.DataItem item);
    }

ChooseFragment继承DialogFragment 整个界面是一个文字列表,文本用DataItem中的title来进行赋值,使用回调的方式将 listview 的OnItemClickListener事件回调出去。需要注意一点有用的细节就是这里展示了一种Fragment之间通信的方法,onResume()中通过TAG来关联DataFragment,然后通过直接调用DataFragment中的 getData() 方法来获取数据

英雄展示

选择完成后就是展示界面,用一个图片来展示就可以了

public class DetailFragment extends Fragment {

    private ImageView imageView;


    public DetailFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        imageView = new ImageView(getActivity());
        return imageView;
    }

    //画图
    public void paint(int resId){
        imageView.setImageResource(resId);
    }

非常简单,不多说明了。现在数据模块,列表模块,显示模块,都已经写好。剩下的工作就是把3者整合到一起。

Activity中整合

先来看Activity的布局

<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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:onClick="onShowClick"
        android:text="进入英雄选择"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></Button>

    <fragment
        android:id="@+id/fragment_detail"
        android:name="com.haibuzou.common.DetailFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>

button按钮用来调出ChooseFragment 选择列表,已经设置好了点击事件,DetailFragment 用来显示英雄图片。

public class MainActivity extends AppCompatActivity implements ChooseFragment.ItemClick{

    private DetailFragment mDetail;
    private ChooseFragment mChoose;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DataFragment df = (DataFragment)getSupportFragmentManager().findFragmentByTag(DataFragment.TAG);
        if(df == null){
            df = DataFragment.newInstance();
            //希望保存这个实例,在配置变化时 比如横竖屏时获得同一个实例
            df.setRetainInstance(true);
            FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
            //通过Tag而不是id来关联fragment
            ft.add(df,DataFragment.TAG);
            ft.commit();
        }
        //通过xml中的id 获得详情fragment
        mDetail = (DetailFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_detail);
        //获取选择框的Fragment实例
        mChoose = ChooseFragment.newInstance();

    }

    public void onShowClick(View v){
        mChoose.show(getSupportFragmentManager(),null);
    }

    @Override
    public void ItemClick(DataFragment.DataItem item) {
        mDetail.paint(item.getResId());
    }
}

Activity中首先去关联DataFragment,这里有一个小细节setRetainInstance(true) 这个设置是为了告诉FragmentManager即使Ui发生变化比如:横竖屏,也要保存这个DataFragment,保证至始至终只有一个数据模型。接着通过xml中的id R.id.fragment_detail 关联DetailFragment,最后用代码去创建列表 ChooseFragment,并且实现了ChooseFragment中的回调,执行ListView的点击操作。
就这样Fragment把代码整个模块化了。

  1. DataFragment数据模块 只负责提供数据
  2. ChooseFragment 列表模块 只负责显示列表数据
  3. Activity 作为最高指挥官负责整个界面的点击事件,跳转逻辑

3者各司其职,Activity也不再臃肿,并且这些模块都可以进行复用。是不是跃跃欲试了呢

这里写图片描述

猜你喜欢

转载自blog.csdn.net/DanteStones/article/details/46836177