public class CorePage implements Serializable {private static final long serialVersionUID = 3736359137726536495L;private String mName;//页面名private String mClazz;//页面classprivate String mParams;//传入参数,json object结构public CorePage(String name, String clazz, String params) {mName = name;mClazz = clazz;mParams = params;}public String getClazz() {return mClazz;}public void setClazz(String clazz) {mClazz = clazz;}public String getName() {return mName;}public void setName(String name) {mName = name;}public String getParams() {return mParams;}public void setParams(String params) {mParams = params;}@Overridepublic String toString() {return "Page{" +"mName="" + mName + """ +", mClazz="" + mClazz + """ +", mParams="" + mParams + """ +"}";}}实体类编写好了,为了更方便的进行页面跳转,我们需要像Activity那样,有一个配置文件,里面存着Fragment名到其全类名的映射关系。那么这些数据存在哪呢。我们参考网络数据,一般从网络上获取的数据有两种格式,一种是json,一种是xml,json由于其优点,在网络传输中被大量使用,这里,我们优先使用json,选定了json之后,就要选定一个json解析的框架,我们不使用android系统自带的,我们使用阿里的fastjson,当然你也可以使用gson或者jackson。我们的Fragment有很多,所以这个Fragment的配置文件应该是一个json数组。就像这个样子[ {"name": "test1","class": "cn.edu.zafu.corepage.sample.TestFragment1","params": { "param1": "value1", "param2": "value2"} }, {"name": "test2","class": "cn.edu.zafu.corepage.sample.TestFragment2","params": "" }]有了这个配置,我们就要在程序进入时读取这个配置。我们将这个配置放在assets目录下,当然你也可以放在其他目录下,只有你能读取到就行,甚至你可以放在压缩包里。然而,实际情况下,这个文件不应该暴露,因为一旦暴露就存在风险。因此,大家可以采用更安全的方式存这些数据,比如把数据压缩到压缩包中,增加一个密码,而读取文件的内容的代码我们移到native中取实现,毕竟java层太容易被反编译了,而c/c++层相对来说会毕竟有难度。/** * 从assets目录下读取文件 * * @param context 上下文 * @param fileName 文件名 * @return */private String readFileFromAssets(Context context, String fileName) {String result = "";try {InputStreamReader inputReader = new InputStreamReader(context.getResources().getAssets().open(fileName));BufferedReader bufReader = new BufferedReader(inputReader);String line = "";while ((line = bufReader.readLine()) != null)result += line;} catch (Exception e) {e.printStackTrace();}return result;}然后根据该文件内容读取json配置。读取出来后需要将这些数据保存下来。因此要有一个数据结构来保存这个对象,存完之后还要方便取出,存取的依据应该是Fragment的表示,即前面提到的name,因此Map这个数据结构是最适合不过了。private Map<String, CorePage> mPageMap = new HashMap<String, CorePage>();//保存page的map将配置读取出来存进该map,读取的时候判断name和class是否为空,为空则跳过。
/** * 从配置文件中读取page */private void readConfig() {Log.d(TAG, "readConfig from json");String content = readFileFromAssets(mContext, "page.json");JSONArray jsonArray = JSON.parseArray(content);Iterator<Object> iterator = jsonArray.iterator();JSONObject jsonPage = null;String pageName = null;String pageClazz = null;String pageParams = null;while (iterator.hasNext()) {jsonPage = (JSONObject) iterator.next();pageName = jsonPage.getString("name");pageClazz = jsonPage.getString("class");pageParams = jsonPage.getString("params");if (TextUtils.isEmpty(pageName) || TextUtils.isEmpty(pageClazz)) {Log.d(TAG, "page Name is null or pageClass is null");return;}mPageMap.put(pageName, new CorePage(pageName, pageClazz, pageParams));Log.d(TAG, "put a page:" + pageName);}Log.d(TAG, "finished read pages,page size:" + mPageMap.size());}此外,除了从配置文件中读取,我们应该可以动态添加,对外提供这个函数。/** * 新增新页面 * * @param name 页面名 * @param clazz 页面class * @param params 页面参数 * @return 是否新增成功 */public boolean putPage(String name, Class<? extends BaseFragment> clazz, Map<String, String> params) {if (TextUtils.isEmpty(name) || clazz == null) {Log.d(TAG, "page Name is null or pageClass is null");return false;}if (mPageMap.containsKey(name)) {Log.d(TAG, "page has already put!");return false;}CorePage corePage = new CorePage(name, clazz.getName(), buildParams(params));Log.d(TAG, "put a page:" + name);return true;}/** * 从hashMap中得到参数的json格式 * * @param params 页面map形式参数 * @return json格式参数 */private String buildParams(Map<String, String> params) {if (params == null) {return "";}String result = JSON.toJSONString(params);Log.d(TAG, "params:" + result);return result;}文章开头已经说了,页面跳转的参数是json形式的字符串,我们还要这么一个函数,能够根据json字符串构造出一个bundle/** * 根据page,从pageParams中获得bundle * * @param corePage 页面 * @return 页面的参数 */private Bundle buildBundle(CorePage corePage) {Bundle bundle = new Bundle();String key = null;Object value = null;if (corePage != null && corePage.getParams() != null) {JSONObject j = JSON.parseObject(corePage.getParams());if (j != null) {Set<String> keySet = j.keySet();if (keySet != null) {Iterator<String> ite = keySet.iterator();while (ite.hasNext()) {key = ite.next();value = j.get(key);bundle.putString(key, value.toString());}}}}return bundle;}以上配置读取的一系列函数,构成了页面管理类CorePageManager,我们对其应用单例模式。/** * 跳转页面管理 */public class CorePageManager {private volatile static CorePageManager mInstance = null;//单例private Context mContext;//Context上下文/** * 构造函数私有化 */private CorePageManager() {}/** * 获得单例 * * @return PageManager */public static CorePageManager getInstance() {if (mInstance == null) {synchronized (CorePageManager.class) {if (mInstance == null) {mInstance = new CorePageManager();}}}return mInstance;}/** * 初始化配置 * * @param context 上下文 */public void init(Context context) {try {mContext = context.getApplicationContext();readConfig();} catch (Exception e) {e.printStackTrace();}}}其中init函数暴露给程序入口,进行配置文件的读取。一般放在Application的子类的onCreate方法中即可。 /** * 页面跳转核心函数之一 * 打开一个fragemnt * * @param fragmentManager FragmentManager管理类 * @param pageName 页面名 * @param bundle 参数 * @param animations 动画类型 * @param addToBackStack 是否添加到返回栈 * @return */public Fragment openPageWithNewFragmentManager(FragmentManager fragmentManager, String pageName, Bundle bundle, int[] animations, boolean addToBackStack) {BaseFragment fragment = null;try {CorePage corePage = this.mPageMap.get(pageName);if (corePage == null) {Log.d(TAG, "Page:" + pageName + " is null");return null;}fragment = (BaseFragment) Class.forName(corePage.getClazz()).newInstance();Bundle pageBundle = buildBundle(corePage);if (bundle != null) {pageBundle.putAll(bundle);}fragment.setArguments(pageBundle);fragment.setPageName(pageName);FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();if (animations != null && animations.length >= 4) {fragmentTransaction.setCustomAnimations(animations[0], animations[1], animations[2], animations[3]);}Fragment fragmentContainer = fragmentManager.findFragmentById(R.id.fragment_container);if (fragmentContainer != null) {fragmentTransaction.hide(fragmentContainer);}fragmentTransaction.add(R.id.fragment_container, fragment, pageName);if (addToBackStack) {fragmentTransaction.addToBackStack(pageName);}fragmentTransaction.commitAllowingStateLoss();//fragmentTransaction.commit();} catch (Exception e) {e.printStackTrace();Log.d(TAG, "Fragment.error:" + e.getMessage());return null;}return fragment;}而上面这个函数中的id值在一个基础的布局中,之后的Fragment都会添加到该布局中去。我们的基类Activity也将使用这个布局,这个后续编写BaseActivity的时候会提到<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/fragment_container"android:layout_width="fill_parent"android:layout_height="fill_parent" ></FrameLayout>此外,我们再提供一个核心函数。就是如果返回栈中存在了目标fragment,则将其弹出,否则新建fragment打开。
/** * 页面跳转核心函数之一 * 打开一个Fragement,如果返回栈中有则出栈,否则新建 * * @param fragmentManager FragmentManager管理类 * @param pageName 页面别名 * @param bundle 参数 * @param animations 动画 * @return 成功跳转到的fragment */public Fragment gotoPage(FragmentManager fragmentManager, String pageName, Bundle bundle, int[] animations) {Log.d(TAG, "gotoPage:" + pageName);Fragment fragment = null;if (fragmentManager != null) {fragment = fragmentManager.findFragmentByTag(pageName);}if (fragment != null) {fragmentManager.popBackStackImmediate(pageName, 0);} else {fragment = this.openPageWithNewFragmentManager(fragmentManager, pageName, bundle, animations, true);}return fragment;}细心的你可能已经注意到了页面跳转函数中用到了动画,其实这个动画是一个数组,为了方便使用,我们将其封装为枚举类,提供常见的几种动画形式。package cn.edu.zafu.corepage.core;/** * 页面切换动画类别 */public enum CoreAnim {none, /* 没有动画 */present, /*由下到上动画 */slide,/* 从左到右动画 */fade;/*渐变 */}之后我们还要根据该枚举类获得对应的动画的xml文件。/** * 动画转化,根据枚举类返回int数组 * * @param coreAnim * @return */public static int[] convertAnimations(CoreAnim coreAnim) {if (coreAnim == CoreAnim.present) {int[] animations = {R.anim.push_in_down, R.anim.push_no_ani, R.anim.push_no_ani, R.anim.push_out_down};return animations;} else if (coreAnim == CoreAnim.fade) {int[] animations = {R.anim.alpha_in, R.anim.alpha_out, R.anim.alpha_in, R.anim.alpha_out};return animations;} else if (coreAnim == CoreAnim.slide) {int[] animations = {R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right};return animations;}return null;}这里贴出一个alpha_in.xml中的代码,其他文件类似,这些文件都位于res/anim目录下<?xml version="1.0" encoding="utf-8"?><alpha xmlns:android="http://schemas.android.com/apk/res/android"android:duration="@android:integer/config_mediumAnimTime"android:fromAlpha="0.0"android:toAlpha="1.0" />到了这里,如果你都明白了,那么后面基本上就没有什么难度了,因为之后的功能都是基于以上内容。
/** * 页面跳转控制参数 */public class CoreSwitchBean implements Parcelable {public static final Parcelable.Creator<CoreSwitchBean> CREATOR = new Parcelable.Creator<CoreSwitchBean>() {@Overridepublic CoreSwitchBean createFromParcel(Parcel in) {return new CoreSwitchBean(in);}@Overridepublic CoreSwitchBean[] newArray(int size) {return new CoreSwitchBean[size];}};private String mPageName;//页面名private Bundle mBundle;//相关数据private int[] mAnim = null;//动画类型private boolean mAddToBackStack = true;//是否添加到栈中private boolean mNewActivity = false;//是否起新的Activityprivate int requestCode = -1;//fragment跳转public CoreSwitchBean(String pageName) {this.mPageName = pageName;}public CoreSwitchBean(String pageName, Bundle bundle) {this.mPageName = pageName;this.mBundle = bundle;}public CoreSwitchBean(String pageName, Bundle bundle, CoreAnim coreAnim) {this.mPageName = pageName;this.mBundle = bundle;this.setAnim(coreAnim);}public void setAnim(CoreAnim anim) {mAnim = convertAnimations(anim);}/** * 动画转化,根据枚举类返回int数组 * * @param coreAnim * @return */public static int[] convertAnimations(CoreAnim coreAnim) {if (coreAnim == CoreAnim.present) {int[] animations = {R.anim.push_in_down, R.anim.push_no_ani, R.anim.push_no_ani, R.anim.push_out_down};return animations;} else if (coreAnim == CoreAnim.fade) {int[] animations = {R.anim.alpha_in, R.anim.alpha_out, R.anim.alpha_in, R.anim.alpha_out};return animations;} else if (coreAnim == CoreAnim.slide) {int[] animations = {R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right};return animations;}return null;}public CoreSwitchBean(String pageName, Bundle bundle, int[] anim) {this.mPageName = pageName;this.mBundle = bundle;this.mAnim = anim;}public CoreSwitchBean(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack) {this.mPageName = pageName;this.mBundle = bundle;this.setAnim(coreAnim);this.mAddToBackStack = addToBackStack;}public CoreSwitchBean(String pageName, Bundle bundle, int[] anim, boolean addToBackStack) {this.mPageName = pageName;this.mBundle = bundle;this.mAnim = anim;this.mAddToBackStack = addToBackStack;}public CoreSwitchBean(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack, boolean newActivity) {this.mPageName = pageName;this.mBundle = bundle;this.setAnim(coreAnim);this.mAddToBackStack = addToBackStack;this.mNewActivity = newActivity;}public CoreSwitchBean(String pageName, Bundle bundle, int[] anim, boolean addToBackStack, boolean newActivity) {this.mPageName = pageName;this.mBundle = bundle;this.mAnim = anim;this.mAddToBackStack = addToBackStack;this.mNewActivity = newActivity;}public CoreSwitchBean(String pageName, Bundle bundle, int[] anim, boolean addToBackStack, boolean newActivity, int requestCode) {this.mPageName = pageName;this.mBundle = bundle;this.mAnim = anim;this.mAddToBackStack = addToBackStack;this.mNewActivity = newActivity;this.requestCode = requestCode;}protected CoreSwitchBean(Parcel in) {mPageName = in.readString();mBundle = in.readBundle();int[] a = {in.readInt(), in.readInt(), in.readInt(), in.readInt()};mAnim = a;mAddToBackStack = in.readInt() == 1 ? true : false;mNewActivity = in.readInt() == 1 ? true : false;requestCode = in.readInt();}public String getPageName() {return mPageName;}public void setPageName(String pageName) {mPageName = pageName;}public boolean isNewActivity() {return mNewActivity;}public void setNewActivity(boolean newActivity) {mNewActivity = newActivity;}public boolean isAddToBackStack() {return mAddToBackStack;}public void setAddToBackStack(boolean addToBackStack) {mAddToBackStack = addToBackStack;}public int[] getAnim() {return mAnim;}public void setAnim(int[] anim) {mAnim = anim;}public Bundle getBundle() {return mBundle;}public void setBundle(Bundle bundle) {mBundle = bundle;}public int getRequestCode() {return requestCode;}public void setRequestCode(int requestCode) {this.requestCode = requestCode;}@Overridepublic String toString() {return "SwitchBean{" +"mPageName="" + mPageName + """ +", mBundle=" + mBundle +", mAnim=" + Arrays.toString(mAnim) +", mAddToBackStack=" + mAddToBackStack +", mNewActivity=" + mNewActivity +", requestCode=" + requestCode +"}";}@Overridepublic int describeContents() {return 0;}@Overridepublic void writeToParcel(Parcel out, int flags) {if (mPageName == null) {mPageName = "";}if (mBundle == null) {mBundle = new Bundle();}if (mAnim == null) {int[] a = {-1, -1, -1, -1};mAnim = a;}out.writeString(mPageName);mBundle.writeToParcel(out, flags);if (mAnim != null && mAnim.length == 4) {out.writeInt(mAnim[0]);out.writeInt(mAnim[1]);out.writeInt(mAnim[2]);out.writeInt(mAnim[3]);} else {out.writeInt(-1);out.writeInt(-1);out.writeInt(-1);out.writeInt(-1);}out.writeInt(mAddToBackStack ? 1 : 0);out.writeInt(mNewActivity ? 1 : 0);out.writeInt(requestCode);}}该类中的部分属性有一些默认值,比如是否添加到返回栈,是否起新Activity,我们默认在当前activity中打开fragment,并且添加到返回栈。有了这个类,之后的页面切换都通过该实体类进行传参就可以了。/** * 页面跳转接口,用于控制页面跳转或启动新的activity */public interface CoreSwitcher {/** * 返回到前一个页面(只有一个fragment时会关闭Activityt) */void popPage();/** * fragmentTag 是否在当前顶上activity上的最顶上的fragment * * @param fragmentTag * @return */boolean isFragmentTop(String fragmentTag);/** * 是否查找到某个page * * @param pageName * @return */boolean findPage(final String pageName);/** * 跳转到某一个页面。 * * @param bean * @return */Fragment gotoPage(CoreSwitchBean bean);/** * 打开一个新的页面 * * @param bean * @return */Fragment openPage(CoreSwitchBean bean);/** * 移除当前Acitivity不需要的fragment * * @param fragmentLists */void removeUnlessFragment(List<String> fragmentLists);/** * 页面跳转,支持跨Activity进行传递数据 * * @param page * @param fragment * @return */public Fragment openPageForResult(final CoreSwitchBean page, final BaseFragment fragment);}到了这里,似乎已经初具模型了,接下来,我们实现该接口。为了保证在子线程中也能调用这些方法,我们需要一个主线程的handler来帮我们完成一部分工作。假设我们已经获得了这个handler。具体细节看下面的代码实现吧,仔细阅读以下不难理解的。private static List<WeakReference<BaseActivity>> mActivities = new ArrayList<WeakReference<BaseActivity>>();//所有activity的引用private Handler mHandler = null;//线程安全的handlerprivate WeakReference<BaseActivity> mCurrentInstance = null;//当前activity的引用/** * 弹出页面 */@Overridepublic void popPage() {popOrFinishActivity();//如果只有一个Fagment则退出activty}/** * 保证在主线程操作 */private void popOrFinishActivity() {if (this.isFinishing()) {return;}if (this.getSupportFragmentManager().getBackStackEntryCount() > 1) {if (isMainThread()) {this.getSupportFragmentManager().popBackStackImmediate();} else {this.mHandler.post(new Runnable() {@Overridepublic void run() {getSupportFragmentManager().popBackStackImmediate();}});}} else {finishActivity(this, true);}}/** * 是否是主线程 * @return */private boolean isMainThread() {return Thread.currentThread() == this.getMainLooper().getThread();}/** * 是否位于栈顶 * @param fragmentTag * @return */@Overridepublic boolean isFragmentTop(String fragmentTag) {int size = mActivities.size();if (size > 0) {WeakReference<BaseActivity> ref = mActivities.get(size - 1);BaseActivity item = ref.get();if (item != null && item == this) {FragmentActivity activity = item;FragmentManager manager = activity.getSupportFragmentManager();if (manager != null) {int count = manager.getBackStackEntryCount();if (count >= 1) {FragmentManager.BackStackEntry entry = manager.getBackStackEntryAt(count - 1);if (entry.getName().equalsIgnoreCase(fragmentTag)) {return true;}}}}}return false;}/** * 查找fragment * @param pageName * @return */@Overridepublic boolean findPage(String pageName) {int size = mActivities.size();int j = size - 1;boolean hasFind = false;for (; j >= 0; j--) {WeakReference<BaseActivity> ref = mActivities.get(j);if (ref != null) {BaseActivity item = ref.get();if (item == null) {Log.d(TAG, "item is null");continue;}FragmentManager manager = item.getSupportFragmentManager();int count = manager.getBackStackEntryCount();for (int i = count - 1; i >= 0; i--) {String name = manager.getBackStackEntryAt(i).getName();if (name.equalsIgnoreCase(pageName)) {hasFind = true;break;}}if (hasFind) {break;}}}return hasFind;}/** * 弹出并用bundle刷新数据,在onFragmentDataReset中回调 * @param page * @return */@Overridepublic Fragment gotoPage(CoreSwitchBean page) {if (page == null) {Log.e(TAG, "page name empty");return null;}String pageName = page.getPageName();if (!findPage(pageName)) {Log.d(TAG, "Be sure you have the right pageName" + pageName);return this.openPage(page);}int size = mActivities.size();int i = size - 1;for (; i >= 0; i--) {WeakReference<BaseActivity> ref = mActivities.get(i);if (ref != null) {BaseActivity item = ref.get();if (item == null) {Log.d(TAG, "item null");continue;}boolean findInActivity = popFragmentInActivity(pageName, page.getBundle(), item);if (findInActivity) {break;} else {item.finish();// 找不到就弹出}}}return null;}/** * 当前activiti中弹fragment * @param pageName * @param bundle * @param findAcitivity * @return */protected boolean popFragmentInActivity(final String pageName, Bundle bundle, BaseActivity findAcitivity) {if (pageName == null || findAcitivity == null || findAcitivity.isFinishing()) {return false;} else {final FragmentManager fragmentManager = findAcitivity.getSupportFragmentManager();if (fragmentManager != null) {Fragment frg = fragmentManager.findFragmentByTag(pageName);if (frg != null && frg instanceof BaseFragment) {if (fragmentManager.getBackStackEntryCount() > 1 && mHandler != null) {mHandler.postDelayed(new Runnable() {@Overridepublic void run() {fragmentManager.popBackStack(pageName, 0);}}, 100);}((BaseFragment) frg).onFragmentDataReset(bundle);//默认为空实现,用于舒心返回时的页面数据,重写改方法完成数据刷新return true;}}}return false;}/** * 根据Switchpage打开activity * @param page */public void startActivity(CoreSwitchBean page) {try {Intent intent = new Intent(this, BaseActivity.class);intent.putExtra("SwitchBean", page);this.startActivity(intent);int[] animations = page.getAnim();if (animations != null && animations.length >= 2) {this.overridePendingTransition(animations[0], animations[1]);}} catch (Exception e) {e.printStackTrace();Log.e(TAG, e.getMessage());}}/** * 根据SwitchBean打开fragment * @param page * @return */@Overridepublic Fragment openPage(CoreSwitchBean page) {boolean addToBackStack = page.isAddToBackStack();boolean newActivity = page.isNewActivity();Bundle bundle = page.getBundle();int[] animations = page.getAnim();if (newActivity) {startActivity(page);return null;} else {String pageName = page.getPageName();return CorePageManager.getInstance().openPageWithNewFragmentManager(getSupportFragmentManager(), pageName, bundle, animations, addToBackStack);}}/** * 移除无用fragment * @param fragmentLists */@Overridepublic void removeUnlessFragment(List<String> fragmentLists) {if (this.isFinishing()) {return;}FragmentManager manager = getSupportFragmentManager();if (manager != null) {FragmentTransaction transaction = manager.beginTransaction();for (String tag : fragmentLists) {Fragment fragment = manager.findFragmentByTag(tag);if (fragment != null) {transaction.remove(fragment);}}transaction.commitAllowingStateLoss();int count = manager.getBackStackEntryCount();if (count == 0) {this.finish();}}}/** * 给BaseFragment调用 * @param page * @param fragment * @return */@Overridepublic Fragment openPageForResult(CoreSwitchBean page, BaseFragment fragment) {if (page != null) {if (page.isNewActivity()) {Log.d(TAG,"openPageForResult start new activity-----"+fragment.getPageName());mFragmentForResult=fragment;mFragmentRequestCode=page.getRequestCode();startActivityForResult(page);return null;}else{String pageName=page.getPageName();Bundle bundle=page.getBundle();int[] animations=page.getAnim();boolean addToBackStack=page.isAddToBackStack();BaseFragment frg = (BaseFragment) CorePageManager.getInstance().openPageWithNewFragmentManager(getSupportFragmentManager(), pageName, bundle, animations, addToBackStack);if (frg==null){return null;}final BaseFragment opener= fragment;frg.setRequestCode(page.getRequestCode());frg.setFragmentFinishListener(new BaseFragment.OnFragmentFinishListener() {@Overridepublic void onFragmentResult(int requestCode, int resultCode, Intent intent) {opener.onFragmentResult(requestCode,resultCode,intent);}});return frg;}}else{Log.d(TAG, "openPageForResult.SwitchBean is null");}return null;}public void startActivityForResult(CoreSwitchBean page) {try {Intent intent = new Intent(this, BaseActivity.class);intent.putExtra("SwitchBean", page);intent.putExtra("startActivityForResult", "true");this.startActivityForResult(intent, page.getRequestCode());int[] animations = page.getAnim();if (animations != null && animations.length >= 2) {this.overridePendingTransition(animations[0], animations[1]);}} catch (Exception e) {e.printStackTrace();}}/** * 如果是fragment发起的由fragment处理,否则默认处理 * @param requestCode * @param resultCode * @param data */@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {Log.d(TAG, "onActivityResult from baseActivity" + requestCode + " " + resultCode);if (mFragmentRequestCode == requestCode && mFragmentForResult != null) {mFragmentForResult.onFragmentResult(mFragmentRequestCode, resultCode, data);}super.onActivityResult(requestCode, resultCode, data);}除此之外,提供一些函数的重载便于调用以及一些工具函数。/** * 仅用于接受应用退出广播,程序退出时有机会做一些必要的清理工作 */private BroadcastReceiver mExitReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(Config.ACTION_EXIT_APP)) {Log.d(TAG,"exit from broadcast");finish();}}};/** * 返回最上层的activity * * @return */public static BaseActivity getTopActivity() {if (mActivities != null) {int size = mActivities.size();if (size >= 1) {WeakReference<BaseActivity> ref = mActivities.get(size - 1);if (ref != null) {return ref.get();}}}return null;}/** * 广播退出时清理activity列表 */public static void unInit() {if (mActivities != null) {mActivities.clear();}}/** * 获得当前活动页面名 * @return */protected String getPageName() {BaseFragment frg = getActiveFragment();if (frg != null) {return frg.getPageName();}return "";}/** * 打开fragment,并设置是否新开activity,设置是否添加到返回栈 * * @param pageName * @param bundle * @param coreAnim * @param addToBackStack * @param newActivity * @return */public Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack, boolean newActivity) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, coreAnim, addToBackStack, newActivity);return openPage(page);}/** * 打开fragment,并设置是否新开activity,设置是否添加到返回栈 * * @param pageName * @param bundle * @param anim * @param addToBackStack * @param newActivity * @return */public Fragment openPage(String pageName, Bundle bundle, int[] anim, boolean addToBackStack, boolean newActivity) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, anim, addToBackStack, newActivity);return openPage(page);}/** * 打开fragment,并设置是否添加到返回栈 * * @param pageName * @param bundle * @param coreAnim * @param addToBackStack * @return */public Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, coreAnim, addToBackStack);return openPage(page);}/** * 打开fragment,并设置是否添加到返回栈 * * @param pageName * @param bundle * @param anim * @param addToBackStack * @return */public Fragment openPage(String pageName, Bundle bundle, int[] anim, boolean addToBackStack) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, anim, addToBackStack);return openPage(page);}/** * 打开fragment * * @param pageName * @param bundle * @param coreAnim * @return */public Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, coreAnim);return openPage(page);}/** * 打开fragment * * @param pageName * @param bundle * @param anim * @return */public Fragment openPage(String pageName, Bundle bundle, int[] anim) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, anim);return openPage(page);}/** * 如果当前activity中只有一个activity,则关闭activity,否则父类处理 */@Overridepublic void onBackPressed() {if (this.getSupportFragmentManager().getBackStackEntryCount() == 1) {this.finishActivity(this, true);} else {super.onBackPressed();}}/** * 如果fragment中处理了则fragment处理否则activity处理 * @param keyCode * @param event * @return */@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {BaseFragment activeFragment = getActiveFragment();boolean isHanlde = false;if (activeFragment != null) {isHanlde = activeFragment.onKeyDown(keyCode, event);}if (!isHanlde) {return super.onKeyDown(keyCode, event);} else {return isHanlde;}}/** * 获得当前活动fragmnet * * @return */public BaseFragment getActiveFragment() {if (this.isFinishing()) {return null;}FragmentManager manager = this.getSupportFragmentManager();if (manager != null) {int count = manager.getBackStackEntryCount();if (count > 0) {String tag = manager.getBackStackEntryAt(count - 1).getName();return (BaseFragment) manager.findFragmentByTag(tag);}}return null;}/** * 打印,调试用 */private void printAllActivities() {Log.d(TAG, "------------BaseActivity print all------------activities size:" + mActivities.size());for (WeakReference<BaseActivity> ref : mActivities) {if (ref != null) {BaseActivity item = ref.get();if (item != null) {Log.d(TAG, item.toString());}}}}/** * 结束activity,设置是否显示动画 * * @param activity * @param showAnimation */private void finishActivity(BaseActivity activity, boolean showAnimation) {if (activity != null) {activity.finish();}if (showAnimation) {//动画int[] animations = null;if (activity.mFirstCoreSwitchBean != null && activity.mFirstCoreSwitchBean.getAnim() != null) {animations = activity.mFirstCoreSwitchBean.getAnim();}if (animations != null && animations.length >= 4) {overridePendingTransition(animations[2], animations[3]);}}}并在BaseActivity的onCreate方法中完成一些初始化工作。/** * 页面跳转都通过BaseActivity 嵌套Fragment来实现,动态替换fragment只需要指定相应的参数。 避免Activity 需要再manifest中注册的问题。 * 1.管理应用中所有BaseActivity 实例。 2.管理BaseActivity 实例和fragment的跳转 */public class BaseActivity extends FragmentActivity implements CoreSwitcher {private static final String TAG = BaseActivity.class.getSimpleName();private static List<WeakReference<BaseActivity>> mActivities = new ArrayList<WeakReference<BaseActivity>>();protected CoreSwitchBean mFirstCoreSwitchBean;//记录首个,用于页面切换//所有activity的引用private Handler mHandler = null;private WeakReference<BaseActivity> mCurrentInstance = null;//当前activity的引用private BaseFragment mFragmentForResult = null;//forResult 的fragmentprivate int mFragmentRequestCode = -1;//请求码,必须大于等于0/** * 仅用于接受应用退出广播,程序退出时有机会做一些必要的清理工作 */private BroadcastReceiver mExitReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (action.equals(Config.ACTION_EXIT_APP)) {Log.d(TAG,"exit from broadcast");finish();}}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_base);Intent mNewIntent = getIntent();//处理新开activity的情况if (null != savedInstanceState) {loadActivitySavedData(savedInstanceState);//恢复数据//需要用注解SaveWithActivity}mHandler = new Handler(getMainLooper());//获得主线程handlermCurrentInstance = new WeakReference<BaseActivity>(this);//当前activity弱引用mActivities.add(mCurrentInstance);//当前activity增加到activity列表中printAllActivities();//打印所有activity情况init(mNewIntent);//处理新开activity跳转IntentFilter filter = new IntentFilter();filter.addAction(Config.ACTION_EXIT_APP);filter.addCategory(Intent.CATEGORY_DEFAULT);BaseApplication.getLocalBroadcastManager().registerReceiver(mExitReceiver, filter);//注册本地广播,接收程序退出广播}}接下来就是处理基类BaseFragment的问题了,这里贴出该类所有代码,具体请参考注释。public class BaseFragment extends Fragment {private static final String TAG = BaseFragment.class.getSimpleName();protected Activity mActivity;//所在activityprivate String mPageName;//页面名private int mRequestCode;//用于startForResult的requestCodeprivate CoreSwitcher mPageCoreSwitcher;//openPageForResult接口,用于传递返回结果private OnFragmentFinishListener mFragmentFinishListener;/** * 设置该接口用于返回结果 * @param listener OnFragmentFinishListener对象 */public void setFragmentFinishListener(OnFragmentFinishListener listener) {this.mFragmentFinishListener = listener;}/** * 设置openPageForResult打开的页面的返回结果 * @param resultCode 返回结果码 * @param intent 返回的intent对象 */public void setFragmentResult(int resultCode, Intent intent) {if (mFragmentFinishListener != null) {mFragmentFinishListener.onFragmentResult(mRequestCode, resultCode, intent);}}/** * 得到requestCode * @return 请求码 */public int getRequestCode() {return this.mRequestCode;}/** * 设置requestCode * @param code 请求码 */public void setRequestCode(int code) {this.mRequestCode = code;}/** * 将Activity中onKeyDown在Fragment中实现, * @param keyCode * @param event * @return */public boolean onKeyDown(int keyCode, KeyEvent event) {return false;}/** * 数据设置,回调 * @param bundle */public void onFragmentDataReset(Bundle bundle) {}/** * 弹出栈顶的Fragment。如果Activity中只有一个Fragemnt时,Acitivity也退出。 */public void popToBack() {this.popToBack(null, null);}/** * 如果在fragment栈中找到,则跳转到该fragment中去,否则弹出栈顶 * @param pageName 页面名 * @param bundle 参数 */public final void popToBack(String pageName, Bundle bundle) {CoreSwitcher coreSwitcher = getSwitcher();if (coreSwitcher != null) {if (pageName == null) {coreSwitcher.popPage();} else {if (this.findPage(pageName)) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle);coreSwitcher.gotoPage(page);} else {coreSwitcher.popPage();}}} else {Log.d(TAG, "pageSwitcher null");}}/** * 得到页面切换Switcher,即BaseActivity * @return Switcher */public CoreSwitcher getSwitcher() {synchronized (BaseFragment.this) {// 加强保护,保证pageSwitcher 不为nullif (mPageCoreSwitcher == null) {if (this.mActivity != null && this.mActivity instanceof CoreSwitcher) {mPageCoreSwitcher = (CoreSwitcher) this.mActivity;}if (mPageCoreSwitcher == null) {BaseActivity topActivity = BaseActivity.getTopActivity();if (topActivity != null && topActivity instanceof CoreSwitcher) {mPageCoreSwitcher = (CoreSwitcher) topActivity;}}}}return mPageCoreSwitcher;}public void setSwitcher(CoreSwitcher pageCoreSwitcher) {this.mPageCoreSwitcher = pageCoreSwitcher;}/** * 查找fragment是否存在,通过Switcher查找 * @param pageName 页面名 * @return 是否找到 */public boolean findPage(String pageName) {if (pageName == null) {Log.d(TAG, "pageName is null");return false;}CoreSwitcher coreSwitcher = getSwitcher();if (coreSwitcher != null) {return coreSwitcher.findPage(pageName);} else {Log.d(TAG, "pageSwitch is null");return false;}}/** * 对应fragment是否位于栈顶,通过Switcher查找 * @param fragmentTag fragment的tag * @return 是否位于栈顶 */public boolean isFragmentTop(String fragmentTag) {CoreSwitcher pageCoreSwitcher = this.getSwitcher();if (pageCoreSwitcher != null) {return pageCoreSwitcher.isFragmentTop(fragmentTag);} else {Log.d(TAG, "pageSwitcher is null");return false;}}/** * 重新该方法用于获得返回的数据 * @param requestCode 请求码 * @param resultCode 返回结果码 * @param data 返回数据 */public void onFragmentResult(int requestCode, int resultCode, Intent data) {Log.d(TAG, "onFragmentResult from baseFragment:requestCode-" + requestCode + " resultCode-" + resultCode);}/** * 在当前activity中打开一个fragment,并添加到返回栈中 * @param pageName Fragemnt 名,在page.json中配置。 * @param bundle 页面跳转时传递的参数 * @param coreAnim 指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @return */public final Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim) {return this.openPage(pageName, bundle, CoreSwitchBean.convertAnimations(coreAnim), true);}/** * 在当前activity中打开一个fragment,并设置是否添加到返回栈 * @param pageName Fragemnt 名,在page.json中配置。 * @param bundle 页面跳转时传递的参数 * @param anim 指定的动画农林 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @param addToBackStack 是否添加到用户操作栈中 * @return */public final Fragment openPage(String pageName, Bundle bundle, int[] anim, boolean addToBackStack) {return this.openPage(pageName, bundle, anim, addToBackStack, false);}/** * 打开一个fragment并设置是否新开activity,设置是否添加返回栈 * @param pageName Fragemnt 名,在page.json中配置。 * @param bundle 页面跳转时传递的参数 * @param anim 指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @param addToBackStack 是否添加到用户操作栈中 * @param newActivity 该页面是否新建一个Activity * @return */public final Fragment openPage(String pageName, Bundle bundle, int[] anim, boolean addToBackStack, boolean newActivity) {if (pageName == null) {Log.d(TAG, "pageName is null");return null;}CoreSwitcher coreSwitcher = this.getSwitcher();if (coreSwitcher != null) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, anim, addToBackStack, newActivity);return coreSwitcher.openPage(page);} else {Log.d(TAG, "pageSwitcher is null");return null;}}/** * 在当前activity中打开一个fragment,并添加到返回栈中 * * @param pageName Fragemnt 名,在page.json中配置。 * @param bundle页面跳转时传递的参数 * @param anim 指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @return */public final Fragment openPage(String pageName, Bundle bundle, int[] anim) {return this.openPage(pageName, bundle, anim, true);}/** * 在当前activity中打开一个fragment,并设置是否添加到返回栈 * * @param pageNameFragemnt 名,在page.json中配置。 * @param bundle 页面跳转时传递的参数 * @param coreAnim指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @param addToBackStack 是否添加到用户操作栈中 * @return */public final Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack) {return this.openPage(pageName, bundle, CoreSwitchBean.convertAnimations(coreAnim), addToBackStack, false);}/** * 打开一个fragment并设置是否新开activity,设置是否添加返回栈 * @param pageName Fragemnt 名,在page.json中配置。 * @param bundle 页面跳转时传递的参数 * @param coreAnim 指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @param addToBackStack 是否添加到用户操作栈中 * @param newActivity 该页面是否新建一个Activity * @return */public final Fragment openPage(String pageName, Bundle bundle, CoreAnim coreAnim, boolean addToBackStack, boolean newActivity) {return this.openPage(pageName, bundle, CoreSwitchBean.convertAnimations(coreAnim), addToBackStack, newActivity);}/** * @param pageName * @param bundle * @param coreAnim * @return */public Fragment gotoPage(String pageName, Bundle bundle, CoreAnim coreAnim) {return this.gotoPage(pageName, bundle, coreAnim,false);}/** * 新建或跳转到一个页面(Fragment)。找不到pageName Fragment时,就新建Fragment。找到pageName * Fragment时,则弹出该Fragement到栈顶上的所有actvity和fragment * * @param pageNameFragemnt 名,在在configure.zip 的pageContext.txt中配置。 * @param bundle 页面跳转时传递的参数 * @param coreAnim指定的动画理性 none/slide(左右平移)/present(由下向上)/fade(fade 动画) * @param newActivity 该页面是否新建一个Activity * @return */public Fragment gotoPage(String pageName, Bundle bundle, CoreAnim coreAnim, boolean newActivity) {CoreSwitcher pageCoreSwitcher = this.getSwitcher();if (pageCoreSwitcher != null) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, coreAnim, true, newActivity);return pageCoreSwitcher.gotoPage(page);} else {Log.d(TAG, "pageSwitcher is null");return null;}}/** * 打开fragment并请求获得返回值 * @param pageName * @param bundle * @param coreAnim * @param requestCode 请求码 * @return */public final Fragment openPageForResult(String pageName, Bundle bundle, CoreAnim coreAnim, int requestCode) {return this.openPageForResult(false, pageName, bundle, coreAnim, requestCode);}/** * 打开fragment并请求获得返回值,并设置是否在新activity中打开 * @param newActivity * @param pageName * @param bundle * @param coreAnim * @param requestCode * @return */public final Fragment openPageForResult(boolean newActivity, String pageName, Bundle bundle, CoreAnim coreAnim, int requestCode) {CoreSwitcher pageCoreSwitcher = this.getSwitcher();if (pageCoreSwitcher != null) {CoreSwitchBean page = new CoreSwitchBean(pageName, bundle, coreAnim, true, newActivity);page.setRequestCode(requestCode);return pageCoreSwitcher.openPageForResult(page, this);} else {Log.d(TAG, "pageSwitcher is null");return null;}}@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);mActivity = activity;}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (getPageName() != null) {Log.d(TAG, "====Fragment.onCreate====" + getPageName());}}public String getPageName() {return mPageName;}public void setPageName(String pageName) {mPageName = pageName;}@Overridepublic void onDetach() {super.onDetach();mActivity = null;}//页面跳转接口public interface OnFragmentFinishListener {void onFragmentResult(int requestCode, int resultCode, Intent intent);}}其实无论BaseActivity还是BaseFragment的原理都是一样的,都是通过接口中的函数进行切换,最终都是调用了我们前面所说的两个核心函数。所谓的难点,其实就是openPageForResult的函数。如果调整函数中指定了新开activity,则直接调用startActivityForResult函数进行跳转,目标Activity中为BaseActivity,传递一些参数用于识别。Intent intent = new Intent(this, BaseActivity.class);intent.putExtra("SwitchBean", page);intent.putExtra("startActivityForResult", "true");然后再onCreate中获得intent
Intent mNewIntent = getIntent(); init(mNewIntent);调用了init函数,在里面获得传递的两个参数,如果是startActivityForResult,则对fragment设置回调函数,当我们手动设置了setFragmentResult函数后回调就会被调用,即onFragmentResult函数回调
private void init(Intent mNewIntent) {try {CoreSwitchBean page = mNewIntent.getParcelableExtra("SwitchBean");String startActivityForResult = mNewIntent.getStringExtra("startActivityForResult");this.mFirstCoreSwitchBean = page;if (page != null) {BaseFragment fragment = null;boolean addToBackStack = page.isAddToBackStack();String pageName = page.getPageName();Bundle bundle = page.getBundle();fragment = (BaseFragment) CorePageManager.getInstance().openPageWithNewFragmentManager(getSupportFragmentManager(), pageName, bundle, null, addToBackStack);if (fragment != null) {if ("true".equalsIgnoreCase(startActivityForResult)) {fragment.setRequestCode(page.getRequestCode());fragment.setFragmentFinishListener(new BaseFragment.OnFragmentFinishListener() {@Overridepublic void onFragmentResult(int requestCode, int resultCode, Intent intent) {BaseActivity.this.setResult(resultCode, intent);}});}} else {this.finish();}}} catch (Exception e) {e.printStackTrace();Log.d(TAG, e.getMessage());this.finish();}}最后的最后,也就是整个Fragment跳转框架的初始化了,继承Application编写一个应用程序类完成初始化。public class BaseApplication extends Application {private static LocalBroadcastManager mLocalBroadcatManager;private static Context mContext;private static BaseApplication instance;public static Context getContext() {return mContext;}@Overridepublic void onCreate() {super.onCreate();instance = this;mContext = this.getApplicationContext();CorePageManager.getInstance().init(this);}/** * 发送本地广播退出程序 */public void exitApp() {Intent intent = new Intent();intent.setAction(Config.ACTION_EXIT_APP);intent.addCategory(Intent.CATEGORY_DEFAULT);BaseApplication.getLocalBroadcastManager().sendBroadcast(intent);BaseActivity.unInit();}public static LocalBroadcastManager getLocalBroadcastManager() {if (mLocalBroadcatManager == null) {mLocalBroadcatManager = LocalBroadcastManager.getInstance(mContext);}return mLocalBroadcatManager;}}完成声明<manifestpackage="cn.edu.zafu.corepage"xmlns:android="http://schemas.android.com/apk/res/android"><application android:allowBackup="true" android:label="@string/app_name"><activityandroid:name="cn.edu.zafu.corepage.base.BaseActivity"android:configChanges="keyboardHidden|orientation|screenSize"android:exported="false"android:launchMode="standard"android:screenOrientation="portrait"android:theme="@style/BaseActivityTheme"android:windowSoftInputMode="adjustUnspecified|stateHidden" ></activity></application></manifest>之后的一切就会变得特别简单,调用即可。由于我是用android studio建的module,因此直接引用该module即可,然后提供一个程序入口Activity,该类继承BaseActivity,将该Activity声明在manifest文件中,然后我们再也不用新建Activity了,后续的页面跳转全都使用Fragment来完成。并且可以设置动画类型等一系列的参数。
openPage("test1",null, CoreAnim.slide);//打开一个页面,不传递参数第二个传null,第三个参数为动画类型,此方法有重载方法,第四个参数表示是否添加到返回栈,第五个参数表示是否新开activity,一般情况下,只需传递前三个参数即可,而动画类型,处理传递枚举类,还支持自定义的动画,对应的文件参考res/anim目录下的相应文件openPageForResult("test2",bundle,CoreAnim.fade,requestCode);//打开一个页面并获得返回结果,之后调用setFragmentResult和popToBack设置结果 setFragmentResult(500, intent); popToBack();重写onFragmentResult函数获取返回结果@Overridepublic void onFragmentResult(int requestCode, int resultCode, Intent data) {}//这个使用过程同startActivityFor的整个过程效果图:
以上就是本文的全部内容,希望对大家的学习有所帮助。