最近又要开始找工作了,准备把私藏了四年…的库给大家,别问我为啥现在才,因为鄙人比较懒(自己偷笑了一下)但是哥们在生活中是个很勤快的人。其实对于程序猿来说懒也是一种优点,但是必备的条件是要面子,两者缺一不可。为啥呢因为懒人都不喜欢重复性的复制与粘贴,所以会去抽取公共的代码,慢慢形成框架。另外为啥还需要要面子呢?因为要面子的人交付给别人的代码一定会自检查许多遍, 交出去的东西一定是当时他能做到的最好的。好了开始了… 要使用本库只需要复制ReusingActivityHelper.java ReusingActivity.java 代码,在manifest.xml配置 代码下载地址:还没来得及更新到github上,等更新了 通知大家 链接:https://pan.baidu.com/s/1oIWisHCGOHbp_ojfXW0-4g 真的开始了~~~~~~ 2.创建三个布局文件 接下来,我们把AndroidManifest.xml中CActivity的标签删除然后启动它: 然后开奖了… android.content.ActivityNotFoundException: Unable to find explicit activity class {com.project.reusingactivity/com.project.reusingactivity.CActivity}; have you declared this activity in your AndroidManifest.xml? 如果大家是工作了三年以上的猴子,看到上面的错误都会楞一下,然后会心一笑吧… 先坑你们一下,在老项目中使用需要把activity转成fragment。体力活…如上面的三个activity 然后 启动三个界面的代码 我们先看一下startFragment()中调用的ReusingActivityHelper.builder(this) 方法 上面方法创建了一个IntentBuilder,并调用了IntentBuilder 的create()方法 是不是发现点了啥~~~~~在 create() 中,我们创建一个intent对象并设置了我们要启动的activity是ReusingActivity,另外还创建了两个bundle对象,其中所有配置信息都会存放在 args中,在build()中extra也会被放入args中。 先不要慌~~~~ 很简单的 接下来我们看一下setFragment()方法,这个方法很关键 这个方法我们往args中添加了FRAGMENT_NAME这是我们要启动的fragment的类全路径,FRAGMENT_TAG,FRAGMENT_ARGU是传递给启动fragment的参数(比如:上个页面选中条目的id) 下面几个方法功能一样,都是把参数存放到extra中 另外有一个addIntentFlags(int flags)方法需要注意一下 通过上面方法我们set完配置信息后,调用build()方法返回intent 我们在返过去看看startFragment()方法,最终我们还是调用的startActivity(intent); startActivity(intentBuilder.setFragment(fragmentClass,null).build()); 看到上面的源码你们是不是舒了一口气,在Manifest.xml中配置ReusingActivity的标签 我们先分析一下isSingleFragmentIntent()方法 这个方法就是检查,我们是不是设置了SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM,为了防止其它页面直接启动ReusingActivity,而不是通过ReusingActivityHelper.IntentBuilder()。 其中SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM的值是在ReusingActivityHelper.IntentBuilde.build()方法设置的 helper = new ReusingActivityHelper(this); 逻辑比较简单 ReusingActivityHelper(ReusingActivity activity) { 关键代码来了 helper.ensureFragment(); 我们看一下ensureFragment()方法 调用了ensureFragmentInternal(Bundle param) 在上面方法中,我们设置了我们要显示的界面的layoutId(比如:activity_main),以及我们要显示的fragment显示在layoutId布局中那个view中containerId ,fragment最终显示代码在addFragmentByTag()中,我们看一下 是不是很简单~~~~argument是什么呢? 前面已经提到它是传递给要显示fragment的参数,我们看一下Fragment.instantiate(mActivity, clazz, argument);方法就明白了 看到 f.setArguments(args); 代码没,这下明白了吧,我们可以在fragment中 调用getArguments();获取到,比如: 好了,接下来我们看剩下的1000行代码 优点: 缺点: 好了~~~完事了
<!--用来展示界面内容的activity,因为我们要复用,所以不能配置启动模式--> <activity android:name="com.reusing.lib.ReusingActivity"/>
此库从2015年就开始使用,已经在7个项目使用,稳定性能够保证,而其此库代码逻辑并不难,很容易理解
提取码:3srn如果app有三个界面之前我们大概会这样做吧
public class AActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); } }
public class BActivity extends AppCompatActivity { ... }
public class CActivity extends AppCompatActivity { ... }
3.在AndroidManifest.xml中配置这三个activity的标签
上面这三个步骤是大家经常做的事,第三步是重复性最高,又非常重要让人很烦的东西,为什么呢,因为忘记配置第三步,那么恭喜你中奖了,而其android studio在编译的时候并不会告诉你忘记配置了。 startActivity(new Intent(getApplication(), CActivity.class));
接下来让我们只需要在manifest.xml配置一个activity来优化它。看到这里你估计心里在想吹牛…我们先看看库效果
public class AFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.activity_a, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Bundle arguments = getArguments(); if (arguments != null) { TextView tv = view.findViewById(R.id.tv_content); tv.setText(arguments.getString("content")); } } }
我们删除mainfest.xml中的A、B、C三个activity的标签,然后配置ReusingActivity 的标签,mainfest.xml内容大概像这样:<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="com.project.reusingactivity"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <!--启动页--> <activity android:name=".SplashActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!--用来展示界面内容的activity,因为我们要复用,所以不能配置启动模式--> <activity android:name="com.reusing.lib.ReusingActivity"/> </application> </manifest>
public class SplashActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.tv_to_a_activity).setOnClickListener(v -> { ReusingActivityHelper.IntentBuilder intentBuilder = ReusingActivityHelper.builder(this); if (intentBuilder == null) { return; } //设置SoftInputMode intentBuilder.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); intentBuilder.setWindowFeature(Window.FEATURE_NO_TITLE); Bundle bundle = new Bundle(); bundle.putString("content","从父界面传递过来的数据"); super.startActivity(intentBuilder.setFragment(AFragment.class, bundle).build()); //设置activity转场动画 SplashActivity.this.overridePendingTransition(R.anim.activity_in, R.anim.activity_out); }); findViewById(R.id.tv_to_b_activity).setOnClickListener(v -> { startFragment(BFragment.class); }); findViewById(R.id.tv_to_c_activity).setOnClickListener(v -> { startFragment(CFragment.class); }); } private void startFragment(Class<? extends Fragment> fragmentClass) { ReusingActivityHelper.IntentBuilder intentBuilder = ReusingActivityHelper.builder(this); startActivity(intentBuilder.setFragment(fragmentClass,null).build()); } }
ok了,我们运行一下试试
我们点击一下AActivity试试,ok跳转成功,界面显示成功
我们先分析一下startFragment()方法
private void startFragment(Class<? extends Fragment> fragmentClass) { ReusingActivityHelper.IntentBuilder intentBuilder = ReusingActivityHelper.builder(this); startActivity(intentBuilder.setFragment(fragmentClass,null).build()); }
public static IntentBuilder builder(Context context) { IntentBuilder b = new IntentBuilder(); return b.create(context, ReusingActivity.class); }
public IntentBuilder create(Context context,Class<? extends Activity> clazz) { intent = new Intent(context, clazz);//clazz 就是上个方法传入的ReusingActivity.class args = new Bundle(); extra = new Bundle(); return this; }
接下来我们看一下库源码,源码就两个文件
ReusingActivityHelper.java
public class ReusingActivityHelper { private static final String SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM = "SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM"; private static final String FRAGMENT_NAME = "fragment_name"; private static final String FRAGMENT_TAG = "fragment_tag"; /** * 指定上个页面传递的数据 */ private static final String FRAGMENT_ARGU = "fragment_argu"; public static final String EXTRA = "extra"; /** * 指定layout资源,为0或不传,使用DecorView 主题不同 内容不同 */ public static final String EXTRA_PARAM_LAYOUT = "layout"; /** * 指定fragment的container id,不传,使用android.R.id.content */ public static final String EXTRA_PARAM_CONTAINER = "container"; /** * 指定activity 启动的window feature参数 */ public static final String EXTRA_PARAM_WINDOW_FEATURE = "window_feature"; /** * 指定activity 启动的window frag参数 */ public static final String EXTRA_PARAM_WINDOW_FLAGS = "window_flags"; /** * 制定activity windowSoftInputMode */ public static final String EXTRA_SOFT_INPUT_MODE = "soft_input_mode"; Fragment mFragment; ReusingActivity mActivity; ReusingActivityHelper(ReusingActivity activity) { mActivity = activity; } /** * 设置window feature参数 */ void requestWindowFeature() { if (!isSingleFragmentIntent(mActivity)) { return; } Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); Bundle extraParam = param.getBundle(EXTRA); if (extraParam != null && extraParam.containsKey(EXTRA_PARAM_WINDOW_FEATURE)) { int windowFeature = extraParam == null ? Window.FEATURE_ACTION_BAR : extraParam.getInt(EXTRA_PARAM_WINDOW_FEATURE, Window.FEATURE_ACTION_BAR); mActivity.requestWindowFeature(windowFeature); if(windowFeature == Window.FEATURE_NO_TITLE && mActivity.getSupportActionBar()!=null){ mActivity.getSupportActionBar().hide();// 隐藏ActionBar } } } /** * 设置 setSoftInputMode */ public void setSoftInputMode() { if (!isSingleFragmentIntent(mActivity)) { return; } Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); Bundle extraParam = param.getBundle(EXTRA); if (extraParam != null && extraParam.containsKey(EXTRA_SOFT_INPUT_MODE)) { int softInputMode = extraParam.getInt(EXTRA_SOFT_INPUT_MODE); try { mActivity.getWindow().setSoftInputMode(softInputMode); } catch (Exception e) { e.printStackTrace(); } } } /** * 设置window frag参数 */ void setWindowFlags() { if (!isSingleFragmentIntent(mActivity)) { return; } Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); Bundle extraParam = param.getBundle(EXTRA); if (extraParam.containsKey(EXTRA_PARAM_WINDOW_FLAGS)) { mActivity.getWindow().addFlags(extraParam.getInt(EXTRA_PARAM_WINDOW_FLAGS)); } } /** * 初始化fragment */ Fragment ensureFragment() { Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); if (param == null) { return null; } return ensureFragmentInternal(param); } public String getFragmentSimpleName() { Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); if (param == null) { return null; } return param.getString(FRAGMENT_TAG); } /** * 初始化fragment * * @param param */ private Fragment ensureFragmentInternal(Bundle param) { Bundle extraParam = param.getBundle(EXTRA); // 设置activity layout int layoutId = extraParam == null ? 0 : extraParam.getInt( EXTRA_PARAM_LAYOUT, 0); if (layoutId != 0) { /* 如果我们在intentBuild中设置了layoutId就会调用setContentView(layoutId) 其实调用setContentView(layoutId) 只是把layoutId布局添加到DecorView的android.R.id.content中 */ mActivity.setContentView(layoutId); } String fragmentTag = param.getString(FRAGMENT_TAG); mFragment = mActivity.getSupportFragmentManager() .findFragmentByTag(fragmentTag); if (mFragment == null) {//看看我们是不是已经在fragmentManager中添加了要显示的fragment,防止重复添加 // 初始化fragment String fragmentName = param.getString(FRAGMENT_NAME); Bundle argu = param.getBundle(FRAGMENT_ARGU); // 设置fragment container id int containerId = layoutId == 0 || extraParam == null ? 0 : extraParam.getInt(EXTRA_PARAM_CONTAINER, 0); //如果我们没设置layoutId则不生效 if (containerId != 0) { //如果我们在intentBuild中设值layoutId 和 containerId 我们把fragment内容显示到containerId中 mFragment = addFragmentByTag(containerId, fragmentName, fragmentTag, argu);//argu是上个页面传递给显示的fragment参数 } else {//如果没有containerId 把fragment内容显示到android.R.id.content中 mFragment = addFragmentByTag(android.R.id.content, fragmentName, fragmentTag, argu);//argu是上个页面传递给显示的fragment参数 } } return mFragment; } private Fragment addFragmentByTag(int container, String clazz, String tag, Bundle argument) { FragmentManager fm = mActivity.getSupportFragmentManager(); Fragment f = fm.findFragmentByTag(tag); if (f == null) { FragmentTransaction ft = fm.beginTransaction(); f = Fragment.instantiate(mActivity, clazz, argument); if (container == 0) { ft.add(f, tag); } else { ft.add(container, f, tag); } ft.commitAllowingStateLoss(); } else if (f.isDetached()) { FragmentTransaction ft = fm.beginTransaction(); ft.attach(f); ft.commitAllowingStateLoss(); } return f; } static boolean isSingleFragmentIntent(Activity activity) { Bundle param = activity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); return param != null; } public static IntentBuilder builder(Context context) { IntentBuilder b = new IntentBuilder(); return b.create(context, ReusingActivity.class); } public static IntentBuilder builder(Context context, Class<? extends ReusingActivity> claz) { IntentBuilder b = new IntentBuilder(); return b.create(context, claz); } public static IntentBuilder builder(Fragment fragment) { if (fragment == null || fragment.getActivity() == null) { return null; } return builder(fragment.getActivity()); } public static class IntentBuilder { private Intent intent; private Bundle args; private Bundle extra; private IntentBuilder() { } private IntentBuilder create(Context context, Class<? extends Activity> clazz) { intent = new Intent(context, clazz); args = new Bundle(); extra = new Bundle(); return this; } public IntentBuilder setFragment(Class<? extends Fragment> fragment, Bundle args4fragment) { args.putString(FRAGMENT_NAME, fragment.getName()); args.putString(FRAGMENT_TAG, fragment.getSimpleName()); args.putBundle(FRAGMENT_ARGU, args4fragment); return this; } public IntentBuilder setFragment(String fragmentName, String fragmentTag, Bundle args4fragment) { args.putString(FRAGMENT_NAME, fragmentName); args.putString(FRAGMENT_TAG, fragmentTag); args.putBundle(FRAGMENT_ARGU, args4fragment); return this; } public IntentBuilder setExtra(Bundle extra) { this.extra.putAll(extra); return this; } /** * 设置我们要显示的布局id */ public IntentBuilder setLayoutId(int layoutId) { extra.putInt(EXTRA_PARAM_LAYOUT, layoutId); return this; } /** * 设置我们要显示的fragment 显示在LayoutId中那个容器里 */ public IntentBuilder setContainerId(int containerId) { extra.putInt(EXTRA_PARAM_CONTAINER, containerId); return this; } public IntentBuilder setWindowFlag(int windowFlag) { extra.putInt(EXTRA_PARAM_WINDOW_FLAGS, windowFlag); return this; } public IntentBuilder addIntentFlags(int flags) { intent.addFlags(flags); return this; } public IntentBuilder setWindowFeature(int windowFeature) { extra.putInt(EXTRA_PARAM_WINDOW_FEATURE, windowFeature); return this; } public IntentBuilder setSoftInputMode(int softInputMode) { extra.putInt(EXTRA_SOFT_INPUT_MODE, softInputMode); return this; } public Intent build() { args.putBundle(EXTRA, extra); intent.putExtra(SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM, args); return intent; } } }
我们先看一下 ReusingActivityHelper 的静态内部类 IntentBuilder , 刚才我们分析了在create()中,我们创建了三个对象intent、args、extra并存到成员变量中,其中intent设置了我们要启动的ReusingActivity public IntentBuilder setFragment(Class<? extends Fragment> fragment, Bundle args4fragment) { args.putString(FRAGMENT_NAME, fragment.getName()); args.putString(FRAGMENT_TAG, fragment.getSimpleName()); args.putBundle(FRAGMENT_ARGU, args4fragment); return this; }
setWindowFeature(int windowFeature)
setWindowFlag(int windowFlag)
setLayoutId(int layoutId)
setContainerId(int containerId)
setSoftInputMode(int softInputMode) public IntentBuilder setContainerId(int containerId) { extra.putInt(EXTRA_PARAM_CONTAINER, containerId); return this; }
public IntentBuilder addIntentFlags(int flags) { intent.addFlags(flags); return this; }
public Intent build() { args.putBundle(EXTRA, extra);//extra被放入到args中 //把所有信息放入到SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM中 intent.putExtra(SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM, args); return intent; }
接下来我们看一下ReusingActivity.java 我们需要在manifest.xml中配置activity
public class ReusingActivity extends AppCompatActivity { private ReusingActivityHelper helper; @Override protected void onCreate(Bundle savedInstanceState) { if (ReusingActivityHelper.isSingleFragmentIntent(this)) { helper = new ReusingActivityHelper(this); } if (helper != null) { //这三个方法是让我们设置的值生效,我们就不做分析了,自己看一下就可以了 helper.requestWindowFeature(); helper.setWindowFlags(); helper.setSoftInputMode(); } super.onCreate(savedInstanceState); if (helper != null) { //显示界面内容 helper.ensureFragment(); } } @Override protected void onDestroy() { super.onDestroy(); helper = null; } }
<!--用来展示界面内容的activity,因为我们要复用,所以不能配置启动模式--> <activity android:name="com.reusing.lib.ReusingActivity"/>
static boolean isSingleFragmentIntent(Activity activity) { Bundle param = activity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); return param != null; }
mActivity = activity;
} Fragment ensureFragment() { Bundle param = mActivity.getIntent().getBundleExtra( SINGLE_FRAGMENT_ACTIVITY_START_ME_PARAM); if (param == null) { return null; } return ensureFragmentInternal(param); }
private Fragment ensureFragmentInternal(Bundle param) { Bundle extraParam = param.getBundle(EXTRA); // 设置activity layout int layoutId = extraParam == null ? 0 : extraParam.getInt( EXTRA_PARAM_LAYOUT, 0); if (layoutId != 0) { /* 如果我们在intentBuild中设置了layoutId就会调用setContentView(layoutId) 其实调用setContentView(layoutId) 只是把layoutId布局添加到DecorView的android.R.id.content中 */ mActivity.setContentView(layoutId); } String fragmentTag = param.getString(FRAGMENT_TAG); mFragment = mActivity.getSupportFragmentManager() .findFragmentByTag(fragmentTag); if (mFragment == null) {//看看我们是不是已经在fragmentManager中添加了要显示的fragment,防止重复添加 // 初始化fragment String fragmentName = param.getString(FRAGMENT_NAME); Bundle argu = param.getBundle(FRAGMENT_ARGU); // 设置fragment container id int containerId = layoutId == 0 || extraParam == null ? 0 : extraParam.getInt(EXTRA_PARAM_CONTAINER, 0); //如果我们没设置layoutId则不生效 if (containerId != 0) { //如果我们在intentBuild中设值layoutId 和 containerId 我们把fragment内容显示到containerId中 mFragment = addFragmentByTag(containerId, fragmentName, fragmentTag, argu);//argu是上个页面传递给显示的fragment参数 } else {//如果没有containerId 把fragment内容显示到android.R.id.content中 mFragment = addFragmentByTag(android.R.id.content, fragmentName, fragmentTag, argu);//argu是上个页面传递给显示的fragment参数 } } return mFragment; }
private Fragment addFragmentByTag(int container, String clazz, String tag, Bundle argument) { FragmentManager fm = mActivity.getSupportFragmentManager(); Fragment f = fm.findFragmentByTag(tag); if (f == null) { FragmentTransaction ft = fm.beginTransaction(); f = Fragment.instantiate(mActivity, clazz, argument); if (container == 0) { ft.add(f, tag); } else { ft.add(container, f, tag); } ft.commitAllowingStateLoss(); } else if (f.isDetached()) { FragmentTransaction ft = fm.beginTransaction(); ft.attach(f); ft.commitAllowingStateLoss(); } return f; }
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) { .... Class<?> clazz = (Class)sClassMap.get(fname); if (clazz == null) { clazz = context.getClassLoader().loadClass(fname); sClassMap.put(fname, clazz); } Fragment f = (Fragment)clazz.getConstructor().newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.setArguments(args); } .... }
public class BFragment extends Fragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { Bundle arguments = getArguments(); return inflater.inflate(R.layout.activity_b,container,false); } }
别慌~~没了 哈哈总结:用这种方式有什么优点和缺点呢?
1、我们不需要每写一个页面就需要在manifest中配置相应的标签了
2、如果多个页面部分内容相同(比如好几个页面的列表相同),因为我们所有页面都是基于fragment实现的,所以直接可以复用,activity不行滴~~~
你有没用发现activity四大启动模式挂了~~~~~
不过呢 我们可以自定义一个fragment启动栈来实现,对不
这时,你可能又要问了,singleInstance 怎么办,这时我们可以用ReusingActivity的子类
另外我们可能需要拦截activity finish事件 我们可以这样做,让fragment实现一个接口,重写ReusingActivity的onBackPressed()、finish() @Override public void onBackPressed() { if (helper != null && helper.mFragment != null && helper.mFragment instanceof OnInterceptListener) { OnInterceptListener onInterceptListener = (OnInterceptListener) helper.mFragment; if (onInterceptListener.interceptOnBackPressed()) {//如果fragment不拦截 return; } } super.onBackPressed(); } @Override public void finish() { if (helper != null && helper.mFragment != null && helper.mFragment instanceof OnInterceptListener) { OnInterceptListener onInterceptListener = (OnInterceptListener) helper.mFragment; if (onInterceptListener.interceptOnFinish()) { return; } } super.finish(); }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算