Repository: senonwx/WanAndroid Branch: master Commit: 548831d6c068 Files: 230 Total size: 550.5 KB Directory structure: gitextract_lw_97uwb/ ├── .gitignore ├── .idea/ │ └── encodings.xml ├── README.md ├── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── xfhmoudel/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── xfhmoudel/ │ │ │ ├── App.java │ │ │ ├── FragmentHomeActivity.java │ │ │ ├── SplashActivity.java │ │ │ └── TestActivity.java │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── ic_launcher_background.xml │ │ │ └── shape_splash_timer.xml │ │ ├── layout/ │ │ │ ├── activity_fragment_home.xml │ │ │ ├── activity_splash.xml │ │ │ └── activity_test.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── xfhmoudel/ │ └── ExampleUnitTest.java ├── build.gradle ├── dependencies.gradle ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── lib_common/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── lib_common/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── lib_common/ │ │ │ ├── AppConfig.java │ │ │ ├── ComUtil.java │ │ │ ├── ConstantArouter.java │ │ │ ├── ConstantLoginArouter.java │ │ │ ├── adapter/ │ │ │ │ ├── CommonAdapter.java │ │ │ │ ├── CommonHolder.java │ │ │ │ ├── RecycleHolder.java │ │ │ │ └── RecyclerAdapter.java │ │ │ ├── api/ │ │ │ │ └── BaseApi.java │ │ │ ├── base/ │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseAppDeletage.java │ │ │ │ ├── BaseApplication.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BaseLazyFragment.java │ │ │ │ ├── BaseNestingLazyFragment.java │ │ │ │ ├── BasePresenter.java │ │ │ │ ├── BaseResponse.java │ │ │ │ └── BaseViewImp.java │ │ │ ├── bean/ │ │ │ │ ├── Banner.java │ │ │ │ ├── CollectionArticle.java │ │ │ │ ├── HomeArticle.java │ │ │ │ ├── KnowledgeSysArticle.java │ │ │ │ ├── KnowledgeSystem.java │ │ │ │ ├── Login.java │ │ │ │ ├── ProjectArticle.java │ │ │ │ ├── WXarticle.java │ │ │ │ └── WXchapters.java │ │ │ ├── common/ │ │ │ │ ├── contract/ │ │ │ │ │ ├── LoginContract.java │ │ │ │ │ └── WebviewContract.java │ │ │ │ ├── presenter/ │ │ │ │ │ ├── LoginPresenter.java │ │ │ │ │ └── WebviewPresenter.java │ │ │ │ └── ui/ │ │ │ │ ├── Common_LoginActivity.java │ │ │ │ ├── Common_RegisterActivity.java │ │ │ │ └── Common_WebviewActivity.java │ │ │ ├── net/ │ │ │ │ ├── RequestInterceptor.java │ │ │ │ ├── ServerUtils.java │ │ │ │ ├── callback/ │ │ │ │ │ ├── ErrorListener.java │ │ │ │ │ ├── RequestCallback.java │ │ │ │ │ └── RxErrorHandler.java │ │ │ │ ├── cookies/ │ │ │ │ │ ├── CookiesManager.java │ │ │ │ │ ├── OkHttpCookies.java │ │ │ │ │ └── PersistentCookieStore.java │ │ │ │ └── progress/ │ │ │ │ ├── ProgressCancelListener.java │ │ │ │ └── ProgressDialogHandler.java │ │ │ ├── service/ │ │ │ │ └── InitializeService.java │ │ │ └── utils/ │ │ │ ├── ACache.java │ │ │ ├── BaseEvent.java │ │ │ ├── ConstantUtils.java │ │ │ ├── LogUtils.java │ │ │ ├── MD5Utils.java │ │ │ ├── PreferenceTool.java │ │ │ ├── RetryWithDelay.java │ │ │ ├── RxUtils.java │ │ │ ├── StatusBarUtils.java │ │ │ └── ToastUtil.java │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── register_border.xml │ │ │ ├── register_border_2.xml │ │ │ ├── register_border_9.xml │ │ │ ├── shape_gradient.xml │ │ │ ├── style_progress_bar.xml │ │ │ └── toast_shape.xml │ │ ├── layout/ │ │ │ ├── activity_common__login.xml │ │ │ ├── activity_common__register.xml │ │ │ ├── activity_common__webview.xml │ │ │ ├── layout_fragmhome_tab.xml │ │ │ ├── layout_toolbar.xml │ │ │ └── toast_layout.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── lib_common/ │ └── ExampleUnitTest.java ├── lib_opensource/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── lib_opensource/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ └── AndroidManifest.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── lib_opensource/ │ └── ExampleUnitTest.java ├── module_art/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── module_art/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── module_art/ │ │ │ ├── App_Art.java │ │ │ ├── MainActivity.java │ │ │ ├── SplashActivity.java │ │ │ ├── adapter/ │ │ │ │ └── ArtMainAdapter.java │ │ │ ├── contract/ │ │ │ │ └── ArtMainFragmentCon.java │ │ │ ├── fragment/ │ │ │ │ └── ArtMainFragment.java │ │ │ └── presenter/ │ │ │ └── ArtMainFragmentPre.java │ │ ├── release/ │ │ │ └── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── art_launcher_background.xml │ │ │ ├── art_shape_transp_con20.xml │ │ │ ├── art_shape_white_con30.xml │ │ │ └── art_shape_yellow_con20.xml │ │ ├── layout/ │ │ │ ├── art_activity_main.xml │ │ │ ├── art_activity_splash.xml │ │ │ ├── art_adapter_artmain_fragment_article.xml │ │ │ ├── art_adapter_artmain_fragment_head.xml │ │ │ ├── art_adapter_artmain_fragment_head_item.xml │ │ │ └── art_fragment_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── module_art/ │ └── ExampleUnitTest.java ├── module_home/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── module_home/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── module_home/ │ │ │ ├── App_Home.java │ │ │ ├── MainActivity.java │ │ │ ├── SplashActivity.java │ │ │ ├── activity/ │ │ │ │ ├── HomeArticleActivity.java │ │ │ │ └── HomeProjectActivity.java │ │ │ ├── adapter/ │ │ │ │ └── HomeMainAdapter.java │ │ │ ├── contract/ │ │ │ │ ├── HomeArticleActivityCon.java │ │ │ │ ├── HomeMainFragmentCon.java │ │ │ │ └── HomeProjectActivityCon.java │ │ │ ├── fragment/ │ │ │ │ └── HomeMainFragment.java │ │ │ └── presenter/ │ │ │ ├── HomeArticleActivityPre.java │ │ │ ├── HomeMainFragmentPre.java │ │ │ └── HomeProjectActivityPre.java │ │ ├── release/ │ │ │ └── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── home_ic_launcher_background.xml │ │ │ ├── home_shape_stro_red_con30.xml │ │ │ └── home_shape_white_con30.xml │ │ ├── layout/ │ │ │ ├── home_activity_home_article.xml │ │ │ ├── home_activity_home_project.xml │ │ │ ├── home_activity_main.xml │ │ │ ├── home_activity_splash.xml │ │ │ ├── home_adapter_homemain_fragment_article.xml │ │ │ ├── home_adapter_homemain_fragment_banneritem.xml │ │ │ ├── home_adapter_homemain_fragment_head.xml │ │ │ ├── home_adapter_homemain_fragment_project.xml │ │ │ └── home_fragment_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── module_home/ │ └── ExampleUnitTest.java ├── module_life/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── module_life/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── module_life/ │ │ │ ├── App_Life.java │ │ │ ├── MainActivity.java │ │ │ ├── SplashActivity.java │ │ │ ├── activity/ │ │ │ │ └── KnowledgeSystemActivity.java │ │ │ ├── contract/ │ │ │ │ ├── KnowledgeSysActivityCon.java │ │ │ │ └── LifeMainFragmentCon.java │ │ │ ├── fragment/ │ │ │ │ └── LifeMainFragment.java │ │ │ └── presenter/ │ │ │ ├── KnowledgeSysActivityPre.java │ │ │ └── LifeMainFragmentPre.java │ │ ├── release/ │ │ │ └── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── life_ic_launcher_background.xml │ │ │ ├── life_shape_gray_10.xml │ │ │ └── life_shape_white_con30.xml │ │ ├── layout/ │ │ │ ├── life_activity_home_article.xml │ │ │ ├── life_activity_main.xml │ │ │ ├── life_activity_splash.xml │ │ │ ├── life_adapter_knowledgesys_item.xml │ │ │ ├── life_adapter_lifemain_flowlayout_item.xml │ │ │ ├── life_adapter_lifemain_fragment.xml │ │ │ └── life_fragment_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── module_life/ │ └── ExampleUnitTest.java ├── module_talent/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── senon/ │ │ └── module_talent/ │ │ └── ExampleInstrumentedTest.java │ ├── main/ │ │ ├── debug/ │ │ │ └── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── senon/ │ │ │ └── module_talent/ │ │ │ ├── App_Talent.java │ │ │ ├── MainActivity.java │ │ │ ├── activity/ │ │ │ │ ├── AboutActivity.java │ │ │ │ └── CollectionActivity.java │ │ │ ├── contract/ │ │ │ │ ├── CollectionActivityCon.java │ │ │ │ └── TalentMainFragmentCon.java │ │ │ ├── fragment/ │ │ │ │ └── TalentMainFragment.java │ │ │ └── presenter/ │ │ │ ├── CollectionActivityPre.java │ │ │ └── TalentMainFragmentPre.java │ │ ├── release/ │ │ │ └── AndroidManifest.xml │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── talent_ic_launcher_background.xml │ │ │ └── talent_shape_white_con30.xml │ │ ├── layout/ │ │ │ ├── talent_activity_about.xml │ │ │ ├── talent_activity_collection.xml │ │ │ ├── talent_activity_main.xml │ │ │ ├── talent_adapter_collection.xml │ │ │ └── talent_fragment_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test/ │ └── java/ │ └── com/ │ └── senon/ │ └── module_talent/ │ └── ExampleUnitTest.java ├── senon.jks └── settings.gradle ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ *.iml .gradle /local.properties /.idea/workspace.xml /.idea/libraries .DS_Store /build /captures .externalNativeBuild ================================================ FILE: .idea/encodings.xml ================================================ ================================================ FILE: README.md ================================================ # WanAndroid 玩安卓http://www.wanandroid.com/ 客户端模块化设计app,包含MVP+Retrofit+Rxjava+Rxlifecycle+Glide+Eventbus+ARouter. 构建一个平面化、简而美的玩安卓app客户端。

如果不清楚如何将Android工程模块化,请看Android模块化使用 # API app采用玩安卓开放api # 主要功能 首页:Banner
首页:最新博文(5条)、最新项目(5条)
体系:一级二级下面全部博文
公众号:所有公众号列表
公众号:某公众号下所有博文
个人中心:登录、退出、收藏、清除缓存
# 屏幕截图



# 子模块打包 工程采用的是模块化,如果想要单独跑或者打包各个子模块,那么请将gradle.properties改为
isBuildModule=true

如果需要整体打包app,则
isBuildModule=false
# 三方轮子 Rxjava
RxAndroid
Retrofit
Okhttp
ARouter
Glide
EventBus
FlowLayout
MZBannerView
AndroidAutoSize
HTextView
CircleImageView
LRecyclerView
Sweetalertdialog
Awesome-WanAndroid
# APK下载
因为图方便,apk资源是放在leancloud上的,微信扫码下载不了,用手机浏览器扫码可下载。 # 版本

V 1.0.1

1.修复各模块清单文件合并问题

V 1.0.0

1.第一版 # Thanks 感谢以上所有开源框架。项目用于学习交流,如果你觉得本项目好,谢谢star哦! ================================================ FILE: app/.gitignore ================================================ /build ================================================ FILE: app/build.gradle ================================================ apply plugin: 'com.android.application' android { signingConfigs { config { keyAlias 'senon' keyPassword '123456' storeFile file('../senon.jks') storePassword '123456' } } compileSdkVersion rootProject.ext.android["compileSdkVersion"] defaultConfig { applicationId "com.senon.xfhmoudel" minSdkVersion rootProject.ext.android["minSdkVersion"] targetSdkVersion rootProject.ext.android["targetSdkVersion"] versionCode rootProject.ext.android["versionCode"] versionName rootProject.ext.android["versionName"] testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true arguments = [AROUTER_MODULE_NAME: project.getName()] } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' signingConfig signingConfigs.config } } aaptOptions { cruncherEnabled = false } lintOptions { checkReleaseBuilds false abortOnError false } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support.constraint:constraint-layout:1.1.3' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' testImplementation rootProject.ext.dependencies["junit"] if (isBuildModule.toBoolean()) { implementation project(':lib_common') } else { implementation project(':module_home') implementation project(':module_life') implementation project(':module_art') implementation project(':module_talent') } annotationProcessor rootProject.ext.dependencies["butterknife-compiler"] annotationProcessor rootProject.ext.dependencies["router-compiler"] api rootProject.ext.dependencies["htextview-base"] api rootProject.ext.dependencies["htextview-fall"] } ================================================ FILE: app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: app/src/androidTest/java/com/senon/xfhmoudel/ExampleInstrumentedTest.java ================================================ package com.senon.xfhmoudel; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.senon.xfhmoudel", appContext.getPackageName()); } } ================================================ FILE: app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: app/src/main/java/com/senon/xfhmoudel/App.java ================================================ package com.senon.xfhmoudel; import com.alibaba.android.arouter.launcher.ARouter; import com.senon.lib_common.base.BaseApplication; import com.senon.lib_common.utils.ConstantUtils; /** * 工程Application */ public class App extends BaseApplication { @Override public void onCreate() { super.onCreate(); initARouter(); } private void initARouter() { if (ConstantUtils.isAppDebug()) { //开启InstantRun之后,一定要在ARouter.init之前调用openDebug ARouter.openDebug(); ARouter.openLog(); } ARouter.init(this); } } ================================================ FILE: app/src/main/java/com/senon/xfhmoudel/FragmentHomeActivity.java ================================================ package com.senon.xfhmoudel; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.TypedValue; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Route; import com.senon.lib_common.ComUtil; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.utils.StatusBarUtils; import com.senon.lib_common.utils.ToastUtil; import com.senon.module_art.fragment.ArtMainFragment; import com.senon.module_home.fragment.HomeMainFragment; import com.senon.module_life.fragment.LifeMainFragment; import com.senon.module_talent.fragment.TalentMainFragment; import java.util.ArrayList; import java.util.List; /** * App主页 */ @Route(path = ConstantArouter.PATH_APP_FRAGMENTHOMEACTIVITY) public class FragmentHomeActivity extends AppCompatActivity { private ViewPager viewPager; private TabLayout tabs; private FragmentManager fragmentManager;//声明fragment管理 private List fragmentList = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StatusBarUtils.with(this).init(); setContentView(R.layout.activity_fragment_home); ComUtil.changeStatusBarTextColor(this,true); viewPager = findViewById(R.id.vp); tabs = findViewById(R.id.tabs); initVp$Tab(); } private void initVp$Tab() { fragmentList.add(new HomeMainFragment()); fragmentList.add(new LifeMainFragment()); fragmentList.add(new ArtMainFragment()); fragmentList.add(new TalentMainFragment()); fragmentManager = getSupportFragmentManager(); FragmentPagerAdapter pagerAdapter = new MyFragmentPagerAdapter(fragmentManager); viewPager.setAdapter(pagerAdapter); viewPager.setOffscreenPageLimit(fragmentList.size()); tabs.setupWithViewPager(viewPager);//将TabLayout和ViewPager关联起来。 tabs.setTabsFromPagerAdapter(pagerAdapter);//给Tabs设置适配器 for (int i = 0; i < tabs.getTabCount(); i++) { TabLayout.Tab tab = tabs.getTabAt(i); if (tab != null) { tab.setCustomView(getTabView(i)); View view = tab.getCustomView(); if(i == 0){ setTextColor(view,0,true); } } } tabs.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { @Override public void onTabSelected(TabLayout.Tab tab) { //在这里可以设置选中状态下 tab字体显示样式 View view = tab.getCustomView(); setTextColor(view,tab.getPosition(),true); } @Override public void onTabUnselected(TabLayout.Tab tab) { View view = tab.getCustomView(); setTextColor(view,tab.getPosition(),false); } @Override public void onTabReselected(TabLayout.Tab tab) { } }); } private String[] titles = {"首页","体系","公众号","我的"}; private int[] colors = {R.color.login_bg_end_1,R.color.tablayout_tv_gray}; private int[] mipmaps = {R.mipmap.ic_tabbar_discover,R.mipmap.ic_tabbar_mainframe,R.mipmap.ic_tabbar_order,R.mipmap.ic_tabbar_me}; private int[] mipmaphls = {R.mipmap.ic_tabbar_discoverhl,R.mipmap.ic_tabbar_mainframehl,R.mipmap.ic_tabbar_orderhl,R.mipmap.ic_tabbar_mehl}; private View getTabView(int curPos) { View view = LayoutInflater.from(this).inflate(R.layout.layout_fragmhome_tab, null); ImageView igv = (ImageView) view.findViewById(R.id.tab_item_igv); TextView tv = (TextView) view.findViewById(R.id.tab_item_tv); tv.setText(titles[curPos]); igv.setImageResource(mipmaps[curPos]); setTextColor(tv,curPos,false); return view; } private void setTextColor(View view,int position,boolean select){ if (null != view && view instanceof RelativeLayout) { TextView tv = (TextView) view.findViewById(R.id.tab_item_tv); ImageView igv = (ImageView) view.findViewById(R.id.tab_item_igv); tv.setTextSize(TypedValue.COMPLEX_UNIT_MM,22); tv.setTextColor(ContextCompat.getColor(this,select ? colors[0] : colors[1])); igv.setImageResource(select ? mipmaphls[position] : mipmaps[position]); } } //记录用户首次点击返回键的时间 private long firstTime=0; @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: long secondTime = System.currentTimeMillis(); if (secondTime - firstTime > 2000) { ToastUtil.initToast("再按一次返回键退出程序"); firstTime = secondTime; return true; } else { System.exit(0); } break; } return super.onKeyUp(keyCode, event); } //FragmentPagerAdapter class MyFragmentPagerAdapter extends FragmentPagerAdapter { public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public int getCount() { return fragmentList.size(); } @Nullable @Override public CharSequence getPageTitle(int position) { return super.getPageTitle(position); } } } ================================================ FILE: app/src/main/java/com/senon/xfhmoudel/SplashActivity.java ================================================ package com.senon.xfhmoudel; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.hanks.htextview.base.HTextView; import com.senon.lib_common.ComUtil; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.utils.LogUtils; import com.senon.lib_common.utils.StatusBarUtils; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.Observer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Consumer; import io.reactivex.functions.Function; import io.reactivex.schedulers.Schedulers; /** * app 闪屏页 */ @Route(path = ConstantArouter.PATH_APP_SPLASHACTIVITY) public class SplashActivity extends AppCompatActivity { private final int count = 5;//count秒后跳过 private TextView version_tv,timmer_tv; private Disposable disposable; private HTextView anim_tv1, anim_tv2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StatusBarUtils.with(this).init(); setContentView(R.layout.activity_splash); ComUtil.changeStatusBarTextColor(this,true); version_tv = findViewById(R.id.version_tv); timmer_tv = findViewById(R.id.timmer_tv); anim_tv1 = findViewById(R.id.anim_tv1); anim_tv2 = findViewById(R.id.anim_tv2); try { version_tv.setText("版本 V" + getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); version_tv.setText(""); } timmer_tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if(disposable != null){ disposable.dispose(); } gotoMainAct(); } }); initTimer(); } private void initTimer() { Observable.interval(0, 1, TimeUnit.SECONDS)//设置0延迟,每隔一秒发送一条数据 .take(count+1) //设置发送count+1次 因为是count~0秒 .map(new Function() { @Override public Long apply(Long aLong) throws Exception { LogUtils.d("apply"+(count-aLong)); return count-aLong; //发送倒计时 } }) .doOnSubscribe(new Consumer() {// 观察者订阅时调用 @Override public void accept(Disposable disposable){ timmer_tv.setEnabled(true);//在发送数据的时候设置为可以跳过 timmer_tv.setVisibility(View.VISIBLE); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())//操作UI要在UI线程 .subscribe(new Observer() { @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onComplete() { LogUtils.d("onCompleted: "+System.currentTimeMillis()); timmer_tv.setEnabled(false); gotoMainAct(); } @Override public void onSubscribe(Disposable d) { timmer_tv.setText(count + " 跳过"); disposable = d; } @Override public void onNext(Long aLong) { //接受到一条就是会操作一次UI LogUtils.d("onNext: "+aLong); timmer_tv.setText(aLong + " 跳过"); initHTextView(aLong); } }); } private void initHTextView(Long aLong) { if(aLong == (2 * count / 3) + 1){//显示第一排文字的时间 anim_tv1.animateText("Talk is cheap."); }else if(aLong == count / 2 +1){//显示第二排文字的时间 anim_tv2.animateText("Show me the code!"); } } private void gotoMainAct(){ ARouter.getInstance().build(ConstantArouter.PATH_APP_FRAGMENTHOMEACTIVITY)//指定跳到那个页面 .navigation(); finish(); } @Override protected void onDestroy() { super.onDestroy(); if(disposable != null){ disposable.dispose(); } } } ================================================ FILE: app/src/main/java/com/senon/xfhmoudel/TestActivity.java ================================================ package com.senon.xfhmoudel; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.senon.lib_common.ComUtil; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.ConstantLoginArouter; import com.senon.lib_common.utils.StatusBarUtils; /** * app 模块主页面 */ @Route(path = ConstantLoginArouter.PATH_APP_MAINACTIVITY) public class TestActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); StatusBarUtils.with(this).init(); setContentView(R.layout.activity_test); ComUtil.changeStatusBarTextColor(this,true); } public void toA(View view){ // 1. 应用内简单的跳转(通过URL跳转在'进阶用法'中) // ARouter.getInstance().build(ConstantLoginArouter.PATH_FIRST_MAINACTIVITY).navigation(); // String curUrl = ConstantLoginArouter.getCurRouter(this.getClass().getSimpleName()); String curUrl = ConstantLoginArouter.getCurRouter(ConstantLoginArouter.PATH_HOME_MAINACTIVITY); ARouter.getInstance().build(ConstantLoginArouter.PATH_COMMON_LOGINACTIVITY)//指定跳到那个页面 .withString("targetUrl",ConstantArouter.PATH_APP_FRAGMENTHOMEACTIVITY)//传入目标页面路由地址 可以在指定页面跳入到目标页面 .navigation(); // Uri testUriMix = Uri.parse("router://com.senon.firstmoduel/firstmoduel/firstmainactivity"); // ARouter.getInstance().build(testUriMix) // .withString("key1", "value1") // .navigation(); } public void toB(View view){ ARouter.getInstance().build(ConstantArouter.PATH_APP_FRAGMENTHOMEACTIVITY) .navigation(); } } ================================================ FILE: app/src/main/res/drawable/ic_launcher_background.xml ================================================ ================================================ FILE: app/src/main/res/drawable/shape_splash_timer.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_fragment_home.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_splash.xml ================================================ ================================================ FILE: app/src/main/res/layout/activity_test.xml ================================================ ================================================ FILE: app/src/main/res/values/colors.xml ================================================ #3F51B5 #303F9F #FF4081 ================================================ FILE: app/src/main/res/values/strings.xml ================================================ 玩安卓 ================================================ FILE: app/src/main/res/values/styles.xml ================================================ ================================================ FILE: app/src/test/java/com/senon/xfhmoudel/ExampleUnitTest.java ================================================ package com.senon.xfhmoudel; import org.junit.Test; import static org.junit.Assert.*; /** * Example local unit test, which will execute on the development machine (host). * * @see Testing documentation */ public class ExampleUnitTest { @Test public void addition_isCorrect() throws Exception { assertEquals(4, 2 + 2); } } ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. apply from: "dependencies.gradle" buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { google() jcenter() maven { url "https://jitpack.io" } } } task clean(type: Delete) { delete rootProject.buildDir } ================================================ FILE: dependencies.gradle ================================================ def supportVersion = "27.1.1" def rxBindingVersion = "3.0.0-alpha1" def retrofitVersion = "2.4.0" def okHttpVersion = "3.11.0" def stethoVersion = "1.5.0" def butterKnifeVersion = "8.5.1" def daggerVersion = "2.8" def routerVersion = "0.2.3" def htextviewVersion = "0.1.6" project.ext { android = [ compileSdkVersion: 27, minSdkVersion : 19, targetSdkVersion : 27, versionCode : 2, versionName : "1.0.1" ] dependencies = [ //android-support "support-v4" : "com.android.support:support-v4:${supportVersion}", "appcompat-v7" : "com.android.support:appcompat-v7:${supportVersion}", "design" : "com.android.support:design:${supportVersion}", "recyclerview-v7" : "com.android.support:recyclerview-v7:${supportVersion}", "cardview-v7" : "com.android.support:cardview-v7:${supportVersion}", "constraint-layout" : "com.android.support.constraint:constraint-layout:1.1.3", //java8-support "stream" : "com.annimon:stream:1.0.8", //rx "rxjava" : "io.reactivex.rxjava2:rxjava:2.2.3", "rxandroid" : "io.reactivex.rxjava2:rxandroid:2.1.0", "rxlifecycle" : "com.trello.rxlifecycle2:rxlifecycle:2.2.1", "rxlifecycle-components" : "com.trello.rxlifecycle2:rxlifecycle-components:2.2.1", "rxbinding" : "com.jakewharton.rxbinding3:rxbinding-core:${rxBindingVersion}", "rxbinding-appcompat-v7" : "com.jakewharton.rxbinding3:rxbinding-appcompat:${rxBindingVersion}", "rxbinding-recyclerview-v7" : "com.jakewharton.rxbinding3:rxbinding-recyclerview:${rxBindingVersion}", //retrofit "retrofit" : "com.squareup.retrofit2:retrofit:${retrofitVersion}", "adapter-rxjava" : "com.squareup.retrofit2:adapter-rxjava2:${retrofitVersion}", "retrofit-converter" : "com.squareup.retrofit2:converter-scalars:${retrofitVersion}", "retrofit-converter-gson" : "com.squareup.retrofit2:converter-gson:${retrofitVersion}", //dagger "dagger" : "com.google.dagger:dagger:${daggerVersion}", "dagger-compiler" : "com.google.dagger:dagger-compiler:${daggerVersion}", //router // 替换成最新版本, 需要注意的是api // 要与compiler匹配使用,均使用最新版可以保证兼容 "router" : "com.alibaba:arouter-api:1.4.1", "router-compiler" : "com.alibaba:arouter-compiler:1.2.2", //butterKnife 子模块的libary与application转化 R 与R2文件转化(所以最好不用) //https://www.jianshu.com/p/1fa69ad55b0e "butterknife" : "com.jakewharton:butterknife:${butterKnifeVersion}", "butterknife-compiler" : "com.jakewharton:butterknife-compiler:${butterKnifeVersion}", //facebook "stetho" : "com.facebook.stetho:stetho:${stethoVersion}", "stetho-okhttp3" : "com.facebook.stetho:stetho-okhttp3:${stethoVersion}", //okHttp3 "okhttp3" : "com.squareup.okhttp3:okhttp:${okHttpVersion}", "okhttp3-logging-interceptor" : "com.squareup.okhttp3:logging-interceptor:${okHttpVersion}", //others "ormlite-android" : "com.j256.ormlite:ormlite-android:5.0", //test "junit" : "junit:junit:4.12", //sweet alert dialog "sweetalert" : "com.github.f0ris.sweetalert:library:1.5.1", // "sweetalert" : "cn.pedant.sweetalert:library:1.3", //autosize "autosize" : "me.jessyan:autosize:1.0.6", "lrecyclerview" : "com.github.jdsjlzx:LRecyclerView:1.4.3", "glide" : "com.github.bumptech.glide:glide:3.7.0", "eventbus" : "org.greenrobot:eventbus:3.1.1", "smartrefreshlayout" : "com.scwang.smartrefresh:SmartRefreshLayout:1.1.0-alpha-20", "bannerview" : "com.github.pinguo-zhouwei:MZBannerView:v2.0.2", "flowlayout" : "com.hyman:flowlayout-lib:1.1.2", "circleimageview" : "de.hdodenhof:circleimageview:2.2.0", //好看的字体动画 "htextview-base" : "com.hanks:htextview-base:${htextviewVersion}", "htextview-fall" : "com.hanks:htextview-fall:${htextviewVersion}", ] } ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ #Sat Nov 17 20:54:41 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip ================================================ FILE: gradle.properties ================================================ # Project-wide Gradle settings. # IDE (e.g. Android Studio) users: # Gradle settings configured through the IDE *will override* # any settings specified in this file. # For more details on how to configure your build environment visit # http://www.gradle.org/docs/current/userguide/build_environment.html # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true android.enableAapt2 = false; #release isBuildModule=false #ģ #isBuildModule=true ================================================ FILE: gradlew ================================================ #!/usr/bin/env bash ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS="" APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn ( ) { echo "$*" } die ( ) { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; esac # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin, switch paths to Windows format before running java if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=$((i+1)) done case $i in (0) set -- ;; (1) set -- "$args0" ;; (2) set -- "$args0" "$args1" ;; (3) set -- "$args0" "$args1" "$args2" ;; (4) set -- "$args0" "$args1" "$args2" "$args3" ;; (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules function splitJvmOpts() { JVM_OPTS=("$@") } eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" ================================================ FILE: gradlew.bat ================================================ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windowz variants if not "%OS%" == "Windows_NT" goto win9xME_args if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* goto execute :4NT_args @rem Get arguments from the 4NT Shell from JP Software set CMD_LINE_ARGS=%$ :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: lib_common/.gitignore ================================================ /build ================================================ FILE: lib_common/build.gradle ================================================ apply plugin: 'com.android.library' android { compileSdkVersion rootProject.ext.android["compileSdkVersion"] defaultConfig { minSdkVersion rootProject.ext.android["minSdkVersion"] targetSdkVersion rootProject.ext.android["targetSdkVersion"] versionCode rootProject.ext.android["versionCode"] versionName rootProject.ext.android["versionName"] testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" javaCompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support.constraint:constraint-layout:1.1.3' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' testImplementation rootProject.ext.dependencies["junit"] api project(':lib_opensource') annotationProcessor rootProject.ext.dependencies["router-compiler"] } ================================================ FILE: lib_common/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # You can control the set of applied configuration files using the # proguardFiles setting in build.gradle. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} # Uncomment this to preserve the line number information for # debugging stack traces. #-keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile ================================================ FILE: lib_common/src/androidTest/java/com/senon/lib_common/ExampleInstrumentedTest.java ================================================ package com.senon.lib_common; import android.content.Context; import android.support.test.InstrumentationRegistry; import android.support.test.runner.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; /** * Instrumented test, which will execute on an Android device. * * @see Testing documentation */ @RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { @Test public void useAppContext() throws Exception { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); assertEquals("com.senon.lib_common", appContext.getPackageName()); } } ================================================ FILE: lib_common/src/main/AndroidManifest.xml ================================================ ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/AppConfig.java ================================================ package com.senon.lib_common; import com.senon.lib_common.utils.ConstantUtils; /** * APP配置参数 */ public class AppConfig { public static final String BASE_URL = "https://www.wanandroid.com/"; public static final String PATH_DATA = ConstantUtils.getAPPContext().getCacheDir().getAbsolutePath()+"/"+"data"; public static final String PATH_CACHE = PATH_DATA+"/"+"Cache"; } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/ComUtil.java ================================================ package com.senon.lib_common; import android.app.Activity; import android.content.Context; import android.net.ConnectivityManager; import android.os.Build; import android.text.Editable; import android.text.TextWatcher; import android.util.DisplayMetrics; import android.view.View; import android.widget.EditText; import com.senon.lib_common.utils.ConstantUtils; import com.senon.lib_common.utils.MD5Utils; import com.senon.lib_common.utils.ToastUtil; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * ComUtil */ public class ComUtil { public static void changeStatusBarTextColor(Context context,boolean isBlack) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (isBlack) { //设置状态栏黑色字体 ((Activity)context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } else { //恢复状态栏白色字体 ((Activity)context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } } } public static boolean isNumeric(String str) { Pattern pattern = Pattern.compile("^1[3|4|5|7|8|9][0-9]{9}$"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } return true; } public static boolean isChinese(String str) { Pattern pattern = Pattern.compile("^[\\u4E00-\\u9FA5]+$"); Matcher isNum = pattern.matcher(str); if (!isNum.matches()) { return false; } return true; } //long型时间转换为字符串时间类型 public static String longToString(Object longTime, String timeFormat) { SimpleDateFormat formatter = new SimpleDateFormat(timeFormat == null ? "yyyy-MM-dd" : timeFormat); long time = 0; if (longTime instanceof Integer || longTime instanceof Long) { return formatter.format(longTime); } else if (longTime instanceof String) { return formatter.format(Long.valueOf((String) longTime)); } return "时间获取错误"; } //检查是否有可用网络 public static boolean isNetworkConnected() { ConnectivityManager connectivityManager = (ConnectivityManager) ConstantUtils.getAPPContext(). getSystemService(Context.CONNECTIVITY_SERVICE); assert connectivityManager != null; return connectivityManager.getActiveNetworkInfo() != null; } // 屏幕宽度(像素) public static int getScreenWidth(Context context) { DisplayMetrics metric = new DisplayMetrics(); ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metric); return metric.widthPixels; } public static int getScreenHeight(Context context) { DisplayMetrics metric = new DisplayMetrics(); ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(metric); return metric.heightPixels; } public static String getMd5Str(HashMap map) { StringBuffer sb = new StringBuffer(); Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); sb.append(entry.getValue().toString()); } return MD5Utils.getMd5(sb.toString() ); } public static HashMap getMd5Str(String[] keyArray, String[] valueArray) { HashMap map = new HashMap<>(); StringBuffer sb = new StringBuffer(); if (keyArray.length != valueArray.length) { ToastUtil.initToast("key value长度不对应"); } else { for (int i = 0; i < keyArray.length; i++) { map.put(keyArray[i], valueArray[i]); } for (int i = 0; i < valueArray.length; i++) { sb.append(valueArray[i]); } map.put("secret", MD5Utils.getMd5(sb.toString())); return map; } return null; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/ConstantArouter.java ================================================ package com.senon.lib_common; /** * 所有模块均依赖commonmoduel 所以路由跳转均写入本Constant方便调用 * 常量类 * 其中: 路由跳转命名统一用:path+模块名+Activity名 */ public class ConstantArouter { /** * App */ public static final String PATH_APP_SPLASHACTIVITY = "/app/SplashActivity"; public static final String PATH_APP_FRAGMENTHOMEACTIVITY = "/app/FragmentHomeActivity"; /** * home 主页 */ public static final String PATH_HOME_MAINACTIVITY = "/home/MainActivity"; public static final String PATH_HOME_HOMEARTICLEACTIVITY = "/home/HomeArticleActivity"; public static final String PATH_HOME_HOMEPROJECTACTIVITY = "/home/HomeProjectActivity"; /** * life 知识体系 */ public static final String PATH_LIFE_KNOWLEDGESYSTEMACTIVITY = "/life/KnowledgeSystemActivity"; /** * common */ public static final String PATH_COMMON_REGISTERACTIVITY = "/lib_common/CommonRegisterActivity"; public static final String PATH_COMMON_WEBVIEWCTIVITY = "/lib_common/CommonWebviewActivity"; /** * talent 个人中心 */ public static final String PATH_TALENT_COLLECTIONACTIVITY = "/talent/CollectionActivity"; public static final String PATH_TALENT_ABOUTACTIVITY = "/talent/AboutActivity"; } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/ConstantLoginArouter.java ================================================ package com.senon.lib_common; import java.util.HashMap; import java.util.Map; /** * 判断是某个模块登录的 */ public class ConstantLoginArouter { public static Map activityRouterMap = new HashMap<>(); //app主页 public static final String PATH_APP_MAINACTIVITY = "/app/MainActivity"; //home主页 public static final String PATH_HOME_MAINACTIVITY = "/home/HomeMainActivity"; //Life首页 public static final String PATH_LIFE_MAINACTIVITY = "/life/LifeMainActivity"; //Art首页 public static final String PATH_ART_MAINACTIVITY = "/art/ArtMainActivity"; //Talent首页 public static final String PATH_TALENT_MAINACTIVITY = "/talent/TalentMainActivity"; //登录 注册 public static final String PATH_COMMON_LOGINACTIVITY = "/lib_common/CommonLoginActivity"; static { activityRouterMap.put(getActivityName(PATH_APP_MAINACTIVITY), PATH_APP_MAINACTIVITY); activityRouterMap.put(getActivityName(PATH_HOME_MAINACTIVITY), PATH_HOME_MAINACTIVITY); activityRouterMap.put(getActivityName(PATH_LIFE_MAINACTIVITY), PATH_LIFE_MAINACTIVITY); activityRouterMap.put(getActivityName(PATH_ART_MAINACTIVITY), PATH_ART_MAINACTIVITY); activityRouterMap.put(getActivityName(PATH_TALENT_MAINACTIVITY), PATH_TALENT_MAINACTIVITY); activityRouterMap.put(getActivityName(PATH_COMMON_LOGINACTIVITY), PATH_COMMON_LOGINACTIVITY); } private static String getActivityName(String routerUrl) { int pos = routerUrl.lastIndexOf("/"); return routerUrl.substring(pos + 1); } public static String getCurRouter(String activityName) { return activityRouterMap.get(activityName); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/adapter/CommonAdapter.java ================================================ package com.senon.lib_common.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import java.util.List; public abstract class CommonAdapter extends BaseAdapter { protected LayoutInflater mInflater; protected Context mContext; protected List mDatas; protected final int mItemLayoutId; public CommonAdapter(Context context, List mDatas, int itemLayoutId) { mInflater = LayoutInflater.from(context); this.mContext = context; this.mDatas = mDatas; this.mItemLayoutId = itemLayoutId; } @Override public int getCount() { return mDatas.size(); } @Override public T getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { final CommonHolder viewHolder = getViewHolder(position, convertView, parent); convert(viewHolder, getItem(position),position); return viewHolder.getConvertView(); } public abstract void convert(CommonHolder helper, T item,int position); private CommonHolder getViewHolder(int position, View convertView, ViewGroup parent) { return CommonHolder.get(mContext, convertView, parent, mItemLayoutId, position); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/adapter/CommonHolder.java ================================================ package com.senon.lib_common.adapter; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Paint; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; import android.text.util.Linkify; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.widget.Checkable; import android.widget.GridView; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RatingBar; import android.widget.TextView; import com.bumptech.glide.Glide; public class CommonHolder { private final SparseArray mViews; private int mPosition; private View mConvertView; private Context mContext; private int mLayoutId; private CommonHolder(Context context, ViewGroup parent, int layoutId, int position) { this.mLayoutId = layoutId; this.mContext = context; this.mPosition = position; this.mViews = new SparseArray(); mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false); //setTag mConvertView.setTag(this); } /** * 拿到一个CommonHolder对象 * * @param context * @param convertView * @param parent * @param layoutId * @param position * @return */ public static CommonHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) { if (convertView == null) { return new CommonHolder(context, parent, layoutId, position); } return (CommonHolder) convertView.getTag(); } /** * 通过控件的Id获取对于的控件,如果没有则加入views * * @param viewId * @return */ public T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } public View getConvertView() { return mConvertView; } /** * 为TextView设置字符串 * * @param viewId * @param text * @return */ public CommonHolder setText(int viewId, String text) { TextView view = getView(viewId); view.setText(text); return this; } public String getText(int viewId) { TextView view = getView(viewId); return view.getText().toString().trim(); } public CommonHolder setEnabled(int viewId, boolean enabled) { View view = getView(viewId); view.setEnabled(enabled); return this; } public CommonHolder setSelected(int viewId, boolean selected) { View view = getView(viewId); view.setSelected(selected); return this; } /** * 为ImageView设置图片 * * @param viewId * @param drawableId * @return */ public CommonHolder setImageResource(int viewId, int drawableId) { ImageView view = getView(viewId); view.setImageResource(drawableId); return this; } /** * 为ImageView设置图片 * * @param viewId * @param bm * @return */ public CommonHolder setImageBitmap(int viewId, Bitmap bm) { ImageView view = getView(viewId); view.setImageBitmap(bm); return this; } public CommonHolder setColorFilter(int viewId, Integer colorFilter) { ImageView imageView = getView(viewId); if (colorFilter == null) imageView.setColorFilter(null); else imageView.setColorFilter(colorFilter); return this; } public CommonHolder setImageDrawable(int viewId, Drawable drawable) { ImageView view = getView(viewId); view.setImageDrawable(drawable); return this; } public CommonHolder setBackgroundColor(int viewId, int color) { View view = getView(viewId); view.setBackgroundColor(color); return this; } public CommonHolder setBackgroundRes(int viewId, int backgroundRes) { View view = getView(viewId); view.setBackgroundResource(backgroundRes); return this; } public CommonHolder setTextColor(int viewId, int textColor) { TextView view = getView(viewId); view.setTextColor(textColor); return this; } public CommonHolder setTextColorRes(int viewId, int textColorRes) { TextView view = getView(viewId); view.setTextColor(mContext.getResources().getColor(textColorRes)); return this; } @SuppressLint("NewApi") public CommonHolder setAlpha(int viewId, float value) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { getView(viewId).setAlpha(value); } else { // Pre-honeycomb hack to set Alpha value AlphaAnimation alpha = new AlphaAnimation(value, value); alpha.setDuration(0); alpha.setFillAfter(true); getView(viewId).startAnimation(alpha); } return this; } public CommonHolder setVisible(int viewId, int visible) { View view = getView(viewId); view.setVisibility(visible); return this; } public CommonHolder linkify(int viewId) { TextView view = getView(viewId); Linkify.addLinks(view, Linkify.ALL); return this; } public CommonHolder setTypeface(Typeface typeface, int... viewIds) { for (int viewId : viewIds) { TextView view = getView(viewId); view.setTypeface(typeface); view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); } return this; } public CommonHolder setProgress(int viewId, int progress) { ProgressBar view = getView(viewId); view.setProgress(progress); return this; } public CommonHolder setProgress(int viewId, int progress, int max) { ProgressBar view = getView(viewId); view.setMax(max); view.setProgress(progress); return this; } public CommonHolder setMax(int viewId, int max) { ProgressBar view = getView(viewId); view.setMax(max); return this; } public CommonHolder setRating(int viewId, float rating) { RatingBar view = getView(viewId); view.setRating(rating); return this; } public CommonHolder setRating(int viewId, float rating, int max) { RatingBar view = getView(viewId); view.setMax(max); view.setRating(rating); return this; } public CommonHolder setTag(int viewId, Object tag) { View view = getView(viewId); view.setTag(tag); return this; } public CommonHolder setTag(int viewId, int key, Object tag) { View view = getView(viewId); view.setTag(key, tag); return this; } public CommonHolder setChecked(int viewId, boolean checked) { Checkable view = (Checkable) getView(viewId); view.setChecked(checked); return this; } /** * 关于事件的 */ public CommonHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = getView(viewId); view.setOnClickListener(listener); return this; } public CommonHolder setOnTouchListener(int viewId, View.OnTouchListener listener) { View view = getView(viewId); view.setOnTouchListener(listener); return this; } public CommonHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) { View view = getView(viewId); view.setOnLongClickListener(listener); return this; } /** * 设置中划线 * * @return */ public void setStrikeThruText(int viewID) { TextView view = (TextView) getView(viewID); view.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG); } public int getPosition() { return mPosition; } public GridView setData(int viewId) { GridView gridView = getView(viewId); return gridView; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/adapter/RecycleHolder.java ================================================ package com.senon.lib_common.adapter; import android.app.Activity; import android.graphics.Bitmap; import android.support.v7.widget.RecyclerView; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.style.AbsoluteSizeSpan; import android.text.style.ForegroundColorSpan; import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.widget.Checkable; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; public class RecycleHolder extends RecyclerView.ViewHolder { /** * 用于存储当前item当中的View */ private SparseArray mViews; public RecycleHolder(View itemView) { super(itemView); mViews = new SparseArray(); } public T findView(int ViewId) { View view = mViews.get(ViewId); //集合中没有,则从item当中获取,并存入集合当中 if (view == null) { view = itemView.findViewById(ViewId); mViews.put(ViewId, view); } return (T) view; } public RecycleHolder setOnClickListener(int viewId, View.OnClickListener listener) { View view = findView(viewId); view.setOnClickListener(listener); return this; } public RecycleHolder setOnClickListener(int viewId,int viewId2 ,View.OnClickListener listener) { View view = findView(viewId); view.setOnClickListener(listener); View view2 = findView(viewId2); view2.setOnClickListener(listener); return this; } public RecycleHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) { View view = findView(viewId); view.setOnLongClickListener(listener); return this; } public RecycleHolder setOnLongClickListener(int viewId,int viewId2, View.OnLongClickListener listener) { View view = findView(viewId); view.setOnLongClickListener(listener); View view2 = findView(viewId2); view2.setOnLongClickListener(listener); return this; } public RecycleHolder setText(int viewId, String text) { TextView tv = findView(viewId); tv.setText(text); return this; } public RecycleHolder setText(int viewId, SpannableStringBuilder text) { TextView tv = findView(viewId); tv.setText(text); return this; } public RecycleHolder setMaxLine(int viewId, int lineCount) { TextView tv = findView(viewId); tv.setMaxLines(lineCount); return this; } public RecycleHolder setPadding(int viewId, int left, int top, int right, int bottom) { View tv = findView(viewId); tv.setPadding(left, top, right, bottom); return this; } public RecycleHolder setAppendTextColor(int viewId, CharSequence str, int resColorId, int resDimen) { TextView tv = findView(viewId); SpannableString spannableString = new SpannableString(str); spannableString.setSpan(new ForegroundColorSpan(tv.getContext().getResources().getColor(resColorId)), 0, str.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannableString.setSpan(new AbsoluteSizeSpan((int) tv.getContext().getResources().getDimension(resDimen)), 0, str.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); tv.append(spannableString); return this; } public RecycleHolder setSelected(int viewId, boolean selected) { View tv = findView(viewId); tv.setSelected(selected); return this; } public RecycleHolder setEnabled(int viewId, boolean enabled) { View tv = findView(viewId); tv.setEnabled(enabled); return this; } public RecycleHolder setEnabled_imgView(int viewId, boolean enabled) { ImageView tv = findView(viewId); tv.setEnabled(enabled); return this; } public RecycleHolder setText(int viewId, int text) { TextView tv = findView(viewId); tv.setText(text); return this; } public RecycleHolder setChecked(int viewId, boolean checked) { Checkable view = findView(viewId); view.setChecked(checked); return this; } public RecycleHolder setTextColor(int viewId, int colorResId) { TextView tv = findView(viewId); tv.setTextColor(tv.getContext().getResources().getColor(colorResId)); return this; } public RecycleHolder setImageResource(int viewId, int ImageId) { ImageView image = findView(viewId); image.setImageResource(ImageId); return this; } public RecycleHolder setLayoutParams(int viewId, ViewGroup.LayoutParams para) { View view = findView(viewId); view.setLayoutParams(para); return this; } public RecycleHolder setImageBitmap(int viewId, Bitmap bitmap) { ImageView image = findView(viewId); image.setImageBitmap(bitmap); return this; } public RecycleHolder setGlideImage(int viewId, String url,int placehodlerImg,Activity activity){ ImageView image = findView(viewId); Glide.with(activity) .load(url) .error(placehodlerImg) .placeholder(placehodlerImg) .into(image); return this; } public RecycleHolder setImageNet(int viewId, String url) { ImageView image = findView(viewId); //使用你所用的网络框架等 return this; } public RecycleHolder setBackgroundColor(int viewId, int color) { View view = findView(viewId); view.setBackgroundColor(color); return this; } public RecycleHolder setBackgroundRes(int viewId, int backgroundRes) { View view = findView(viewId); view.setBackgroundResource(backgroundRes); return this; } public RecycleHolder setVisible(int viewId, boolean visible) { View image = findView(viewId); image.setVisibility(visible ? View.VISIBLE : View.GONE); //使用你所用的网络框架等 return this; } public RecycleHolder setVisible_invisible(int viewId, boolean visible) { View image = findView(viewId); image.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); //使用你所用的网络框架等 return this; } public RecycleHolder setProgesss(int viewId, int percent) { ProgressBar progressBar = findView(viewId); progressBar.setProgress(percent); return this; } public boolean getVisible(int viewId) { View view = findView(viewId); return view.getVisibility() == View.VISIBLE; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/adapter/RecyclerAdapter.java ================================================ package com.senon.lib_common.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import java.util.List; public abstract class RecyclerAdapter extends RecyclerView.Adapter { private Context mContext; private List mDatas; private int mLayoutId; private LayoutInflater mInflater; private OnItemClickListener onItemClickListener; public RecyclerAdapter(Context mContext, List mDatas, int mLayoutId) { this.mContext = mContext; this.mDatas = mDatas; this.mLayoutId = mLayoutId; mInflater = LayoutInflater.from(mContext); } @Override public RecycleHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new RecycleHolder(mInflater.inflate(mLayoutId, parent, false)); } @Override public void onBindViewHolder(final RecycleHolder holder, int position) { convert(holder, mDatas.get(position), position); if (onItemClickListener != null) { //设置背景 holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //注意,这里的position不要用上面参数中的position,会出现位置错乱\ onItemClickListener.OnItemClickListener(holder.itemView, holder.getLayoutPosition()); } }); } } public abstract void convert(RecycleHolder holder, T data, int position); @Override public int getItemCount() { return mDatas.size(); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } public interface OnItemClickListener { void OnItemClickListener(View view, int position); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/api/BaseApi.java ================================================ package com.senon.lib_common.api; import com.senon.lib_common.bean.Banner; import com.senon.lib_common.bean.CollectionArticle; import com.senon.lib_common.bean.HomeArticle; import com.senon.lib_common.bean.KnowledgeSysArticle; import com.senon.lib_common.bean.KnowledgeSystem; import com.senon.lib_common.bean.Login; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.bean.ProjectArticle; import com.senon.lib_common.bean.WXarticle; import com.senon.lib_common.bean.WXchapters; import java.util.List; import java.util.Map; import io.reactivex.Observable; import retrofit2.http.Field; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Path; import retrofit2.http.Query; /** * 网络请求接口 */ public interface BaseApi { //登录 @POST("user/login") @FormUrlEncoded Observable> login(@FieldMap Map map); //登出 @GET("user/logout/json") Observable logout(); //注册 @POST("user/register") @FormUrlEncoded Observable> register(@FieldMap Map map); //首页banner @GET("banner/json") Observable>> banner(); //首页文章列表 @GET("article/list/{page}/json") Observable> getHomeArticle(@Path("page") int page); //首页最新项目 @GET("article/listproject/{page}/json") Observable> getHomeProject(@Path("page") int page); //项目列表数据 @GET("project/list/{page}/json") Observable> getProjectList(@Path("page") int page, @Query("cid") int cid); //体系数据 @GET("tree/json") Observable>> getKnowledgeList(); //知识体系下的文章 @GET("article/list/{page}/json") Observable> getKnowledgeArticle(@Path("page") int page, @Query("cid") int cid); //获取公众号列表 @GET("wxarticle/chapters/json") Observable>> getWXarticleChapters(); //查看某个公众号历史数据 @GET("wxarticle/list/{id}/{page}/json") Observable> getWXarticleList(@Path("id") int id, @Path("page") int page); //收藏站内文章 @POST("lg/collect/{id}/json") Observable getCollect(@Path("id") int id); //取消收藏-->文章列表 @POST("lg/uncollect_originId/{id}/json") Observable getUncollectOriginId(@Path("id") int id); //取消收藏-->我的收藏页面 @POST("lg/uncollect/{id}/json") Observable getUncollect(@Path("id") int id,@Query("originId") int originId); //收藏文章列表 @GET("lg/collect/list/{page}/json") Observable> getCollectList(@Path("page") int page); } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseActivity.java ================================================ package com.senon.lib_common.base; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.view.Window; import com.alibaba.android.arouter.launcher.ARouter; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; /** * 父类->基类->动态指定类型->泛型设计(通过泛型指定动态类型->由子类指定,父类只需要规定范围即可) */ public abstract class BaseActivity> extends RxAppCompatActivity { //引用V层和P层 private P presenter; private V view; public P getPresenter(){ return presenter; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(getLayoutId()); setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // 禁止所有的activity横屏 ARouter.getInstance().inject(this); if(presenter == null){ presenter = createPresenter(); } if(view == null){ view = createView(); } if(presenter != null && view != null){ presenter.attachView(view); } init(); } //由子类指定具体类型 public abstract int getLayoutId(); public abstract P createPresenter(); public abstract V createView(); public abstract void init(); @Override protected void onDestroy() { super.onDestroy(); if(presenter != null){ presenter.detachView(); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseAppDeletage.java ================================================ package com.senon.lib_common.base; import android.app.Application; import android.content.Context; import com.scwang.smartrefresh.layout.SmartRefreshLayout; import com.scwang.smartrefresh.layout.api.DefaultRefreshFooterCreator; import com.scwang.smartrefresh.layout.api.DefaultRefreshHeaderCreator; import com.scwang.smartrefresh.layout.api.RefreshFooter; import com.scwang.smartrefresh.layout.api.RefreshHeader; import com.scwang.smartrefresh.layout.api.RefreshLayout; import com.scwang.smartrefresh.layout.footer.ClassicsFooter; import com.scwang.smartrefresh.layout.header.ClassicsHeader; import com.senon.lib_common.R; import com.senon.lib_common.net.cookies.PersistentCookieStore; import com.senon.lib_common.service.InitializeService; import com.senon.lib_common.utils.ConstantUtils; import com.senon.lib_common.utils.LogUtils; import com.senon.lib_common.utils.PreferenceTool; import com.senon.lib_common.utils.ToastUtil; import me.jessyan.autosize.AutoSizeConfig; import me.jessyan.autosize.unit.Subunits; public class BaseAppDeletage { private Application mApplication; //static 代码段可以防止内存泄露 static { //设置全局的Header构建器 SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() { @Override public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { // 指定为经典Header,默认是 贝塞尔雷达Header return new ClassicsHeader(context); } }); //设置全局的Footer构建器 SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() { @Override public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) { //指定为经典Footer,默认是 BallPulseFooter return new ClassicsFooter(context).setDrawableSize(20); } }); } public BaseAppDeletage(Application application) { mApplication = application; } public void onCreate() { ConstantUtils.init(mApplication); //全局Utils LogUtils.setLogEnable(ConstantUtils.isAppDebug()); //Log日志 PreferenceTool.init(mApplication); //Preference参数 PersistentCookieStore.init(mApplication); //Cookies持久化Preference参数 ToastUtil.init(mApplication); //吐司初始化 initAutoSizeUnits(); //配置全局 布局适配单位mm InitializeService.start(mApplication); //初始化服务Service } private void initAutoSizeUnits() { AutoSizeConfig.getInstance().getUnitsManager() //支持dp适配 默认true .setSupportDP(false) //支持sp适配 默认true .setSupportSP(false) .setSupportSubunits(Subunits.MM); AutoSizeConfig.getInstance() //按照宽度适配 默认true .setBaseOnWidth(true) //是否让框架支持自定义 Fragment 的适配参数, 由于这个需求是比较少见的, 所以须要使用者手动开启 //如果没有这个需求建议不开启 .setCustomFragment(true); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseApplication.java ================================================ package com.senon.lib_common.base; import android.app.Application; /** * 要想使用BaseApplication,必须在组件中实现自己的Application,并且继承BaseApplication; * 组件模块中实现的Application必须在debug包中的AndroidManifest.xml中注册,否则无法使用; * 组件模块的Application需置于java/debug文件夹中,不得放于主代码; * 组件模块中获取Context的方法必须为:ConstantUtils.getAPPContext(),不允许其他写法; */ public class BaseApplication extends Application { @Override public void onCreate() { super.onCreate(); BaseAppDeletage baseAppDeletage = new BaseAppDeletage(this); baseAppDeletage.onCreate(); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseFragment.java ================================================ package com.senon.lib_common.base; import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.trello.rxlifecycle2.components.support.RxFragment; /** * 父类->基类->动态指定类型->泛型设计(通过泛型指定动态类型->由子类指定,父类只需要规定范围即可) */ public abstract class BaseFragment> extends RxFragment { //引用V层和P层 private P presenter; private V view; public Context mContext; public P getPresenter() { return presenter; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(getLayoutId(), container, false); mContext = getActivity(); if (presenter == null) { presenter = createPresenter(); } if (this.view == null) { this.view = createView(); } if (presenter != null && view != null) { presenter.attachView(this.view); } init(); return view; } //由子类指定具体类型 public abstract int getLayoutId(); public abstract P createPresenter(); public abstract V createView(); public abstract void init(); @Override public void onDestroyView() { super.onDestroyView(); if (presenter != null) { presenter.detachView(); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseLazyFragment.java ================================================ package com.senon.lib_common.base; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.senon.lib_common.utils.LogUtils; import com.trello.rxlifecycle2.components.support.RxFragment; /** * https://juejin.im/post/5adcb0e36fb9a07aa7673fbc * BaseLazyFragment 单fragment懒加载 * * * 生命周期执行的方法 如下: * 第一次生成页面-->可见 * setUserVisibleHint: ----->false * setUserVisibleHint: ----->true * onCreateView: -----> onCreateView * onStart: -----> onStart * onFragmentFirst: 首次可见 * onFragmentFirst: -----> 子fragment进行初始化操作 * onResume: -----> onResume * * 可见-->第一次隐藏: * onPause: -----> onPause * onFragmentInVisible: 不可见 * * 未销毁且不可见-->重新可见: * onStart: -----> onStart * onFragmentVisble: 可见 * onFragmentVisble: -----> 子fragment每次可见时的操作 * onResume: -----> onResume * * 可见-->销毁: * onPause: -----> onPause * onFragmentInVisible: 不可见 * onDestroyView: -----> onDestroyView * * 我们可以更具以上生命周期来操作不同的业务逻辑, * 请务必运行此module demo,观看打印日志来自定义逻辑。 */ public abstract class BaseLazyFragment> extends RxFragment { //引用V层和P层 private P presenter; private V view; public Context mContext; private View rootView; private boolean mIsFirstVisible = true;/*当前Fragment是否首次可见,默认是首次可见**/ private boolean isViewCreated = false;/*当前Fragment的View是否已经创建**/ private boolean currentVisibleState = false;/*当前Fragment的可见状态,一种当前可见,一种当前不可见**/ public P getPresenter() { return presenter; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { LogUtils.e("-----> onCreateView"); if(rootView == null){ rootView = inflater.inflate(getLayoutId(), container, false); mContext = getActivity(); if (presenter == null) { presenter = createPresenter(); } if (this.view == null) { this.view = createView(); } if (presenter != null && view != null) { presenter.attachView(this.view); } init(rootView); } isViewCreated=true;//在onCreateView执行完毕,将isViewCreated改为true; return rootView; } //由子类指定具体类型 public abstract int getLayoutId(); public abstract P createPresenter(); public abstract V createView(); public abstract void init(View rootView); @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); LogUtils.e("----->"+isVisibleToUser); if (isViewCreated) { //Fragment可见且状态不是可见(从一个Fragment切换到另外一个Fragment,后一个设置状态为可见) if (isVisibleToUser && !currentVisibleState) { disPatchFragment(true); } else if (!isVisibleToUser && currentVisibleState) { //Fragment不可见且状态是可见(从一个Fragment切换到另外一个Fragment,前一个更改状态为不可见) disPatchFragment(false); } } } @Override public void onStart() { super.onStart(); LogUtils.e("-----> onStart"); //isHidden()是Fragment是否处于隐藏状态和isVisible()有区别 //getUserVisibleHint(),Fragement是否可见 if(!isHidden()&& getUserVisibleHint()){//如果Fragment没有隐藏且可见 //执行分发的方法,三种结果对应自Fragment的三个回调,对应的操作,Fragment首次加载,可见,不可见 disPatchFragment(true); } } @Override public void onResume() { super.onResume(); LogUtils.e("-----> onResume"); if(!mIsFirstVisible){ //表示点击home键又返回操作,设置可见状态为ture if(!isHidden()&& !getUserVisibleHint() && currentVisibleState){ disPatchFragment(true); } } } @Override public void onPause() { super.onPause(); LogUtils.e("-----> onPause"); //表示点击home键,原来可见的Fragment要走该方法,更改Fragment的状态为不可见 if(!isHidden()&& getUserVisibleHint()){ disPatchFragment(false); } } @Override public void onDestroyView() { super.onDestroyView(); LogUtils.e("-----> onDestroyView"); //当 View 被销毁的时候我们需要重新设置 isViewCreated mIsFirstVisible 的状态 isViewCreated = false; mIsFirstVisible = true; if (presenter != null) { presenter.detachView(); } } /** * @param visible Fragment当前是否可见,然后调用相关方法 */ public void disPatchFragment(boolean visible){ currentVisibleState=visible; if(visible){//Fragment可见 if(mIsFirstVisible){//可见又是第一次 mIsFirstVisible=false;//改变首次可见的状态 onFragmentFirst(); }else{//可见但不是第一次 onFragmentVisble(); } }else {//不可见 onFragmentInVisible(); } } //Fragemnet首次可见的方法 public void onFragmentFirst(){ LogUtils.e("首次可见"); } //Fragemnet可见的方法 public void onFragmentVisble(){//子Fragment调用次方法,执行可见操作 LogUtils.e("可见"); } //Fragemnet不可见的方法 public void onFragmentInVisible(){ LogUtils.e("不可见"); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseNestingLazyFragment.java ================================================ package com.senon.lib_common.base; import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.senon.lib_common.utils.LogUtils; import com.trello.rxlifecycle2.components.support.RxFragment; import java.util.List; /** * https://juejin.im/post/5adcb0e36fb9a07aa7673fbc * * BaseNestingLazyFragment fragment嵌套fragment的懒加载父类 */ public abstract class BaseNestingLazyFragment> extends RxFragment { //引用V层和P层 private P presenter; private V view; public Context mContext; private View rootView; private boolean mIsFirstVisible = true;/*当前Fragment是否首次可见,默认是首次可见**/ private boolean isViewCreated = false;/*当前Fragment的View是否已经创建**/ private boolean currentVisibleState = false;/*当前Fragment的可见状态,一种当前可见,一种当前不可见**/ public P getPresenter() { return presenter; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { LogUtils.e("-----> onCreateView"); if (rootView == null) { rootView = inflater.inflate(getLayoutId(), container, false); mContext = getActivity(); if (presenter == null) { presenter = createPresenter(); } if (this.view == null) { this.view = createView(); } if (presenter != null && view != null) { presenter.attachView(this.view); } init(rootView); } isViewCreated = true;//在onCreateView执行完毕,将isViewCreated改为true; return rootView; } //由子类指定具体类型 public abstract int getLayoutId(); public abstract P createPresenter(); public abstract V createView(); public abstract void init(View rootView); @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); LogUtils.e("----->" + isVisibleToUser); if (isViewCreated) { //Fragment可见且状态不是可见(从一个Fragment切换到另外一个Fragment,后一个设置状态为可见) if (isVisibleToUser && !currentVisibleState) { disPatchFragment(true); } else if (!isVisibleToUser && currentVisibleState) { //Fragment不可见且状态是可见(从一个Fragment切换到另外一个Fragment,前一个更改状态为不可见) disPatchFragment(false); } } } @Override public void onStart() { super.onStart(); LogUtils.e("-----> onStart"); //isHidden()是Fragment是否处于隐藏状态和isVisible()有区别 //getUserVisibleHint(),Fragement是否可见 if (!isHidden() && getUserVisibleHint()) {//如果Fragment没有隐藏且可见 //执行分发的方法,三种结果对应自Fragment的三个回调,对应的操作,Fragment首次加载,可见,不可见 disPatchFragment(true); } } @Override public void onResume() { super.onResume(); LogUtils.e("-----> onResume"); if (!mIsFirstVisible) { //表示点击home键又返回操作,设置可见状态为ture if (!isHidden() && !getUserVisibleHint() && currentVisibleState) { disPatchFragment(true); } } } @Override public void onPause() { super.onPause(); LogUtils.e("-----> onPause"); //表示点击home键,原来可见的Fragment要走该方法,更改Fragment的状态为不可见 if (!isHidden() && getUserVisibleHint()) { disPatchFragment(false); } } @Override public void onDestroyView() { super.onDestroyView(); LogUtils.e("-----> onDestroyView"); //当 View 被销毁的时候我们需要重新设置 isViewCreated mIsFirstVisible 的状态 isViewCreated = false; mIsFirstVisible = true; if (presenter != null) { presenter.detachView(); } } /** * @param visible Fragment当前是否可见,然后调用相关方法 */ public void disPatchFragment(boolean visible) { String aa = getClass().getSimpleName(); //如果父Fragment不可见,则不向下分发给子Fragment if (visible && isParentFragmentVsible()) return; // 如果当前的 Fragment 要分发的状态与 currentVisibleState 相同(都为false)我们就没有必要去做分发了。 if (currentVisibleState == visible) return; currentVisibleState = visible; if (visible) {//Fragment可见 if (mIsFirstVisible) {//可见又是第一次 mIsFirstVisible = false;//改变首次可见的状态 onFragmentFirst(); }else {//可见但不是第一次 onFragmentVisble(); } //可见状态的时候内层 fragment 生命周期晚于外层 所以在 onFragmentResume 后分发 dispatchChildFragmentVisibleState(true); } else {//不可见 onFragmentInVisible(); dispatchChildFragmentVisibleState(false); } } /** * 重新分发给子Fragment * * @param visible */ private void dispatchChildFragmentVisibleState(boolean visible) { FragmentManager childFragmentManager = getChildFragmentManager(); @SuppressLint("RestrictedApi") List fragments = childFragmentManager.getFragments(); if (fragments != null) { if (!fragments.isEmpty()) { for (Fragment child : fragments) { if (child instanceof BaseNestingLazyFragment && !child.isHidden() && child.getUserVisibleHint()) { ((BaseNestingLazyFragment) child).disPatchFragment(visible); } } } } } //Fragemnet首次可见的方法 public void onFragmentFirst() { LogUtils.e("首次可见"); } //Fragemnet可见的方法 public void onFragmentVisble() {//子Fragment调用次方法,执行可见操作 LogUtils.e("可见"); } //Fragemnet不可见的方法 public void onFragmentInVisible() { LogUtils.e("不可见"); } /** * 判断多层嵌套的父Fragment是否显示 */ private boolean isParentFragmentVsible() { BaseNestingLazyFragment fragment = (BaseNestingLazyFragment) getParentFragment(); return fragment != null && !fragment.getCurrentVisibleState(); } private boolean getCurrentVisibleState() { return currentVisibleState; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BasePresenter.java ================================================ package com.senon.lib_common.base; /** * BasePresenter */ public abstract class BasePresenter{ private V mView; public V getView(){ return mView; } public void attachView(V v){ mView = v; } public void detachView(){ mView = null; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseResponse.java ================================================ package com.senon.lib_common.base; import com.google.gson.annotations.SerializedName; /** * BaseResponse */ public class BaseResponse { @SerializedName("errorMsg") private String msg; @SerializedName("errorCode") private int code; private T data; public String getMsg() { return msg; } public int getCode() { return code; } public T getData() { return data; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/base/BaseViewImp.java ================================================ package com.senon.lib_common.base; /** * View 父类接口 */ public interface BaseViewImp { } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/Banner.java ================================================ package com.senon.lib_common.bean; /** * 首页Banner */ public class Banner { /** * desc : 一起来做个App吧 * id : 10 * imagePath : http://www.wanandroid.com/blogimgs/50c115c2-cf6c-4802-aa7b-a4334de444cd.png * isVisible : 1 * order : 3 * title : 一起来做个App吧 * type : 0 * url : http://www.wanandroid.com/blog/show/2 */ private String desc; private int id; private String imagePath; private int isVisible; private int order; private String title; private int type; private String url; public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getImagePath() { return imagePath; } public void setImagePath(String imagePath) { this.imagePath = imagePath; } public int getIsVisible() { return isVisible; } public void setIsVisible(int isVisible) { this.isVisible = isVisible; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/CollectionArticle.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 收藏列表文章 */ public class CollectionArticle { /** * curPage : 1 * datas : [{"author":"xiangcman","chapterId":314,"chapterName":"RV列表动效","courseId":13,"desc":"快速利用RecyclerView的LayoutManager搭建流式布局 ","envelopePic":"http://www.wanandroid.com/blogimgs/36badc79-fb1e-460e-8368-6898c16ba723.png","id":9977,"link":"http://www.wanandroid.com/blog/show/2112","niceDate":"2018-05-02","origin":"","originId":2829,"publishTime":1525237333000,"title":"快速利用RecyclerView的LayoutManager搭建流式布局 ","userId":1864,"visible":0,"zan":0}] * offset : 0 * over : true * pageCount : 1 * size : 20 * total : 5 */ private int curPage; private int offset; private boolean over; private int pageCount; private int size; private int total; private List datas; public int getCurPage() { return curPage; } public void setCurPage(int curPage) { this.curPage = curPage; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } public boolean isOver() { return over; } public void setOver(boolean over) { this.over = over; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public List getDatas() { return datas; } public void setDatas(List datas) { this.datas = datas; } public static class DatasBean { /** * author : xiangcman * chapterId : 314 * chapterName : RV列表动效 * courseId : 13 * desc : 快速利用RecyclerView的LayoutManager搭建流式布局 * envelopePic : http://www.wanandroid.com/blogimgs/36badc79-fb1e-460e-8368-6898c16ba723.png * id : 9977 * link : http://www.wanandroid.com/blog/show/2112 * niceDate : 2018-05-02 * origin : * originId : 2829 * publishTime : 1525237333000 * title : 快速利用RecyclerView的LayoutManager搭建流式布局 * userId : 1864 * visible : 0 * zan : 0 */ private String author; private int chapterId; private String chapterName; private int courseId; private String desc; private String envelopePic; private int id; private String link; private String niceDate; private String origin; private int originId; private long publishTime; private String title; private int userId; private int visible; private int zan; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getChapterId() { return chapterId; } public void setChapterId(int chapterId) { this.chapterId = chapterId; } public String getChapterName() { return chapterName; } public void setChapterName(String chapterName) { this.chapterName = chapterName; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getEnvelopePic() { return envelopePic; } public void setEnvelopePic(String envelopePic) { this.envelopePic = envelopePic; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getNiceDate() { return niceDate; } public void setNiceDate(String niceDate) { this.niceDate = niceDate; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } public int getOriginId() { return originId; } public void setOriginId(int originId) { this.originId = originId; } public long getPublishTime() { return publishTime; } public void setPublishTime(long publishTime) { this.publishTime = publishTime; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public int getZan() { return zan; } public void setZan(int zan) { this.zan = zan; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/HomeArticle.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 首页文章 */ public class HomeArticle { /** * curPage : 1 * datas : [{"apkLink":"","author":"tinycoder","chapterId":191,"chapterName":"数据采集与埋点", * "collect":false,"courseId":13,"desc":"","envelopePic":"","fresh":true,"id":7656, * "link":"https://juejin.im/post/5c0e4117518825369c566f07","niceDate":"15小时前","origin":"", * "projectLink":"","publishTime":1544631512000,"superChapterId":79,"superChapterName":"热门专题", * "tags":[],"title":"无埋点统计SDK实践","type":0,"userId":-1,"visible":1,"zan":0}] * offset : 0 * over : false * pageCount : 290 * size : 20 * total : 5798 */ private int curPage; private int offset; private boolean over; private int pageCount; private int size; private int total; private List datas; public int getCurPage() { return curPage; } public void setCurPage(int curPage) { this.curPage = curPage; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } public boolean isOver() { return over; } public void setOver(boolean over) { this.over = over; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public List getDatas() { return datas; } public void setDatas(List datas) { this.datas = datas; } public static class DatasBean { /** * apkLink : * author : tinycoder * chapterId : 191 * chapterName : 数据采集与埋点 * collect : false * courseId : 13 * desc : * envelopePic : * fresh : true * id : 7656 * link : https://juejin.im/post/5c0e4117518825369c566f07 * niceDate : 15小时前 * origin : * projectLink : * publishTime : 1544631512000 * superChapterId : 79 * superChapterName : 热门专题 * tags : [] * title : 无埋点统计SDK实践 * type : 0 * userId : -1 * visible : 1 * zan : 0 */ private String apkLink; private String author; private int chapterId; private String chapterName; private boolean collect; private int courseId; private String desc; private String envelopePic; private boolean fresh; private int id; private String link; private String niceDate; private String origin; private String projectLink; private long publishTime; private int superChapterId; private String superChapterName; private String title; private int type; private int userId; private int visible; private int zan; private List tags; public String getApkLink() { return apkLink; } public void setApkLink(String apkLink) { this.apkLink = apkLink; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getChapterId() { return chapterId; } public void setChapterId(int chapterId) { this.chapterId = chapterId; } public String getChapterName() { return chapterName; } public void setChapterName(String chapterName) { this.chapterName = chapterName; } public boolean isCollect() { return collect; } public void setCollect(boolean collect) { this.collect = collect; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getEnvelopePic() { return envelopePic; } public void setEnvelopePic(String envelopePic) { this.envelopePic = envelopePic; } public boolean isFresh() { return fresh; } public void setFresh(boolean fresh) { this.fresh = fresh; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getNiceDate() { return niceDate; } public void setNiceDate(String niceDate) { this.niceDate = niceDate; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } public String getProjectLink() { return projectLink; } public void setProjectLink(String projectLink) { this.projectLink = projectLink; } public long getPublishTime() { return publishTime; } public void setPublishTime(long publishTime) { this.publishTime = publishTime; } public int getSuperChapterId() { return superChapterId; } public void setSuperChapterId(int superChapterId) { this.superChapterId = superChapterId; } public String getSuperChapterName() { return superChapterName; } public void setSuperChapterName(String superChapterName) { this.superChapterName = superChapterName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public int getZan() { return zan; } public void setZan(int zan) { this.zan = zan; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/KnowledgeSysArticle.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 知识体系文章 */ public class KnowledgeSysArticle { /** * curPage : 1 * datas : [{"apkLink":"","author":"littledavid-tech","chapterId":294,"chapterName":"完整项目","collect":false,"courseId":13,"desc":"这个算是对Android学习总结,MVP架构+好多轮子","envelopePic":"http://wanandroid.com/blogimgs/9be242c9-e53e-4a54-9f49-d69b04b463b9.png","fresh":false,"id":7641,"link":"http://www.wanandroid.com/blog/show/2449","niceDate":"2天前","origin":"","projectLink":"https://github.com/littledavid-tech/WanAndroidApp","publishTime":1544499146000,"superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=294"}],"title":"我的涂鸦之作WanAndroid第三方客户端","type":0,"userId":-1,"visible":1,"zan":0}] * offset : 0 * over : false * pageCount : 7 * size : 15 * total : 102 */ private int curPage; private int offset; private boolean over; private int pageCount; private int size; private int total; private List datas; public int getCurPage() { return curPage; } public void setCurPage(int curPage) { this.curPage = curPage; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } public boolean isOver() { return over; } public void setOver(boolean over) { this.over = over; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public List getDatas() { return datas; } public void setDatas(List datas) { this.datas = datas; } public static class DatasBean { /** * apkLink : * author : littledavid-tech * chapterId : 294 * chapterName : 完整项目 * collect : false * courseId : 13 * desc : 这个算是对Android学习总结,MVP架构+好多轮子 * envelopePic : http://wanandroid.com/blogimgs/9be242c9-e53e-4a54-9f49-d69b04b463b9.png * fresh : false * id : 7641 * link : http://www.wanandroid.com/blog/show/2449 * niceDate : 2天前 * origin : * projectLink : https://github.com/littledavid-tech/WanAndroidApp * publishTime : 1544499146000 * superChapterId : 294 * superChapterName : 开源项目主Tab * tags : [{"name":"项目","url":"/project/list/1?cid=294"}] * title : 我的涂鸦之作WanAndroid第三方客户端 * type : 0 * userId : -1 * visible : 1 * zan : 0 */ private String apkLink; private String author; private int chapterId; private String chapterName; private boolean collect; private int courseId; private String desc; private String envelopePic; private boolean fresh; private int id; private String link; private String niceDate; private String origin; private String projectLink; private long publishTime; private int superChapterId; private String superChapterName; private String title; private int type; private int userId; private int visible; private int zan; private List tags; public String getApkLink() { return apkLink; } public void setApkLink(String apkLink) { this.apkLink = apkLink; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getChapterId() { return chapterId; } public void setChapterId(int chapterId) { this.chapterId = chapterId; } public String getChapterName() { return chapterName; } public void setChapterName(String chapterName) { this.chapterName = chapterName; } public boolean isCollect() { return collect; } public void setCollect(boolean collect) { this.collect = collect; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getEnvelopePic() { return envelopePic; } public void setEnvelopePic(String envelopePic) { this.envelopePic = envelopePic; } public boolean isFresh() { return fresh; } public void setFresh(boolean fresh) { this.fresh = fresh; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getNiceDate() { return niceDate; } public void setNiceDate(String niceDate) { this.niceDate = niceDate; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } public String getProjectLink() { return projectLink; } public void setProjectLink(String projectLink) { this.projectLink = projectLink; } public long getPublishTime() { return publishTime; } public void setPublishTime(long publishTime) { this.publishTime = publishTime; } public int getSuperChapterId() { return superChapterId; } public void setSuperChapterId(int superChapterId) { this.superChapterId = superChapterId; } public String getSuperChapterName() { return superChapterName; } public void setSuperChapterName(String superChapterName) { this.superChapterName = superChapterName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public int getZan() { return zan; } public void setZan(int zan) { this.zan = zan; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } public static class TagsBean { /** * name : 项目 * url : /project/list/1?cid=294 */ private String name; private String url; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/KnowledgeSystem.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 知识体系 */ public class KnowledgeSystem { /** * children : [{"children":[],"courseId":13,"id":60,"name":"Android Studio相关","order":1000,"parentChapterId":150,"userControlSetTop":false,"visible":1},{"children":[],"courseId":13,"id":169,"name":"gradle","order":1001,"parentChapterId":150,"userControlSetTop":false,"visible":1},{"children":[],"courseId":13,"id":269,"name":"官方发布","order":1002,"parentChapterId":150,"userControlSetTop":false,"visible":1}] * courseId : 13 * id : 150 * name : 开发环境 * order : 1 * parentChapterId : 0 * userControlSetTop : false * visible : 1 */ private int courseId; private int id; private String name; private int order; private int parentChapterId; private boolean userControlSetTop; private int visible; private List children; public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public int getParentChapterId() { return parentChapterId; } public void setParentChapterId(int parentChapterId) { this.parentChapterId = parentChapterId; } public boolean isUserControlSetTop() { return userControlSetTop; } public void setUserControlSetTop(boolean userControlSetTop) { this.userControlSetTop = userControlSetTop; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public List getChildren() { return children; } public void setChildren(List children) { this.children = children; } public static class ChildrenBean { /** * children : [] * courseId : 13 * id : 60 * name : Android Studio相关 * order : 1000 * parentChapterId : 150 * userControlSetTop : false * visible : 1 */ private int courseId; private int id; private String name; private int order; private int parentChapterId; private boolean userControlSetTop; private int visible; private List children; public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public int getParentChapterId() { return parentChapterId; } public void setParentChapterId(int parentChapterId) { this.parentChapterId = parentChapterId; } public boolean isUserControlSetTop() { return userControlSetTop; } public void setUserControlSetTop(boolean userControlSetTop) { this.userControlSetTop = userControlSetTop; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public List getChildren() { return children; } public void setChildren(List children) { this.children = children; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/Login.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 登录--实体 */ public class Login { /** * chapterTops : [] * collectIds : [2683,2880,2875,2868,2831,2829,2807] * email : * icon : * id : 1864 * password : * token : * type : 0 * username : senonwx */ private String email; private String icon; private int id; private String password; private String token; private int type; private String username; private List chapterTops; private List collectIds; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public List getChapterTops() { return chapterTops; } public void setChapterTops(List chapterTops) { this.chapterTops = chapterTops; } public List getCollectIds() { return collectIds; } public void setCollectIds(List collectIds) { this.collectIds = collectIds; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/ProjectArticle.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 项目列表 */ public class ProjectArticle { /** * curPage : 1 * datas : [{"apkLink":"","author":"littledavid-tech","chapterId":294,"chapterName":"完整项目","collect":false,"courseId":13,"desc":"这个算是对Android学习总结,MVP架构+好多轮子","envelopePic":"http://wanandroid.com/blogimgs/9be242c9-e53e-4a54-9f49-d69b04b463b9.png","fresh":false,"id":7641,"link":"http://www.wanandroid.com/blog/show/2449","niceDate":"2天前","origin":"","projectLink":"https://github.com/littledavid-tech/WanAndroidApp","publishTime":1544499146000,"superChapterId":294,"superChapterName":"开源项目主Tab","tags":[{"name":"项目","url":"/project/list/1?cid=294"}],"title":"我的涂鸦之作WanAndroid第三方客户端","type":0,"userId":-1,"visible":1,"zan":0}] * offset : 0 * over : false * pageCount : 7 * size : 15 * total : 102 */ private int curPage; private int offset; private boolean over; private int pageCount; private int size; private int total; private List datas; public int getCurPage() { return curPage; } public void setCurPage(int curPage) { this.curPage = curPage; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } public boolean isOver() { return over; } public void setOver(boolean over) { this.over = over; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public List getDatas() { return datas; } public void setDatas(List datas) { this.datas = datas; } public static class DatasBean { /** * apkLink : * author : littledavid-tech * chapterId : 294 * chapterName : 完整项目 * collect : false * courseId : 13 * desc : 这个算是对Android学习总结,MVP架构+好多轮子 * envelopePic : http://wanandroid.com/blogimgs/9be242c9-e53e-4a54-9f49-d69b04b463b9.png * fresh : false * id : 7641 * link : http://www.wanandroid.com/blog/show/2449 * niceDate : 2天前 * origin : * projectLink : https://github.com/littledavid-tech/WanAndroidApp * publishTime : 1544499146000 * superChapterId : 294 * superChapterName : 开源项目主Tab * tags : [{"name":"项目","url":"/project/list/1?cid=294"}] * title : 我的涂鸦之作WanAndroid第三方客户端 * type : 0 * userId : -1 * visible : 1 * zan : 0 */ private String apkLink; private String author; private int chapterId; private String chapterName; private boolean collect; private int courseId; private String desc; private String envelopePic; private boolean fresh; private int id; private String link; private String niceDate; private String origin; private String projectLink; private long publishTime; private int superChapterId; private String superChapterName; private String title; private int type; private int userId; private int visible; private int zan; private List tags; public String getApkLink() { return apkLink; } public void setApkLink(String apkLink) { this.apkLink = apkLink; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getChapterId() { return chapterId; } public void setChapterId(int chapterId) { this.chapterId = chapterId; } public String getChapterName() { return chapterName; } public void setChapterName(String chapterName) { this.chapterName = chapterName; } public boolean isCollect() { return collect; } public void setCollect(boolean collect) { this.collect = collect; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getEnvelopePic() { return envelopePic; } public void setEnvelopePic(String envelopePic) { this.envelopePic = envelopePic; } public boolean isFresh() { return fresh; } public void setFresh(boolean fresh) { this.fresh = fresh; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getNiceDate() { return niceDate; } public void setNiceDate(String niceDate) { this.niceDate = niceDate; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } public String getProjectLink() { return projectLink; } public void setProjectLink(String projectLink) { this.projectLink = projectLink; } public long getPublishTime() { return publishTime; } public void setPublishTime(long publishTime) { this.publishTime = publishTime; } public int getSuperChapterId() { return superChapterId; } public void setSuperChapterId(int superChapterId) { this.superChapterId = superChapterId; } public String getSuperChapterName() { return superChapterName; } public void setSuperChapterName(String superChapterName) { this.superChapterName = superChapterName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public int getZan() { return zan; } public void setZan(int zan) { this.zan = zan; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } public static class TagsBean { /** * name : 项目 * url : /project/list/1?cid=294 */ private String name; private String url; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/WXarticle.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 公众号文章 */ public class WXarticle { /** * curPage : 2 * datas : [{"apkLink":"","author":"鸿洋","chapterId":408,"chapterName":"鸿洋","collect":false,"courseId":13,"desc":"","envelopePic":"","fresh":false,"id":7503,"link":"https://mp.weixin.qq.com/s/m1MhhUYi71OO9eZCU3xEwA","niceDate":"2018-11-12","origin":"","projectLink":"","publishTime":1541952000000,"superChapterId":408,"superChapterName":"公众号","tags":[{"name":"公众号","url":"/wxarticle/list/408/1"}],"title":"Toast 不显示了?","type":0,"userId":-1,"visible":1,"zan":0}] * offset : 20 * over : false * pageCount : 33 * size : 20 * total : 641 */ private int curPage; private int offset; private boolean over; private int pageCount; private int size; private int total; private List datas; public int getCurPage() { return curPage; } public void setCurPage(int curPage) { this.curPage = curPage; } public int getOffset() { return offset; } public void setOffset(int offset) { this.offset = offset; } public boolean isOver() { return over; } public void setOver(boolean over) { this.over = over; } public int getPageCount() { return pageCount; } public void setPageCount(int pageCount) { this.pageCount = pageCount; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getTotal() { return total; } public void setTotal(int total) { this.total = total; } public List getDatas() { return datas; } public void setDatas(List datas) { this.datas = datas; } public static class DatasBean { /** * apkLink : * author : 鸿洋 * chapterId : 408 * chapterName : 鸿洋 * collect : false * courseId : 13 * desc : * envelopePic : * fresh : false * id : 7503 * link : https://mp.weixin.qq.com/s/m1MhhUYi71OO9eZCU3xEwA * niceDate : 2018-11-12 * origin : * projectLink : * publishTime : 1541952000000 * superChapterId : 408 * superChapterName : 公众号 * tags : [{"name":"公众号","url":"/wxarticle/list/408/1"}] * title : Toast 不显示了? * type : 0 * userId : -1 * visible : 1 * zan : 0 */ private String apkLink; private String author; private int chapterId; private String chapterName; private boolean collect; private int courseId; private String desc; private String envelopePic; private boolean fresh; private int id; private String link; private String niceDate; private String origin; private String projectLink; private long publishTime; private int superChapterId; private String superChapterName; private String title; private int type; private int userId; private int visible; private int zan; private List tags; public String getApkLink() { return apkLink; } public void setApkLink(String apkLink) { this.apkLink = apkLink; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getChapterId() { return chapterId; } public void setChapterId(int chapterId) { this.chapterId = chapterId; } public String getChapterName() { return chapterName; } public void setChapterName(String chapterName) { this.chapterName = chapterName; } public boolean isCollect() { return collect; } public void setCollect(boolean collect) { this.collect = collect; } public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getEnvelopePic() { return envelopePic; } public void setEnvelopePic(String envelopePic) { this.envelopePic = envelopePic; } public boolean isFresh() { return fresh; } public void setFresh(boolean fresh) { this.fresh = fresh; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getNiceDate() { return niceDate; } public void setNiceDate(String niceDate) { this.niceDate = niceDate; } public String getOrigin() { return origin; } public void setOrigin(String origin) { this.origin = origin; } public String getProjectLink() { return projectLink; } public void setProjectLink(String projectLink) { this.projectLink = projectLink; } public long getPublishTime() { return publishTime; } public void setPublishTime(long publishTime) { this.publishTime = publishTime; } public int getSuperChapterId() { return superChapterId; } public void setSuperChapterId(int superChapterId) { this.superChapterId = superChapterId; } public String getSuperChapterName() { return superChapterName; } public void setSuperChapterName(String superChapterName) { this.superChapterName = superChapterName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getType() { return type; } public void setType(int type) { this.type = type; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public int getZan() { return zan; } public void setZan(int zan) { this.zan = zan; } public List getTags() { return tags; } public void setTags(List tags) { this.tags = tags; } public static class TagsBean { /** * name : 公众号 * url : /wxarticle/list/408/1 */ private String name; private String url; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/bean/WXchapters.java ================================================ package com.senon.lib_common.bean; import java.util.List; /** * 微信公众号列表 */ public class WXchapters { /** * children : [] * courseId : 13 * id : 408 * name : 鸿洋 * order : 190000 * parentChapterId : 407 * userControlSetTop : false * visible : 1 */ private int courseId; private int id; private String name; private int order; private int parentChapterId; private boolean userControlSetTop; private int visible; private List children; public int getCourseId() { return courseId; } public void setCourseId(int courseId) { this.courseId = courseId; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } public int getParentChapterId() { return parentChapterId; } public void setParentChapterId(int parentChapterId) { this.parentChapterId = parentChapterId; } public boolean isUserControlSetTop() { return userControlSetTop; } public void setUserControlSetTop(boolean userControlSetTop) { this.userControlSetTop = userControlSetTop; } public int getVisible() { return visible; } public void setVisible(int visible) { this.visible = visible; } public List getChildren() { return children; } public void setChildren(List children) { this.children = children; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/contract/LoginContract.java ================================================ package com.senon.lib_common.common.contract; import com.senon.lib_common.base.BasePresenter; import com.senon.lib_common.base.BaseViewImp; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.bean.Login; import java.util.HashMap; /** * LoginContract */ public interface LoginContract { //方法命名以 请求方法+Result 命名 interface View extends BaseViewImp { void getLoginResult(BaseResponse data); void getRegisterResult(BaseResponse data); } //方法命名以 get+方法 命名 abstract class Presenter extends BasePresenter { public abstract void getLogin(HashMap map, boolean isDialog, boolean cancelable); public abstract void getRegister(HashMap map, boolean isDialog, boolean cancelable); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/contract/WebviewContract.java ================================================ package com.senon.lib_common.common.contract; import com.senon.lib_common.base.BasePresenter; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.base.BaseViewImp; import com.senon.lib_common.bean.Login; import java.util.HashMap; /** * WebviewContract */ public interface WebviewContract { //方法命名以 请求方法+Result 命名 interface View extends BaseViewImp { void getCollectResult(int id,boolean isCollect); void getCollFailResult(int id); } //方法命名以 get+方法 命名 abstract class Presenter extends BasePresenter { public abstract void getCollect(int id ,boolean isDialog, boolean cancelable); public abstract void getUnollect(int id, boolean isDialog, boolean cancelable); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/presenter/LoginPresenter.java ================================================ package com.senon.lib_common.common.presenter; import android.content.Context; import com.senon.lib_common.bean.Login; import com.senon.lib_common.common.contract.LoginContract; import com.senon.lib_common.net.ServerUtils; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.net.callback.RequestCallback; import com.senon.lib_common.net.callback.RxErrorHandler; import com.senon.lib_common.utils.RetryWithDelay; import com.senon.lib_common.utils.RxUtils; import com.senon.lib_common.utils.ToastUtil; import java.util.HashMap; /** * 登录 P */ public class LoginPresenter extends LoginContract.Presenter { private Context context; public LoginPresenter(Context context) { this.context = context; } @Override public void getLogin(HashMap map, boolean isDialog, boolean cancelable) { ServerUtils.getCommonApi().login(map) .retryWhen(new RetryWithDelay(3,2)) .compose(RxUtils.>bindToLifecycle(getView())) .compose(RxUtils.>getSchedulerTransformer()) .subscribe(new RequestCallback>(context, RxErrorHandler.getInstance(),isDialog,cancelable) { @Override public void onNext(BaseResponse baseResponse) { super.onNext(baseResponse); if(baseResponse.getCode() == 0){ getView().getLoginResult(baseResponse); }else{ ToastUtil.initToast(baseResponse.getMsg()); } } @Override public void onError(Throwable e) { super.onError(e); } }); } @Override public void getRegister(HashMap map, boolean isDialog, boolean cancelable) { ServerUtils.getCommonApi().register(map) .retryWhen(new RetryWithDelay(3,2)) .compose(RxUtils.>bindToLifecycle(getView())) .compose(RxUtils.>getSchedulerTransformer()) .subscribe(new RequestCallback>(context, RxErrorHandler.getInstance(),isDialog,cancelable) { @Override public void onNext(BaseResponse baseResponse) { super.onNext(baseResponse); if(baseResponse.getCode() == 0){ getView().getRegisterResult(baseResponse); }else{ ToastUtil.initToast(baseResponse.getMsg()); } } @Override public void onError(Throwable e) { super.onError(e); } }); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/presenter/WebviewPresenter.java ================================================ package com.senon.lib_common.common.presenter; import android.content.Context; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.bean.Login; import com.senon.lib_common.common.contract.WebviewContract; import com.senon.lib_common.net.ServerUtils; import com.senon.lib_common.net.callback.RequestCallback; import com.senon.lib_common.net.callback.RxErrorHandler; import com.senon.lib_common.utils.RetryWithDelay; import com.senon.lib_common.utils.RxUtils; import com.senon.lib_common.utils.ToastUtil; import java.util.HashMap; /** * Webview P */ public class WebviewPresenter extends WebviewContract.Presenter { private Context context; public WebviewPresenter(Context context) { this.context = context; } @Override public void getCollect(final int id, boolean isDialog, boolean cancelable) { ServerUtils.getCommonApi().getCollect(id) .retryWhen(new RetryWithDelay(3,2)) .compose(RxUtils.bindToLifecycle(getView())) .compose(RxUtils.getSchedulerTransformer()) .subscribe(new RequestCallback(context, RxErrorHandler.getInstance(),isDialog,cancelable) { @Override public void onNext(BaseResponse baseResponse) { super.onNext(baseResponse); if(baseResponse.getCode() == 0){ getView().getCollectResult(id,true); }else{ getView().getCollFailResult(id); ToastUtil.initToast(baseResponse.getMsg()); } } @Override public void onError(Throwable e) { super.onError(e); } }); } @Override public void getUnollect(final int id, boolean isDialog, boolean cancelable) { ServerUtils.getCommonApi().getUncollectOriginId(id) .retryWhen(new RetryWithDelay(3,2)) .compose(RxUtils.bindToLifecycle(getView())) .compose(RxUtils.getSchedulerTransformer()) .subscribe(new RequestCallback(context, RxErrorHandler.getInstance(),isDialog,cancelable) { @Override public void onNext(BaseResponse baseResponse) { super.onNext(baseResponse); if(baseResponse.getCode() == 0){ getView().getCollectResult(id,false); }else{ getView().getCollFailResult(id); ToastUtil.initToast(baseResponse.getMsg()); } } @Override public void onError(Throwable e) { super.onError(e); } }); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/ui/Common_LoginActivity.java ================================================ package com.senon.lib_common.common.ui; import android.graphics.Paint; import android.view.View; import android.widget.EditText; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Autowired; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.ConstantLoginArouter; import com.senon.lib_common.R; import com.senon.lib_common.base.BaseActivity; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.ComUtil; import com.senon.lib_common.bean.Login; import com.senon.lib_common.common.contract.LoginContract; import com.senon.lib_common.common.presenter.LoginPresenter; import com.senon.lib_common.net.cookies.PersistentCookieStore; import com.senon.lib_common.utils.BaseEvent; import com.senon.lib_common.utils.StatusBarUtils; import com.senon.lib_common.utils.ToastUtil; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; /** * 所有模块统一登录页面 */ @Route(path = ConstantLoginArouter.PATH_COMMON_LOGINACTIVITY) public class Common_LoginActivity extends BaseActivity implements LoginContract.View { @Autowired String targetUrl; private EditText account_edt,password_edt; private TextView register_tv; @Override public int getLayoutId() { StatusBarUtils.with(this).init(); return R.layout.activity_common__login; } @Override public LoginContract.Presenter createPresenter() { return new LoginPresenter(this); } @Override public LoginContract.View createView() { return this; } @Override public void init() { EventBus.getDefault().register(this); account_edt = findViewById(R.id.account_edt); password_edt = findViewById(R.id.password_edt); register_tv = findViewById(R.id.register_tv); register_tv.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); } @Override public void getLoginResult(BaseResponse data) { //登录成功时 //保存参数 PersistentCookieStore.getCookieStore().saveUserInfo( data.getData().getUsername(), password_edt.getText().toString().trim()); if(targetUrl != null){ //跳转到目标页 ARouter.getInstance().build(targetUrl).navigation(); } BaseEvent event = new BaseEvent(); event.setCode(0); EventBus.getDefault().post(event); finish(); } @Override public void getRegisterResult(BaseResponse data) { } public void onClick(View view) { int id = view.getId(); if(id == R.id.login_btn){ String account = account_edt.getText().toString(); String password = password_edt.getText().toString(); if (account.isEmpty()) { ToastUtil.initToast("请输入账号"); return; } if (password.isEmpty()) { ToastUtil.initToast("请输入密码"); return; } getPresenter().getLogin(ComUtil.getMd5Str( new String[]{"username", "password"}, new String[]{account.trim(), password.trim()}) , true, true); }else if(id == R.id.visitor_tv){ // 跳转到目标页 if(targetUrl != null){ //跳转到目标页 ARouter.getInstance().build(targetUrl).navigation(); } finish(); }else if(id == R.id.register_tv){ //跳转到注册页 同意用arouter跳转,便于以后移动模块的改动 ARouter.getInstance().build(ConstantArouter.PATH_COMMON_REGISTERACTIVITY) .withString("targetUrl",targetUrl) .navigation(); } } @Override protected void onDestroy() { super.onDestroy(); EventBus.getDefault().unregister(this); } @Subscribe(threadMode = ThreadMode.MAIN) //在ui线程执行 public void onEventReceived(BaseEvent event) { if(event.getCode() == 0){ finish(); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/ui/Common_RegisterActivity.java ================================================ package com.senon.lib_common.common.ui; import android.graphics.Paint; import android.view.View; import android.widget.EditText; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Autowired; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.senon.lib_common.ComUtil; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.ConstantLoginArouter; import com.senon.lib_common.R; import com.senon.lib_common.base.BaseActivity; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.bean.Login; import com.senon.lib_common.common.contract.LoginContract; import com.senon.lib_common.common.presenter.LoginPresenter; import com.senon.lib_common.net.cookies.PersistentCookieStore; import com.senon.lib_common.utils.BaseEvent; import com.senon.lib_common.utils.StatusBarUtils; import com.senon.lib_common.utils.ToastUtil; import org.greenrobot.eventbus.EventBus; /** * 所有模块统一注册页面 */ @Route(path = ConstantArouter.PATH_COMMON_REGISTERACTIVITY) public class Common_RegisterActivity extends BaseActivity implements LoginContract.View { @Autowired String targetUrl; private EditText account_edt,password_edt,password_re_edt; private TextView login_tv; @Override public int getLayoutId() { StatusBarUtils.with(this).init(); return R.layout.activity_common__register; } @Override public LoginContract.Presenter createPresenter() { return new LoginPresenter(this); } @Override public LoginContract.View createView() { return this; } @Override public void init() { if (targetUrl == null) { //默认跳转到MainActivity targetUrl = ConstantLoginArouter.PATH_APP_MAINACTIVITY; } account_edt = findViewById(R.id.account_edt); password_edt = findViewById(R.id.password_edt); password_re_edt = findViewById(R.id.password_re_edt); login_tv = findViewById(R.id.login_tv); login_tv.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG); } @Override public void getLoginResult(BaseResponse data) { } @Override public void getRegisterResult(BaseResponse data) { //登录成功时 //保存参数 PersistentCookieStore.getCookieStore().saveUserInfo( data.getData().getUsername(), password_edt.getText().toString().trim()); //跳转到目标页 if(targetUrl != null){ ARouter.getInstance().build(targetUrl).navigation(); } BaseEvent event = new BaseEvent(); event.setCode(0); EventBus.getDefault().post(event); finish(); } public void onClick(View view) { int id = view.getId(); if(id == R.id.register_btn){ String account = account_edt.getText().toString(); String password = password_edt.getText().toString(); String repassword = password_re_edt.getText().toString(); if (account.isEmpty()) { ToastUtil.initToast("请输入账号"); return; } if (password.isEmpty()) { ToastUtil.initToast("请输入密码"); return; } if (repassword.isEmpty()) { ToastUtil.initToast("请输入确认密码"); return; } if (!password.equals(repassword)) { ToastUtil.initToast("确认密码与密码不同"); return; } getPresenter().getRegister(ComUtil.getMd5Str( new String[]{"username", "password", "repassword"}, new String[]{account.trim(), password.trim(),repassword.trim()}) , true, true); }else if(id == R.id.login_tv){ finish(); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/common/ui/Common_WebviewActivity.java ================================================ package com.senon.lib_common.common.ui; import android.view.View; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.alibaba.android.arouter.facade.annotation.Autowired; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.senon.lib_common.ComUtil; import com.senon.lib_common.ConstantArouter; import com.senon.lib_common.ConstantLoginArouter; import com.senon.lib_common.R; import com.senon.lib_common.base.BaseActivity; import com.senon.lib_common.base.BaseResponse; import com.senon.lib_common.common.contract.WebviewContract; import com.senon.lib_common.common.presenter.WebviewPresenter; import com.senon.lib_common.utils.BaseEvent; import com.senon.lib_common.utils.StatusBarUtils; import org.greenrobot.eventbus.EventBus; /** * webview */ @Route(path = ConstantArouter.PATH_COMMON_WEBVIEWCTIVITY) public class Common_WebviewActivity extends BaseActivity implements WebviewContract.View { @Autowired int id; @Autowired String url; @Autowired boolean isCollection; @Autowired String title; private TextView toolbar_title_tv; private ProgressBar progressBar; private WebView webView; private TextView collection_tv; @Override public int getLayoutId() { StatusBarUtils.with(this).init(); return R.layout.activity_common__webview; } @Override public WebviewContract.Presenter createPresenter() { return new WebviewPresenter(this); } @Override public WebviewContract.View createView() { return this; } @Override public void init() { ComUtil.changeStatusBarTextColor(this,true); progressBar = findViewById(R.id.progressBar); webView = findViewById(R.id.webView); collection_tv = findViewById(R.id.collection_tv); toolbar_title_tv = findViewById(R.id.toolbar_title_tv); initClickListener(); initWebView(); } private void initClickListener() { toolbar_title_tv.setText(title); toolbar_title_tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { webView.scrollTo(0,0); } }); findViewById(R.id.toolbar_back_igv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); if(id == 0){//id为空 则不设置收藏按钮 collection_tv.setVisibility(View.GONE); return; } collection_tv.setText(isCollection ? "已收藏":"收藏"); collection_tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { isCollection = !isCollection;//该为相反状态 collection_tv.setText(isCollection ? "已收藏":"收藏"); if(isCollection){ getPresenter().getCollect(id,false,true); }else{ getPresenter().getUnollect(id,false,true); } } }); } private void initWebView() { WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); // 设置支持javascript脚本 webSettings.setPluginState(WebSettings.PluginState.ON); webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true); webSettings.setTextZoom(100); webSettings.setAppCacheEnabled(true); webSettings.setDomStorageEnabled(true); webSettings.setDatabaseEnabled(true); if (ComUtil.isNetworkConnected()) { webSettings.setCacheMode(WebSettings.LOAD_DEFAULT); } else { webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); } webView.loadUrl(url); webView.setWebViewClient(new WebViewClient() { //实现点击webView页面的链接 @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { view.loadUrl(url); return true; } }); //设置WebViewClient用来辅助WebView处理各种通知请求事件等,如更新历史记录、网页开始加载/完毕、报告错误信息等 webView.setWebViewClient(new WebViewClient() { // 以下方法避免 自动打开系统自带的浏览器,而是让新打开的网页在当前的WebView中显示 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } }); // 用于辅助WebView处理JavaScript的对话框、网站图标、网站标题以及网页加载进度等 webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { progressBar.setVisibility(View.INVISIBLE); } else { if (progressBar.getVisibility() == View.INVISIBLE) { progressBar.setVisibility(View.VISIBLE); } progressBar.setProgress(newProgress); } super.onProgressChanged(view, newProgress); } @Override public void onShowCustomView(View view, CustomViewCallback callback) { super.onShowCustomView(view, callback); } @Override public void onHideCustomView() { super.onHideCustomView(); } }); } @Override public void getCollectResult(int id,boolean isCollect) { BaseEvent event = new BaseEvent(); event.setCode(101); event.setId(id); event.setCollect(isCollect); EventBus.getDefault().post(event); } @Override public void getCollFailResult(int id) { if(this.id == id){ isCollection = !isCollection; collection_tv.setText(isCollection ? "已收藏":"收藏"); } ARouter.getInstance().build(ConstantLoginArouter.PATH_COMMON_LOGINACTIVITY) .navigation(); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/RequestInterceptor.java ================================================ package com.senon.lib_common.net; import org.json.JSONObject; import java.io.IOException; import java.util.HashMap; import java.util.Map; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; /** * 网络统一拦截 */ public class RequestInterceptor implements Interceptor { private final int DEVICE_TYPE = 1; // 设备类型 private RequestInterceptor() { } private static RequestInterceptor instance; public static RequestInterceptor getInstance() { if (instance == null) { synchronized (RequestInterceptor.class) { if (instance == null) { instance = new RequestInterceptor(); } } } return instance; } @Override public Response intercept(Chain chain) throws IOException { Request original = chain.request(); Request.Builder requestBuilder = original.newBuilder() .header("data", fetchHeaderInfo()) .method(original.method(), original.body()); return chain.proceed(requestBuilder.build()); } private String fetchHeaderInfo() { // String deviceCode = MD5Utils.GetMD5Code(MobileInfo.phoneOnlyCode(context)); Map map = new HashMap<>(); // map.put("DeviceType", String.valueOf(DEVICE_TYPE)); // map.put("DeviceToken", deviceCode); // map.put("APPVersion", APP_VERSION_NAME); // map.put("RegistrationID", jpushID); // map.put("Authorization", token); JSONObject json = new JSONObject(map); return json.toString(); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/ServerUtils.java ================================================ package com.senon.lib_common.net; import com.senon.lib_common.AppConfig; import com.senon.lib_common.ComUtil; import com.senon.lib_common.api.BaseApi; import com.senon.lib_common.net.cookies.CookiesManager; import com.senon.lib_common.utils.ConstantUtils; import java.io.File; import java.io.IOException; import java.security.cert.CertificateException; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import okhttp3.Cache; import okhttp3.CacheControl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import okhttp3.logging.HttpLoggingInterceptor; import retrofit2.Retrofit; import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; import retrofit2.converter.scalars.ScalarsConverterFactory; /** * 网络请求 工具 */ public class ServerUtils { private static final int TIME_OUT = 5 * 1000;//链接超时时间 private volatile static BaseApi mBaseApi; private static File cacheFile = new File(AppConfig.PATH_CACHE); private static Cache cache = new Cache(cacheFile, 1024 * 1024 * 50); public static BaseApi getCommonApi() { try { if (mBaseApi == null) { synchronized (ServerUtils.class) { if (mBaseApi == null) { mBaseApi = createService(BaseApi.class, AppConfig.BASE_URL); } } } } catch (Exception e) { e.printStackTrace(); } return mBaseApi; } private static S createService(Class serviceClass, String url) throws Exception { Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(url) .client(httpClient.build()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()); Retrofit retrofit = builder.build(); return retrofit.create(serviceClass); } private static Interceptor cacheInterceptor = new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); if (!ComUtil.isNetworkConnected()) { request = request.newBuilder() .cacheControl(CacheControl.FORCE_CACHE) .build(); } Response response = chain.proceed(request); if (ComUtil.isNetworkConnected()) { int maxAge = 0; // 有网络时, 不缓存, 最大保存时长为0 response.newBuilder() .header("Cache-Control", "public, max-age=" + maxAge) .removeHeader("Pragma") .build(); } else { // 无网络时,设置超时为1周 int maxStale = 60 * 60 * 24 * 7; response.newBuilder() .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) .removeHeader("Pragma") .build(); } return response; } }; private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder() //设置超时 .readTimeout(TIME_OUT, TimeUnit.SECONDS) .writeTimeout(TIME_OUT, TimeUnit.SECONDS) .connectTimeout(TIME_OUT, TimeUnit.SECONDS) // .addInterceptor(RequestInterceptor.getInstance())//网络请求 统一拦截 .addInterceptor(getLogInterceptor()) .sslSocketFactory(getSSLSocketFactory()) //设置缓存 .addNetworkInterceptor(cacheInterceptor) .addInterceptor(cacheInterceptor) .cache(cache) //设置cookies .cookieJar(new CookiesManager()) .hostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); private static HttpLoggingInterceptor getLogInterceptor() { HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); if (ConstantUtils.isAppDebug()) { loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); } else { loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.NONE); } return loggingInterceptor; } /** * 不验证证书 * * @return * @throws Exception */ private static SSLSocketFactory getSSLSocketFactory() { //创建一个不验证证书链的证书信任管理器。 final TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() { @Override public void checkClientTrusted( java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted( java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; } }}; final SSLContext sslContext; try { sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); return sslContext .getSocketFactory(); } catch (Exception e) { e.printStackTrace(); } return null; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/callback/ErrorListener.java ================================================ package com.senon.lib_common.net.callback; public interface ErrorListener { void handleError(Throwable e); } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/callback/RequestCallback.java ================================================ package com.senon.lib_common.net.callback; import android.content.Context; import com.senon.lib_common.net.progress.ProgressCancelListener; import com.senon.lib_common.net.progress.ProgressDialogHandler; import io.reactivex.Observer; import io.reactivex.annotations.NonNull; import io.reactivex.disposables.Disposable; /** * RxJava 自定义回调 */ public abstract class RequestCallback implements Observer,ProgressCancelListener { private ErrorListener errorListener; private Disposable mDisposable; private Context mContext; private boolean cancelable = false;//该dialog如果开启 则可以设置是否能够返回键取消请求 private ProgressDialogHandler mProgressDialogHandler;//默认为null 即不开启dialog public RequestCallback(Context context,ErrorListener errorListener) { this(context,errorListener,false); } /** * 传这个构造默认开启dialog * @param cancelable 该dialog如果开启 则可以设置是否能够返回键取消请求 */ public RequestCallback(Context context,ErrorListener errorListener,boolean cancelable) { this(context,errorListener,true,cancelable); } public RequestCallback(Context context,ErrorListener errorListener,boolean showDialog,boolean cancelable) { this.mContext = context; this.errorListener = errorListener; this.cancelable = cancelable; if(showDialog){ this.mProgressDialogHandler = new ProgressDialogHandler(context, this, cancelable); } } private void showProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.SHOW_PROGRESS_DIALOG).sendToTarget(); } } private void dismissProgressDialog() { if (mProgressDialogHandler != null) { mProgressDialogHandler.obtainMessage(ProgressDialogHandler.DISMISS_PROGRESS_DIALOG).sendToTarget(); mProgressDialogHandler = null; } } @Override public void onSubscribe(@NonNull Disposable d) { this.mDisposable = d; showProgressDialog(); } @Override public void onNext(@NonNull T t) { } @Override public void onError(@NonNull Throwable e) { e.printStackTrace(); dismissProgressDialog(); if (errorListener != null) { errorListener.handleError(e); } } @Override public void onComplete() { dismissProgressDialog(); } @Override public void onCancelProgress() { //如果处于订阅状态,则取消订阅 if (!mDisposable.isDisposed()) { mDisposable.dispose(); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/callback/RxErrorHandler.java ================================================ package com.senon.lib_common.net.callback; import com.senon.lib_common.utils.LogUtils; import com.senon.lib_common.utils.ToastUtil; public class RxErrorHandler implements ErrorListener { private volatile static RxErrorHandler rxErrorHandler; private RxErrorHandler() { } public static RxErrorHandler getInstance() { if (rxErrorHandler == null) { synchronized (RxErrorHandler.class) { if (rxErrorHandler == null) { rxErrorHandler = new RxErrorHandler(); } } } return rxErrorHandler; } @Override public void handleError(Throwable throwable) { String errorString = throwable.toString(); LogUtils.e("网络错误信息为 ========>>>" + throwable.toString()); //返回的错误为空 if (errorString == null) { ToastUtil.initToast("网络数据异常,请重试"); } else { //请求超时 if (errorString.contains("TimeoutException") || errorString.contains("SocketTimeoutException")) { ToastUtil.initToast("网络请求超时,请重试"); } //能识别的请求异常,忽略不提示 if (errorString.contains("SSLException")) { } //403、404等服务错误 if (errorString.contains("ServiceConfigurationError") || errorString.contains("AuthenticatorException")) { ToastUtil.initToast("网络数据异常,请重试"); } //网络未连接 if (errorString.contains("NetworkErrorException") || errorString.contains("NoConnectionPendingException") || errorString.contains("UnknownHostException")) { ToastUtil.initToast("您的网络不给力,请检查网络设置"); } //连接不到服务器 if (errorString.contains("ConnectException")) { ToastUtil.initToast("网络连接失败"); } } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/cookies/CookiesManager.java ================================================ package com.senon.lib_common.net.cookies; import android.support.annotation.NonNull; import java.util.List; import okhttp3.Cookie; import okhttp3.CookieJar; import okhttp3.HttpUrl; /** * @author lw * @date 2018/1/25 */ public class CookiesManager implements CookieJar { private static final PersistentCookieStore COOKIE_STORE = PersistentCookieStore.getCookieStore(); @Override public void saveFromResponse(@NonNull HttpUrl url, @NonNull List cookies) { if (cookies.size() > 0) { for (Cookie item : cookies) { COOKIE_STORE.add(url, item); } } } @Override public List loadForRequest(@NonNull HttpUrl url) { return COOKIE_STORE.get(url); } /** * 清除所有cookie */ public static void clearAllCookies() { COOKIE_STORE.removeAll(); } /** * 清除指定cookie * * @param url HttpUrl * @param cookie Cookie * @return if clear cookies */ public static boolean clearCookies(HttpUrl url, Cookie cookie) { return COOKIE_STORE.remove(url, cookie); } /** * 获取cookies * * @return List */ public static List getCookies() { return COOKIE_STORE.getCookies(); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/cookies/OkHttpCookies.java ================================================ package com.senon.lib_common.net.cookies; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import okhttp3.Cookie; /** * Cookies对象 */ class OkHttpCookies implements Serializable { private transient final Cookie cookies; private transient Cookie clientCookies; OkHttpCookies(Cookie cookies) { this.cookies = cookies; } Cookie getCookies() { Cookie bestCookies = cookies; if (clientCookies != null) { bestCookies = clientCookies; } return bestCookies; } private void writeObject(ObjectOutputStream out) throws IOException { out.writeObject(cookies.name()); out.writeObject(cookies.value()); out.writeLong(cookies.expiresAt()); out.writeObject(cookies.domain()); out.writeObject(cookies.path()); out.writeBoolean(cookies.secure()); out.writeBoolean(cookies.httpOnly()); out.writeBoolean(cookies.hostOnly()); out.writeBoolean(cookies.persistent()); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { String name = (String) in.readObject(); String value = (String) in.readObject(); long expiresAt = in.readLong(); String domain = (String) in.readObject(); String path = (String) in.readObject(); boolean secure = in.readBoolean(); boolean httpOnly = in.readBoolean(); boolean hostOnly = in.readBoolean(); Cookie.Builder builder = new Cookie.Builder(); builder = builder.name(name); builder = builder.value(value); builder = builder.expiresAt(expiresAt); builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain); builder = builder.path(path); builder = secure ? builder.secure() : builder; builder = httpOnly ? builder.httpOnly() : builder; clientCookies = builder.build(); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/cookies/PersistentCookieStore.java ================================================ package com.senon.lib_common.net.cookies; import android.content.Context; import android.content.SharedPreferences; import android.text.TextUtils; import android.util.Log; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import okhttp3.Cookie; import okhttp3.HttpUrl; /** * 持久化Cookies */ public class PersistentCookieStore { private static final String LOG_TAG = "PersistentCookieStore"; private static final String COOKIE_PREFS = "Cookies_Prefs"; private static final String NAME = "user_name"; private static final String PASSWORD = "user_password"; private final Map> cookies; private final SharedPreferences cookiePrefs; private static PersistentCookieStore cookieStore; public static void init(Context context){ cookieStore = new PersistentCookieStore(context); } public static PersistentCookieStore getCookieStore(){ return cookieStore; } private PersistentCookieStore(Context context) { cookies = new HashMap<>(); cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, Context.MODE_PRIVATE); //将持久化的cookies缓存到内存中 即map cookies Map prefsMap = cookiePrefs.getAll(); for (Map.Entry entry : prefsMap.entrySet()) { String[] cookieNames = TextUtils.split((String) entry.getValue(), ","); for (String name : cookieNames) { String encodedCookie = cookiePrefs.getString(name, null); if (encodedCookie != null) { Cookie decodedCookie = decodeCookie(encodedCookie); if (decodedCookie != null) { if (!cookies.containsKey(entry.getKey())) { cookies.put(entry.getKey(), new ConcurrentHashMap()); } cookies.get(entry.getKey()).put(name, decodedCookie); } } } } } private String getCookieToken(Cookie cookie) { return cookie.name() + "@" + cookie.domain(); } public void add(HttpUrl url, Cookie cookie) { String name = getCookieToken(cookie); //将cookies缓存到内存中 如果缓存过期 就重置此cookie if (!cookie.persistent()) { if (!cookies.containsKey(url.host())) { cookies.put(url.host(), new ConcurrentHashMap(10)); } cookies.get(url.host()).put(name, cookie); } else { if (cookies.containsKey(url.host())) { cookies.get(url.host()).remove(name); } } //将cookies持久化到本地 SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));//将key值存储用以查询 prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie))); prefsWriter.apply(); } public List get(HttpUrl url) { ArrayList ret = new ArrayList<>(); if (cookies.containsKey(url.host())) { ret.addAll(cookies.get(url.host()).values()); } return ret; } void removeAll() { SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.clear(); prefsWriter.apply(); cookies.clear(); } public void saveUserInfo(String username,String password){ //将userinfo持久化到本地 SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); prefsWriter.putString(NAME,username); prefsWriter.putString(PASSWORD,password); prefsWriter.apply(); } public boolean isLogin(){ if(cookiePrefs.getString(NAME,null) != null && cookiePrefs.getString(PASSWORD,null) != null){ return true; } return false; } public String getUsername(){ String name = cookiePrefs.getString(NAME,null); if(cookiePrefs.getString(NAME,null) != null){ return name; } return "未知用户"; } boolean remove(HttpUrl url, Cookie cookie) { String name = getCookieToken(cookie); if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) { cookies.get(url.host()).remove(name); SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); if (cookiePrefs.contains(name)) { prefsWriter.remove(name); } prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet())); prefsWriter.apply(); return true; } else { return false; } } List getCookies() { ArrayList ret = new ArrayList<>(); for (String key : cookies.keySet()) { ret.addAll(cookies.get(key).values()); } return ret; } /** * cookies 序列化成 string * * @param cookie 要序列化的cookie * @return 序列化之后的string */ private String encodeCookie(OkHttpCookies cookie) { if (cookie == null) { return null; } ByteArrayOutputStream os = new ByteArrayOutputStream(); try { ObjectOutputStream outputStream = new ObjectOutputStream(os); outputStream.writeObject(cookie); } catch (IOException e) { Log.d(LOG_TAG, "IOException in encodeCookie", e); return null; } return byteArrayToHexString(os.toByteArray()); } /** * 将字符串反序列化成cookies * * @param cookieString cookies string * @return cookie object */ private Cookie decodeCookie(String cookieString) { byte[] bytes = hexStringToByteArray(cookieString); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); Cookie cookie = null; try { ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); cookie = ((OkHttpCookies) objectInputStream.readObject()).getCookies(); } catch (IOException e) { Log.d(LOG_TAG, "IOException in decodeCookie", e); } catch (ClassNotFoundException e) { Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e); } return cookie; } /** * 二进制数组转十六进制字符串 * * @param bytes byte array to be converted * @return string containing hex values */ private String byteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 2); for (byte element : bytes) { int v = element & 0xff; if (v < 16) { sb.append('0'); } sb.append(Integer.toHexString(v)); } return sb.toString().toUpperCase(Locale.US); } /** * 十六进制字符串转二进制数组 * * @param hexString string of hex-encoded values * @return decoded byte array */ private byte[] hexStringToByteArray(String hexString) { int len = hexString.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); } return data; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/progress/ProgressCancelListener.java ================================================ package com.senon.lib_common.net.progress; /** * 取消请求监听 */ public interface ProgressCancelListener { void onCancelProgress(); } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/net/progress/ProgressDialogHandler.java ================================================ package com.senon.lib_common.net.progress; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; import cn.pedant.SweetAlert.SweetAlertDialog; /** * Dialog的进度控制 */ public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESS_DIALOG = 1; public static final int DISMISS_PROGRESS_DIALOG = 2; private SweetAlertDialog sad; private Context context; private boolean cancelable; private ProgressCancelListener mProgressCancelListener; public ProgressDialogHandler(Context context, ProgressCancelListener mProgressCancelListener, boolean cancelable) { super(); this.context = context; this.mProgressCancelListener = mProgressCancelListener; this.cancelable = cancelable; } private void initProgressDialog() { if (sad == null) { sad = new SweetAlertDialog(context); sad.changeAlertType(SweetAlertDialog.PROGRESS_TYPE); sad.setTitleText("正在加载..."); sad.setCancelable(cancelable); if (cancelable) { sad.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialogInterface) { mProgressCancelListener.onCancelProgress(); } }); } if (!sad.isShowing()) { sad.show(); } } } private void dismissProgressDialog() { if (sad != null) { sad.dismiss(); sad = null; } } @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_PROGRESS_DIALOG: initProgressDialog(); break; case DISMISS_PROGRESS_DIALOG: dismissProgressDialog(); break; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/service/InitializeService.java ================================================ package com.senon.lib_common.service; import android.app.IntentService; import android.content.Context; import android.content.Intent; /** * 在Service中 初始化耗时的SDK等(BaseAppDeletage调用) * 为了在application中 不进行耗时操作 影响冷启动 白屏时间增加 * * IntentService特点: * 1.在任务完成后将自动停止。 * 2.任务在队列中执行,是有先后顺序的。 * 3.任务在子线程中运行,可以执行耗时任务。 */ public class InitializeService extends IntentService { private static final String ACTION_INIT = "initApplication"; public InitializeService() { super("InitializeService"); } public static void start(Context context) { Intent intent = new Intent(context, InitializeService.class); intent.setAction(ACTION_INIT); context.startService(intent); } @Override protected void onHandleIntent(Intent intent) { if (intent != null) { final String action = intent.getAction(); if (ACTION_INIT.equals(action)) { initApplication(); } } } //初始化 private void initApplication() { } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/ACache.java ================================================ package com.senon.lib_common.utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import com.senon.lib_common.AppConfig; import org.json.JSONArray; import org.json.JSONObject; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.math.BigDecimal; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * @author Michael Yang(www.yangfuhai.com) update at 2013.08.07 */ public class ACache { public static final int TIME_HOUR = 60 * 60; public static final int TIME_DAY = TIME_HOUR * 24; private static final int MAX_SIZE = 1000 * 1000 * 50; // 50 mb private static final int MAX_COUNT = Integer.MAX_VALUE; // 不限制存放数据的数量 private static Map mInstanceMap = new HashMap(); private ACacheManager mCache; public static ACache get(Context ctx) { return get(ctx, "Data"); } public static ACache get(Context ctx, String cacheName) { File f = new File(AppConfig.PATH_DATA, cacheName); return get(f, MAX_SIZE, MAX_COUNT); } public static ACache get(File cacheDir) { return get(cacheDir, MAX_SIZE, MAX_COUNT); } public static ACache get(Context ctx, long max_zise, int max_count) { File f = new File(AppConfig.PATH_DATA, "Data"); return get(f, max_zise, max_count); } public static ACache get(File cacheDir, long max_zise, int max_count) { ACache manager = mInstanceMap.get(cacheDir.getAbsoluteFile() + myPid()); if (manager == null) { manager = new ACache(cacheDir, max_zise, max_count); mInstanceMap.put(cacheDir.getAbsolutePath() + myPid(), manager); } return manager; } public static boolean deleteDir(File dir) { if (dir != null && dir.isDirectory()) { String[] children = dir.list(); for (String aChildren : children) { boolean success = deleteDir(new File(dir, aChildren)); if (!success) { return false; } } } assert dir != null; return dir.delete(); } public static String getCacheSize(File file) { return getFormatSize(getFolderSize(file)); } public static long getFolderSize(File file) { long size = 0; try { File[] fileList = file.listFiles(); for (File aFileList : fileList) { // 如果下面还有文件 if (aFileList.isDirectory()) { size = size + getFolderSize(aFileList); } else { size = size + aFileList.length(); } } } catch (Exception e) { e.printStackTrace(); } return size; } public static String getFormatSize(double size) { double kiloByte = size / 1024; if (kiloByte < 1) { // return size + "Byte"; return "0K"; } double megaByte = kiloByte / 1024; if (megaByte < 1) { BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); return result1.setScale(2, BigDecimal.ROUND_HALF_UP) .toPlainString() + "KB"; } double gigaByte = megaByte / 1024; if (gigaByte < 1) { BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); return result2.setScale(2, BigDecimal.ROUND_HALF_UP) .toPlainString() + "MB"; } double teraBytes = gigaByte / 1024; if (teraBytes < 1) { BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); return result3.setScale(2, BigDecimal.ROUND_HALF_UP) .toPlainString() + "GB"; } BigDecimal result4 = new BigDecimal(teraBytes); return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB"; } private static String myPid() { return "_" + android.os.Process.myPid(); } private ACache(File cacheDir, long max_size, int max_count) { if (!cacheDir.exists() && !cacheDir.mkdirs()) { throw new RuntimeException("can't make dirs in " + cacheDir.getAbsolutePath()); } mCache = new ACacheManager(cacheDir, max_size, max_count); } // ======================================= // ============ String数据 读写 ============== // ======================================= /** * 保存 String数据 到 缓存中 * * @param key 保存的key * @param value 保存的String数据 */ public void put(String key, String value) { File file = mCache.newFile(key); BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(file), 1024); out.write(value); } catch (IOException e) { e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } mCache.put(file); } } /** * 保存 String数据 到 缓存中 * * @param key 保存的key * @param value 保存的String数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, String value, int saveTime) { put(key, Utils.newStringWithDateInfo(saveTime, value)); } /** * 读取 String数据 * * @return String 数据 */ public String getAsString(String key) { File file = mCache.get(key); if (!file.exists()) return null; boolean removeFile = false; BufferedReader in = null; try { in = new BufferedReader(new FileReader(file)); String readString = ""; String currentLine; while ((currentLine = in.readLine()) != null) { readString += currentLine; } if (!Utils.isDue(readString)) { return Utils.clearDateInfo(readString); } else { removeFile = true; return null; } } catch (IOException e) { e.printStackTrace(); return null; } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } if (removeFile) remove(key); } } // ======================================= // ============= JSONObject 数据 读写 ============== // ======================================= /** * 保存 JSONObject数据 到 缓存中 * @param key 保存的key * @param value 保存的JSON数据 */ public void put(String key, JSONObject value) { put(key, value.toString()); } /** * 保存 JSONObject数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONObject数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, JSONObject value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONObject数据 * * @return JSONObject数据 */ public JSONObject getAsJSONObject(String key) { String JSONString = getAsString(key); try { JSONObject obj = new JSONObject(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============ JSONArray 数据 读写 ============= // ======================================= /** * 保存 JSONArray数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONArray数据 */ public void put(String key, JSONArray value) { put(key, value.toString()); } /** * 保存 JSONArray数据 到 缓存中 * * @param key 保存的key * @param value 保存的JSONArray数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, JSONArray value, int saveTime) { put(key, value.toString(), saveTime); } /** * 读取JSONArray数据 * * @return JSONArray数据 */ public JSONArray getAsJSONArray(String key) { String JSONString = getAsString(key); try { JSONArray obj = new JSONArray(JSONString); return obj; } catch (Exception e) { e.printStackTrace(); return null; } } // ======================================= // ============== byte 数据 读写 ============= // ======================================= /** * 保存 byte数据 到 缓存中 * * @param key 保存的key * @param value 保存的数据 */ public void put(String key, byte[] value) { File file = mCache.newFile(key); FileOutputStream out = null; try { out = new FileOutputStream(file); out.write(value); } catch (Exception e) { e.printStackTrace(); } finally { if (out != null) { try { out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); } } mCache.put(file); } } /** * 保存 byte数据 到 缓存中 * * @param key 保存的key * @param value 保存的数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, byte[] value, int saveTime) { put(key, Utils.newByteArrayWithDateInfo(saveTime, value)); } /** * 获取 byte 数据 * * @return byte 数据 */ public byte[] getAsBinary(String key) { RandomAccessFile RAFile = null; boolean removeFile = false; try { File file = mCache.get(key); if (!file.exists()) return null; RAFile = new RandomAccessFile(file, "r"); byte[] byteArray = new byte[(int) RAFile.length()]; RAFile.read(byteArray); if (!Utils.isDue(byteArray)) { return Utils.clearDateInfo(byteArray); } else { removeFile = true; return null; } } catch (Exception e) { e.printStackTrace(); return null; } finally { if (RAFile != null) { try { RAFile.close(); } catch (IOException e) { e.printStackTrace(); } } if (removeFile) remove(key); } } // ======================================= // ============= 序列化 数据 读写 =============== // ======================================= /** * 保存 Serializable数据 到 缓存中 * * @param key 保存的key * @param value 保存的value */ public void put(String key, Serializable value) { put(key, value, -1); } /** * 保存 Serializable数据到 缓存中 * * @param key 保存的key * @param value 保存的value * @param saveTime 保存的时间,单位:秒 */ public void put(String key, Serializable value, int saveTime) { ByteArrayOutputStream baos = null; ObjectOutputStream oos = null; try { baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(value); byte[] data = baos.toByteArray(); if (saveTime != -1) { put(key, data, saveTime); } else { put(key, data); } } catch (Exception e) { e.printStackTrace(); } finally { try { oos.close(); } catch (IOException e) { } } } /** * 读取 Serializable数据 * * @return Serializable 数据 */ public Object getAsObject(String key) { byte[] data = getAsBinary(key); if (data != null) { ByteArrayInputStream bais = null; ObjectInputStream ois = null; try { bais = new ByteArrayInputStream(data); ois = new ObjectInputStream(bais); Object reObject = ois.readObject(); return reObject; } catch (Exception e) { e.printStackTrace(); return null; } finally { try { if (bais != null) bais.close(); } catch (IOException e) { e.printStackTrace(); } try { if (ois != null) ois.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } // ======================================= // ============== bitmap 数据 读写 ============= // ======================================= /** * 保存 bitmap 到 缓存中 * * @param key 保存的key * @param value 保存的bitmap数据 */ public void put(String key, Bitmap value) { put(key, Utils.Bitmap2Bytes(value)); } /** * 保存 bitmap 到 缓存中 * * @param key 保存的key * @param value 保存的 bitmap 数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, Bitmap value, int saveTime) { put(key, Utils.Bitmap2Bytes(value), saveTime); } /** * 读取 bitmap 数据 * * @return bitmap 数据 */ public Bitmap getAsBitmap(String key) { if (getAsBinary(key) == null) { return null; } return Utils.Bytes2Bimap(getAsBinary(key)); } // ======================================= // ============= drawable 数据 读写 ============= // ======================================= /** * 保存 drawable 到 缓存中 * * @param key 保存的key * @param value 保存的drawable数据 */ public void put(String key, Drawable value) { put(key, Utils.drawable2Bitmap(value)); } /** * 保存 drawable 到 缓存中 * * @param key 保存的key * @param value 保存的 drawable 数据 * @param saveTime 保存的时间,单位:秒 */ public void put(String key, Drawable value, int saveTime) { put(key, Utils.drawable2Bitmap(value), saveTime); } /** * 读取 Drawable 数据 * * @return Drawable 数据 */ public Drawable getAsDrawable(String key) { if (getAsBinary(key) == null) { return null; } return Utils.bitmap2Drawable(Utils.Bytes2Bimap(getAsBinary(key))); } /** * 获取缓存文件 * * @return value 缓存的文件 */ public File file(String key) { File f = mCache.newFile(key); if (f.exists()) return f; return null; } /** * 移除某个key * * @return 是否移除成功 */ public boolean remove(String key) { return mCache.remove(key); } /** * 清除所有数据 */ public void clear() { mCache.clear(); } /** * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 * @title 缓存管理器 */ public class ACacheManager { private final AtomicLong cacheSize; private final AtomicInteger cacheCount; private final long sizeLimit; private final int countLimit; private final Map lastUsageDates = Collections.synchronizedMap(new HashMap()); protected File cacheDir; private ACacheManager(File cacheDir, long sizeLimit, int countLimit) { this.cacheDir = cacheDir; this.sizeLimit = sizeLimit; this.countLimit = countLimit; cacheSize = new AtomicLong(); cacheCount = new AtomicInteger(); calculateCacheSizeAndCacheCount(); } /** * 计算 cacheSize和cacheCount */ private void calculateCacheSizeAndCacheCount() { new Thread(new Runnable() { @Override public void run() { int size = 0; int count = 0; File[] cachedFiles = cacheDir.listFiles(); if (cachedFiles != null) { for (File cachedFile : cachedFiles) { size += calculateSize(cachedFile); count += 1; lastUsageDates.put(cachedFile, cachedFile.lastModified()); } cacheSize.set(size); cacheCount.set(count); } } }).start(); } private void put(File file) { int curCacheCount = cacheCount.get(); while (curCacheCount + 1 > countLimit) { long freedSize = removeNext(); cacheSize.addAndGet(-freedSize); curCacheCount = cacheCount.addAndGet(-1); } cacheCount.addAndGet(1); long valueSize = calculateSize(file); long curCacheSize = cacheSize.get(); while (curCacheSize + valueSize > sizeLimit) { long freedSize = removeNext(); curCacheSize = cacheSize.addAndGet(-freedSize); } cacheSize.addAndGet(valueSize); Long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); } private File get(String key) { File file = newFile(key); Long currentTime = System.currentTimeMillis(); file.setLastModified(currentTime); lastUsageDates.put(file, currentTime); return file; } private File newFile(String key) { return new File(cacheDir, key.hashCode() + ""); } private boolean remove(String key) { File image = get(key); return image.delete(); } private void clear() { lastUsageDates.clear(); cacheSize.set(0); File[] files = cacheDir.listFiles(); if (files != null) { for (File f : files) { f.delete(); } } } /** * 移除旧的文件 */ private long removeNext() { if (lastUsageDates.isEmpty()) { return 0; } Long oldestUsage = null; File mostLongUsedFile = null; Set> entries = lastUsageDates.entrySet(); synchronized (lastUsageDates) { for (Entry entry : entries) { if (mostLongUsedFile == null) { mostLongUsedFile = entry.getKey(); oldestUsage = entry.getValue(); } else { Long lastValueUsage = entry.getValue(); if (lastValueUsage < oldestUsage) { oldestUsage = lastValueUsage; mostLongUsedFile = entry.getKey(); } } } } long fileSize = calculateSize(mostLongUsedFile); if (mostLongUsedFile.delete()) { lastUsageDates.remove(mostLongUsedFile); } return fileSize; } private long calculateSize(File file) { return file.length(); } } /** * @author 杨福海(michael) www.yangfuhai.com * @version 1.0 * @title 时间计算工具类 */ private static class Utils { /** * 判断缓存的String数据是否到期 * * @return true:到期了 false:还没有到期 */ private static boolean isDue(String str) { return isDue(str.getBytes()); } /** * 判断缓存的byte数据是否到期 * * @return true:到期了 false:还没有到期 */ private static boolean isDue(byte[] data) { String[] strs = getDateInfoFromDate(data); if (strs != null && strs.length == 2) { String saveTimeStr = strs[0]; while (saveTimeStr.startsWith("0")) { saveTimeStr = saveTimeStr.substring(1, saveTimeStr.length()); } long saveTime = Long.valueOf(saveTimeStr); long deleteAfter = Long.valueOf(strs[1]); if (System.currentTimeMillis() > saveTime + deleteAfter * 1000) { return true; } } return false; } private static String newStringWithDateInfo(int second, String strInfo) { return createDateInfo(second) + strInfo; } private static byte[] newByteArrayWithDateInfo(int second, byte[] data2) { byte[] data1 = createDateInfo(second).getBytes(); byte[] retdata = new byte[data1.length + data2.length]; System.arraycopy(data1, 0, retdata, 0, data1.length); System.arraycopy(data2, 0, retdata, data1.length, data2.length); return retdata; } private static String clearDateInfo(String strInfo) { if (strInfo != null && hasDateInfo(strInfo.getBytes())) { strInfo = strInfo.substring(strInfo.indexOf(mSeparator) + 1, strInfo.length()); } return strInfo; } private static byte[] clearDateInfo(byte[] data) { if (hasDateInfo(data)) { return copyOfRange(data, indexOf(data, mSeparator) + 1, data.length); } return data; } private static boolean hasDateInfo(byte[] data) { return data != null && data.length > 15 && data[13] == '-' && indexOf(data, mSeparator) > 14; } private static String[] getDateInfoFromDate(byte[] data) { if (hasDateInfo(data)) { String saveDate = new String(copyOfRange(data, 0, 13)); String deleteAfter = new String(copyOfRange(data, 14, indexOf(data, mSeparator))); return new String[] { saveDate, deleteAfter }; } return null; } private static int indexOf(byte[] data, char c) { for (int i = 0; i < data.length; i++) { if (data[i] == c) { return i; } } return -1; } private static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); byte[] copy = new byte[newLength]; System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; } private static final char mSeparator = ' '; private static String createDateInfo(int second) { String currentTime = System.currentTimeMillis() + ""; while (currentTime.length() < 13) { currentTime = "0" + currentTime; } return currentTime + "-" + second + mSeparator; } /* * Bitmap → byte[] */ private static byte[] Bitmap2Bytes(Bitmap bm) { if (bm == null) { return null; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG, 100, baos); return baos.toByteArray(); } /* * byte[] → Bitmap */ private static Bitmap Bytes2Bimap(byte[] b) { if (b.length == 0) { return null; } return BitmapFactory.decodeByteArray(b, 0, b.length); } /* * Drawable → Bitmap */ private static Bitmap drawable2Bitmap(Drawable drawable) { if (drawable == null) { return null; } // 取 drawable 的长宽 int w = drawable.getIntrinsicWidth(); int h = drawable.getIntrinsicHeight(); // 取 drawable 的颜色格式 Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; // 建立对应 bitmap Bitmap bitmap = Bitmap.createBitmap(w, h, config); // 建立对应 bitmap 的画布 Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, w, h); // 把 drawable 内容画到画布中 drawable.draw(canvas); return bitmap; } /* * Bitmap → Drawable */ @SuppressWarnings("deprecation") private static Drawable bitmap2Drawable(Bitmap bm) { if (bm == null) { return null; } return new BitmapDrawable(bm); } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/BaseEvent.java ================================================ package com.senon.lib_common.utils; /** * eventbus发送实体 */ public class BaseEvent { /** // * -1:退出登录时通知Mainactivity finish * 0:登录成功 刷新所有主界面数据列表 * 1:退出成功 。。。 * * 101:文章收藏/取消收藏 (HomeMainFragment、ArtMainFragment、HomeArticleActivity、HomeProjectActivity) * 102:文章收藏/取消收藏失败 。。。 * * * * */ private int code; private String msg; private T data; private boolean isCollect; private int id; private boolean ingored; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getData() { return data; } public void setData(T data) { this.data = data; } public boolean isCollect() { return isCollect; } public void setCollect(boolean collect) { isCollect = collect; } public int getId() { return id; } public void setId(int id) { this.id = id; } public boolean isIngored() { return ingored; } public void setIngored(boolean ingored) { this.ingored = ingored; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/ConstantUtils.java ================================================ package com.senon.lib_common.utils; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; /** * 基础常量工具类 */ public class ConstantUtils { private static Context context; /** * 初始化工具类 * @param context 上下文 */ public static void init(Context context) { ConstantUtils.context = context.getApplicationContext(); } /** * 获取ApplicationContext * @return ApplicationContext */ public static Context getAPPContext() { if (context != null) return context; throw new NullPointerException("u should init first"); } /** * 判断App是否是Debug版本 * @return {@code true}: 是
{@code false}: 否 */ public static boolean isAppDebug() { String packageName = context.getPackageName(); if (packageName == null || packageName.trim().length() == 0) return false; try { PackageManager pm = context.getPackageManager(); ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), 0); return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); return false; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/LogUtils.java ================================================ package com.senon.lib_common.utils; import android.util.Log; import java.util.Locale; /** * 打印log日志工具类 */ public class LogUtils { private static boolean LOG = true; private static boolean LOGV = true; private static boolean LOGD = true; private static boolean LOGI = true; private static boolean LOGW = true; private static boolean LOGE = true; public static void setLogEnable(boolean enable) { LOG = enable; } public static void v(String mess) { if (LOG && LOGV) { Log.v(getTag(), buildMessage(mess)); } } public static void d(String mess) { if (LOG && LOGD) { Log.d(getTag(), buildMessage(mess)); } } public static void i(String mess) { if (LOG && LOGI) { Log.i(getTag(), buildMessage(mess)); } } public static void w(String mess) { if (LOG && LOGW) { Log.w(getTag(), buildMessage(mess)); } } public static void e(String mess) { if (LOG && LOGE) { log(getTag(), buildMessage(mess)); } } public static void log(String tag, String msg){ if(msg.length() > 4000) { for(int i=0;i clazz = trace[i].getClass(); if (!clazz.equals(LogUtils.class)) { callingClass = trace[i].getClassName(); callingClass = callingClass.substring(callingClass .lastIndexOf('.') + 1); break; } } return callingClass; } private static String buildMessage(String msg) { StackTraceElement[] trace = new Throwable().fillInStackTrace() .getStackTrace(); String caller = ""; for (int i = 2; i < trace.length; i++) { Class clazz = trace[i].getClass(); if (!clazz.equals(LogUtils.class)) { caller = trace[i].getMethodName(); break; } } return String.format(Locale.US, "[%d] %s: %s", Thread.currentThread() .getId(), caller, msg); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/MD5Utils.java ================================================ package com.senon.lib_common.utils; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * MD5工具 */ public class MD5Utils { //静态方法,便于作为工具类 public static String getMd5(String plainText) { try { MessageDigest md = MessageDigest.getInstance("MD5"); md.update(plainText.getBytes()); byte b[] = md.digest(); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < b.length; offset++) { i = b[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } //32位加密 return buf.toString(); // 16位的加密 //return buf.toString().substring(8, 24); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/PreferenceTool.java ================================================ package com.senon.lib_common.utils; import android.content.Context; import android.content.SharedPreferences; import com.senon.lib_opensource.BuildConfig; import java.util.Map; /** * 共享参数工具类 */ public class PreferenceTool { private static final String PREF_NAME = BuildConfig.APPLICATION_ID + "_preferences"; private static SharedPreferences.Editor editor; private static SharedPreferences pref; public static void init(Context context) { pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); editor = pref.edit(); } public static void clear() { if (editor == null) return; editor.clear(); } public static void commit() { if (editor == null) return; editor.commit(); } public static void apply() { if (editor == null) return; editor.apply(); } public static boolean contains(String key) { return pref != null && pref.contains(key); } public static float getFloat(String key, float defValue) { return pref != null ? pref.getFloat(key, defValue) : defValue; } public static int getInt(String key, int defValue) { return pref != null ? pref.getInt(key, defValue) : defValue; } public static long getLong(String key, long defValue) { return pref != null ? pref.getLong(key, defValue) : defValue; } public static String getString(String key) { return pref != null ? pref.getString(key, "") : ""; } public static String getString(String key, String defValue) { return pref != null ? pref.getString(key, defValue) : defValue; } public static boolean getBoolean(String key, boolean defValue) { return pref != null ? pref.getBoolean(key, defValue) : defValue; } public static Map getAll() { return pref != null ? pref.getAll() : null; } public static void putFloat(String key, float value) { if (editor == null) return; editor.putFloat(key, value); } public static void putInt(String key, int value) { if (editor == null) return; editor.putInt(key, value); } public static void putLong(String key, long value) { if (editor == null) return; editor.putLong(key, value); } public static void putString(String key, String value) { if (editor == null) return; editor.putString(key, value); } public static void putBoolean(String key, boolean value) { if (editor == null) return; editor.putBoolean(key, value); } public static void remove(String key) { if (editor == null) return; editor.remove(key); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/RetryWithDelay.java ================================================ package com.senon.lib_common.utils; import java.util.concurrent.TimeUnit; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.annotations.NonNull; import io.reactivex.functions.Function; public class RetryWithDelay implements Function, ObservableSource> { private final int maxRetries; private final int retryDelaySecond; private int retryCount; public RetryWithDelay(int maxRetries, int retryDelaySecond) { this.maxRetries = maxRetries; this.retryDelaySecond = retryDelaySecond; } @Override public ObservableSource apply(@NonNull Observable throwableObservable) throws Exception { return throwableObservable .flatMap(new Function>() { @Override public ObservableSource apply(@NonNull Throwable throwable) throws Exception { if (++retryCount <= maxRetries) { // When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed). LogUtils.d("get error, it will try after " + retryDelaySecond + " second, retry count " + retryCount); return Observable.timer(retryDelaySecond, TimeUnit.SECONDS); } // Max retries hit. Just pass the error along. return Observable.error(throwable); } }); } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/RxUtils.java ================================================ package com.senon.lib_common.utils; import com.senon.lib_common.base.BaseViewImp; import com.trello.rxlifecycle2.LifecycleTransformer; import com.trello.rxlifecycle2.android.ActivityEvent; import com.trello.rxlifecycle2.android.FragmentEvent; import com.trello.rxlifecycle2.components.support.RxAppCompatActivity; import com.trello.rxlifecycle2.components.support.RxFragment; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.ObservableTransformer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.annotations.NonNull; import io.reactivex.schedulers.Schedulers; /** * 在presenter中使用生命周期管理,防止内存泄漏 */ public class RxUtils { public static LifecycleTransformer bindToLifecycle(BaseViewImp view) { if (view instanceof RxAppCompatActivity) { return ((RxAppCompatActivity) view).bindToLifecycle(); } else if (view instanceof RxFragment) { return ((RxFragment) view).bindToLifecycle(); } else { throw new IllegalArgumentException("view isn't activity or fragment"); } } public static LifecycleTransformer bindActivityUntilEvent(BaseViewImp view,ActivityEvent event) { if (view instanceof RxAppCompatActivity) { return ((RxAppCompatActivity) view).bindUntilEvent(event); } else { throw new IllegalArgumentException("view isn't activity"); } } public static LifecycleTransformer bindFragmentUntilEvent(BaseViewImp view,FragmentEvent event) { if (view instanceof RxFragment) { return ((RxFragment) view).bindUntilEvent(event); } else { throw new IllegalArgumentException("view isn't fragment"); } } public static ObservableTransformer getSchedulerTransformer(){ return new ObservableTransformer() { @Override public ObservableSource apply(@NonNull Observable upstream) { return upstream .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } }; } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/StatusBarUtils.java ================================================ package com.senon.lib_common.utils; import android.app.Activity; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Build; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.util.TypedValue; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.LinearLayout; /** * 状态栏沉浸 */ public class StatusBarUtils { private Activity mActivity; //状态栏颜色 private int mColor = -1; //状态栏drawble private Drawable mDrawable; //是否是最外层布局是 DrawerLayout 的侧滑菜单 private boolean mIsDrawerLayout; //是否包含 ActionBar private boolean mIsActionBar; //侧滑菜单页面的内容视图 private int mContentResourseIdInDrawer; public StatusBarUtils(Activity activity) { mActivity = activity; } public static StatusBarUtils with(Activity activity) { return new StatusBarUtils(activity); } public int getColor() { return mColor; } public StatusBarUtils setColor(int color) { mColor = color; return this; } public Drawable getDrawable() { return mDrawable; } public StatusBarUtils setDrawable(Drawable drawable) { mDrawable = drawable; return this; } public boolean isDrawerLayout() { return mIsDrawerLayout; } public boolean isActionBar() { return mIsActionBar; } public StatusBarUtils setIsActionBar(boolean actionBar) { mIsActionBar = actionBar; return this; } /** * 是否是最外层布局为 DrawerLayout 的侧滑菜单 * * @param drawerLayout 是否最外层布局为 DrawerLayout * @param contentId 内容视图的 id * @return */ public StatusBarUtils setDrawerLayoutContentId(boolean drawerLayout, int contentId) { mIsDrawerLayout = drawerLayout; mContentResourseIdInDrawer = contentId; return this; } public void init() { fullScreen(mActivity); if (mColor != -1) { //设置了状态栏颜色 addStatusViewWithColor(mActivity, mColor); } if (mDrawable != null) { //设置了状态栏 drawble,例如渐变色 addStatusViewWithDrawble(mActivity, mDrawable); } if (isDrawerLayout()) { //未设置 fitsSystemWindows 且是侧滑菜单,需要设置 fitsSystemWindows 以解决 4.4 上侧滑菜单上方白条问题 fitsSystemWindows(mActivity); } if (isActionBar()) { //要增加内容视图的 paddingTop,否则内容被 ActionBar 遮盖 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity) + getActionBarHeight(mActivity), 0, 0); } } } /** * 去除 ActionBar 阴影 */ public StatusBarUtils clearActionBarShadow() { if (Build.VERSION.SDK_INT >= 21) { ActionBar supportActionBar = ((AppCompatActivity) mActivity).getSupportActionBar(); if (supportActionBar != null) { supportActionBar.setElevation(0); } } return this; } /** * 设置页面最外层布局 FitsSystemWindows 属性 * * @param activity */ private void fitsSystemWindows(Activity activity) { ViewGroup contentFrameLayout = (ViewGroup) activity.findViewById(android.R.id.content); View parentView = contentFrameLayout.getChildAt(0); if (parentView != null && Build.VERSION.SDK_INT >= 14) { parentView.setFitsSystemWindows(true); //布局预留状态栏高度的 padding if (parentView instanceof DrawerLayout) { DrawerLayout drawer = (DrawerLayout) parentView; //将主页面顶部延伸至status bar;虽默认为false,但经测试,DrawerLayout需显示设置 drawer.setClipToPadding(false); } } } /** * 利用反射获取状态栏高度 * * @return */ public static int getStatusBarHeight(Activity activity) { int result = 0; //获取状态栏高度的资源id int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { result = activity.getResources().getDimensionPixelSize(resourceId); } Log.e("getStatusBarHeight", result + ""); return result; } /** * 获得 ActionBar 的高度 * * @param context * @return */ public static int getActionBarHeight(Context context) { int result = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { TypedValue tv = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true); result = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); } return result; } /** * 添加状态栏占位视图 * * @param activity */ private void addStatusViewWithColor(Activity activity, int color) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (isDrawerLayout()) { //要在内容布局增加状态栏,否则会盖在侧滑菜单上 ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content); //DrawerLayout 则需要在第一个子视图即内容试图中添加padding View parentView = rootView.getChildAt(0); LinearLayout linearLayout = new LinearLayout(activity); linearLayout.setOrientation(LinearLayout.VERTICAL); View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setBackgroundColor(color); //添加占位状态栏到线性布局中 linearLayout.addView(statusBarView, lp); //侧滑菜单 DrawerLayout drawer = (DrawerLayout) parentView; //内容视图 View content = activity.findViewById(mContentResourseIdInDrawer); //将内容视图从 DrawerLayout 中移除 drawer.removeView(content); //添加内容视图 linearLayout.addView(content, content.getLayoutParams()); //将带有占位状态栏的新的内容视图设置给 DrawerLayout drawer.addView(linearLayout, 0); } else { //设置 paddingTop ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //直接设置状态栏颜色 activity.getWindow().setStatusBarColor(color); } else { //增加占位状态栏 ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); statusBarView.setBackgroundColor(color); decorView.addView(statusBarView, lp); } } } } /** * 添加状态栏占位视图 * * @param activity */ private void addStatusViewWithDrawble(Activity activity, Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //占位状态栏 View statusBarView = new View(activity); ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight(activity)); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { statusBarView.setBackground(drawable); } else { statusBarView.setBackgroundDrawable(drawable); } if (isDrawerLayout()) { //要在内容布局增加状态栏,否则会盖在侧滑菜单上 ViewGroup rootView = (ViewGroup) activity.findViewById(android.R.id.content); //DrawerLayout 则需要在第一个子视图即内容试图中添加padding View parentView = rootView.getChildAt(0); LinearLayout linearLayout = new LinearLayout(activity); linearLayout.setOrientation(LinearLayout.VERTICAL); //添加占位状态栏到线性布局中 linearLayout.addView(statusBarView, lp); //侧滑菜单 DrawerLayout drawer = (DrawerLayout) parentView; //内容视图 View content = activity.findViewById(mContentResourseIdInDrawer); //将内容视图从 DrawerLayout 中移除 drawer.removeView(content); //添加内容视图 linearLayout.addView(content, content.getLayoutParams()); //将带有占位状态栏的新的内容视图设置给 DrawerLayout drawer.addView(linearLayout, 0); } else { //增加占位状态栏,并增加状态栏高度的 paddingTop ViewGroup decorView = (ViewGroup) mActivity.getWindow().getDecorView(); decorView.addView(statusBarView, lp); //设置 paddingTop ViewGroup rootView = (ViewGroup) mActivity.getWindow().getDecorView().findViewById(android.R.id.content); rootView.setPadding(0, getStatusBarHeight(mActivity), 0, 0); } } } /** * 通过设置全屏,设置状态栏透明 * * @param activity */ private void fullScreen(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色 Window window = activity.getWindow(); View decorView = window.getDecorView(); //两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间 int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE; window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); decorView.setSystemUiVisibility(option); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); //导航栏颜色也可以正常设置 // window.setNavigationBarColor(Color.TRANSPARENT); } else { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; attributes.flags |= flagTranslucentStatus; // attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); } } } /** * 通过设置全屏,设置状态栏透明 导航栏黑色 * * @param activity */ public static void setStatusTransparent(Activity activity) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; // attributes.flags |= flagTranslucentStatus; attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.TRANSPARENT); } else { Window window = activity.getWindow(); WindowManager.LayoutParams attributes = window.getAttributes(); int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; attributes.flags |= flagTranslucentStatus; attributes.flags |= flagTranslucentNavigation; window.setAttributes(attributes); } } } } ================================================ FILE: lib_common/src/main/java/com/senon/lib_common/utils/ToastUtil.java ================================================ package com.senon.lib_common.utils; import android.app.Activity; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.support.v4.app.FragmentActivity; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.senon.lib_common.R; /** * Toast工具类 */ public class ToastUtil { /** * 可以在多线程里运行的toast */ private static volatile Toast mToast; private static final Object lock = new Object(); private static Context context; private static TextView toastTv; public static void init(Context con){ context = con; } public static void initToast(String msg) { initToast(msg, context, true); } public static void initToast(int resId, Context context) { if (context instanceof Activity || context instanceof FragmentActivity) context = context.getApplicationContext(); initToast(context.getString(resId), context, true); } public static void initToast(String msg, Context context, boolean isSingleton) { if (context instanceof Activity || context instanceof FragmentActivity) context = context.getApplicationContext(); if (mToast != null && isSingleton) { toastTv.setText(msg); } else { synchronized (lock) { // mToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT); mToast = showToast(context,msg,Toast.LENGTH_SHORT); } } mToast.setGravity(Gravity.CENTER, 0, 0);//默认显示位置 mToast.show(); } //可以设置toast的位置 public static void setGravity(int gravity, int xOffset, int yOffset) { mToast.setGravity(gravity, xOffset, yOffset); } //可以自定义toast的view public void setView(View view) { mToast.setView(view); } /** 当你在线程中使用toast时,请使用这个方法(可以控制显示多长时间) */ public static void showInThread(@NonNull final Context context, final String msg, final int length) { new Thread() { @Override public void run() { Looper.prepare();//先移除 Toast.makeText(context, msg, length).show(); Looper.loop();// 进入loop中的循环,查看消息队列 } }.start(); } /** * 以下全部代码为一个整体,可以控制显示时间的Toast */ private static Handler mHandler = null; private static int duration = 0; private static int currDuration = 0; private static final int DEFAULT = 2000; public static void showByDuration(Context context, String msg, int duration) { duration = duration; currDuration = DEFAULT; // mToast = Toast.makeText(context, msg, Toast.LENGTH_LONG); mToast = showToast(context,msg,Toast.LENGTH_LONG); mHandler = new Handler(context.getMainLooper()); mHandler.post(mToastThread); } private static Runnable mToastThread = new Runnable() { public void run() { mToast.show(); mHandler.postDelayed(mToastThread, DEFAULT);// 每隔2秒显示一次 if (duration != 0) { if (currDuration <= duration) { currDuration += DEFAULT; } else { cancel(); } } } }; private static void cancel() { mHandler.removeCallbacks(mToastThread);// 先把显示线程删除 mToast.cancel();// 把最后一个线程的显示效果cancel掉,就一了百了了 currDuration = DEFAULT; } private static Toast showToast(Context context, String msg, int duration) { if (null != context) { if (mToast == null) { mToast = new Toast(context); LayoutInflater inflater = LayoutInflater.from(context); View layout = inflater.inflate(R.layout.toast_layout, null); toastTv = layout.findViewById(R.id.message); toastTv.setText(msg); mToast.setDuration(duration); mToast.setView(layout); }else { toastTv.setText(msg); } } return mToast; } } ================================================ FILE: lib_common/src/main/res/drawable/register_border.xml ================================================ ================================================ FILE: lib_common/src/main/res/drawable/register_border_2.xml ================================================ ================================================ FILE: lib_common/src/main/res/drawable/register_border_9.xml ================================================ ================================================ FILE: lib_common/src/main/res/drawable/shape_gradient.xml ================================================ ================================================ FILE: lib_common/src/main/res/drawable/style_progress_bar.xml ================================================ ================================================ FILE: lib_common/src/main/res/drawable/toast_shape.xml ================================================ ================================================ FILE: lib_common/src/main/res/layout/activity_common__login.xml ================================================