Android使用Fragment打造万能页面切换框架
首先我们来回顾一下传统用Activity进行的页面切换。activity之间切换。首先须要新建intent对象,给该对象设置一些必须的參数,然后调用startActivity方法进行页面跳转。
假设须要activity返回结果。则调用startActivityForResult方法。在onActivityResult方法中获得返回结果。此外,每个要展示的activity须要在AndroidManifest.xml文件里注冊。
而且,假设在某些特定的情况下(比方65536方法数爆炸)要动态载入dex,还得手动管理activity的生命周期。那么。有没有这么一种方法进行页面切换时,无需在AndroidManifest.xml文件里声明这些信息,动态载入时又无需我们管理生命周期。等等长处呢。
我们来回顾一下。在android3.0之后,谷歌出了一个Fragment,这个东西依赖于activity,其生命周期由宿主activity进行管理,而且能够通过FragmentManager和FragmentTransaction等相关的类进行管理。
那么我们能不能从Fragment入手。打造一个全然由Fragment组成的页面跳转框架呢。
使用Fragment事实上非常easy。首先开启一个事务。通过add,replace,remove等方法进行加入,替换。移除等操作,这一切的操作可能须要依赖一个容器。这个容器提供一个id,进行相应操作时将这个id作为參数传入。之后通过相应方法提交事务就能够了,就像这样子。
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
然而我相信你一定有这种经历。在使用Fragment进行页面切换时又得不断用代码控制其显示与隐藏的逻辑,那么有没有这样一种方法在程序中不断复用这段代码呢?
首先,我们希望Fragment能像Activity那样,进行正确的跳转。那么须要什么。答案是Fragment对象。我们肯定须要它的Class全类名,当然跳转的时候可能会带上一些參数,这个參数应该通过Bundle进行传递。
而且,全类名可能太长,不便记忆。我们參考web的架构,应该还要取一个别名alias。
就这样。一个Fragment页面的三个基本属性就被我们抽取出来了。组成了例如以下的实体类。
在这个实体类中,页面传递的參数为json形式的String字符串对象,在须要使用的时候我们通过该json构造出bundle。页面名变量mName是整个程序唯一标示该页面的參数,其值唯一。可是其相应的class全类名能够不唯一。也就是说从name到class的映射能够一对多。
public class CorePage implements Serializable {
private static final long serialVersionUID = 3736359137726536495L;
private String mName;
//页面名
private String mClazz;
//页面class
private 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;
}
@Override
public 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文件夹下,当然你也能够放在其它文件夹下,仅仅有你能读取到就可以,甚至你能够放在压缩包里。然而,实际情况下,这个文件不应该暴露。因为一旦暴露就存在风险。
因此,大家能够採用更安全的方式存这些数据。比方把数据压缩到压缩包中。添加一个password,而读取文件的内容的代码我们移到native中取实现,毕竟java层太easy被反编译了,而c/c++层相对来说会毕竟有难度。
这里为了简单,我们临时放在assets文件夹下,那么要从assets文件夹中读取这个文件内容就必须有这么一个读取该文件夹下文件的函数。该文件夹在android中也算是一个比較特殊的文件夹了,能够通过getAssets()函数。然后获得一个输入流,将文件内容读出,然后将相应的json解析出来就能够了。
/**
* 从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。我们对其应用单例模式。
/**
* 跳转页面管理
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:34
*/
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方法中就可以。
到这里为止,基本上我们一切已经就绪了。就差怎样切换了。
这里。在CorePageManager类中再提供两个核心函数,用于处理页面切换。
以下这个函数是页面切换的核心函数。首先依据參数从map中拿到相应的实体类。假设存在这个页面,通过class名用反射获得该Fragment对象,调用前面写好的创建Bundle的函数得到页面參数。并与当前函数中的入參bundle进行合并。
将參数设置给fragment对象,开启一个fragment事务,查找id为fragment_container的fragment容器,假设该容器已经有fragment,则隐藏它,假设该函数传递了动画參数,则加入页面切换动画,然后将反射获得的fragment对象加入到该容器中。假设须要加入到返回栈。则调用addToBackStack,最后提交事务并返回该fragment对象。
整个函数非常easy,就是我们寻常在activity中写的切换fragment的代码
/**
* 页面跳转核心函数之中的一个
* 打开一个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;
/**
* 页面切换动画类别
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:42
*/
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" />
到了这里,假设你都明确了,那么后面基本上就没有什么难度了,因为之后的功能都是基于以上内容。
前面我们定义了一个CorePage实体类用于保存配置文件里实体类的信息,而页面切换过程中须要传递一些參数。比方是否加入到fragment返回栈,是否在新的activity中打开fragment,页面切换时的动画,传递的參数等等,通样,我们将其封装为实体类。因为该对象可能须要通过intent传递。这里我们将事实上现Parcelable接口。
实现该接口方法非常easy。假设使用的是android studio,使用快捷键alt+insert选择Parcelable就可以创建一个模板,我们将其补齐就好了。整个类例如以下,我们对外提供了多个重载的构造函数。其本质都是一样的,而前面的动画转换函数我们将其放入这个类中。
/**
* 页面跳转控制參数
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:34
*/
public class CoreSwitchBean implements Parcelable {
public static final Parcelable.Creator<CoreSwitchBean> CREATOR = new Parcelable.Creator<CoreSwitchBean>() {
@Override
public CoreSwitchBean createFromParcel(Parcel in) {
return new CoreSwitchBean(in);
}
@Override
public 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;
//是否起新的Activity
private 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;
}
@Override
public String toString() {
return "SwitchBean{" +
"mPageName='" + mPageName + '\'' +
", mBundle=" + mBundle +
", mAnim=" + Arrays.toString(mAnim) +
", mAddToBackStack=" + mAddToBackStack +
", mNewActivity=" + mNewActivity +
", requestCode=" + requestCode +
'}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public 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实现该接口,用于切换时的一些经常使用操作。fragment中调用宿主activity中该接口的方法就可以。
/**
* 页面跳转接口,用于控制页面跳转或启动新的activity
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:34
*/
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;
//线程安全的handler
private WeakReference<BaseActivity> mCurrentInstance = null;
//当前activity的引用
/**
* 弹出页面
*/
@Override
public 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() {
@Override
public void run() {
getSupportFragmentManager().popBackStackImmediate();
}
});
}
} else {
finishActivity(this, true);
}
}
/**
* 是否是主线程
* @return
*/
private boolean isMainThread() {
return Thread.currentThread() == this.getMainLooper().getThread();
}
/**
* 是否位于栈顶
* @param fragmentTag
* @return
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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() {
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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
*/
@Override
public 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() {
@Override
public 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
*/
@Override
protected 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() {
@Override
public 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,否则父类处理
*/
@Override
public void onBackPressed() {
if (this.getSupportFragmentManager().getBackStackEntryCount() == 1) {
this.finishActivity(this, true);
} else {
super.onBackPressed();
}
}
/**
* 假设fragment中处理了则fragment处理否则activity处理
* @param keyCode
* @param event
* @return
*/
@Override
public 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的跳转
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:32
*/
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 的fragment
private int mFragmentRequestCode = -1;
//请求码,必须大于等于0
/**
* 仅用于接受应用退出广播。程序退出时有机会做一些必要的清理工作
*/
private BroadcastReceiver mExitReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Config.ACTION_EXIT_APP)) {
Log.d(TAG,"exit from broadcast");
finish();
}
}
};
@Override
public 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());
//获得主线程handler
mCurrentInstance = 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;
//所在activity
private String mPageName;
//页面名
private int mRequestCode;
//用于startForResult的requestCode
private 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 不为null
if (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 pageName Fragemnt 名。在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 pageName Fragemnt 名,在在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;
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}
@Override
public 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;
}
@Override
public 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() {
@Override
public 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编写一个应用程序类完毕初始化。
/**
*
* User:lizhangqu(513163535@qq.com)
* Date:2015-07-22
* Time: 09:35
*/
public class BaseApplication extends Application {
private static LocalBroadcastManager mLocalBroadcatManager;
private static Context mContext;
private static BaseApplication instance;
public static Context getContext() {
return mContext;
}
@Override
public 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;
}
}
完毕声明
<manifest
package="cn.edu.zafu.corepage"
xmlns:android="http://schemas.android.com/apk/res/android">
<application android:allowBackup="true"
android:label="@string/app_name"
>
<activity
android: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来完毕。而且能够设置动画类型等一系列的參数。
使用非常easy
openPage("test1",null, CoreAnim.slide);
//打开一个页面,不传递參数第二个传null,第三个參数为动画类型。此方法有重载方法,第四个參数表示是否加入到返回栈,第五个參数表示是否新开activity。普通情况下,仅仅需传递前三个參数就可以,而动画类型,处理传递枚举类,还支持自己定义的动画,相应的文件參考res/anim文件夹下的相应文件
openPageForResult("test2",bundle,CoreAnim.fade,requestCode);
//打开一个页面并获得返回结果。之后调用setFragmentResult和popToBack设置结果
setFragmentResult(500, intent);
popToBack();
重写onFragmentResult函数获取返回结果
@Override
public void onFragmentResult(int requestCode, int resultCode, Intent data) {
}
//这个使用过程同startActivityFor的整个过程。
来一张例子动图。
项目代码,肯定有bug,欢迎fork改动