ソースを参照

1.增加全局异常不退出应用
2.增加部分逻辑问题
3.修改部分逻辑问题
4.增加闪屏页

FailedToRead 3 年 前
コミット
e935f8457b
56 ファイル変更1939 行追加400 行削除
  1. 5 0
      .idea/jarRepositories.xml
  2. 14 1
      .idea/misc.xml
  3. 15 1
      app/build.gradle
  4. 6 0
      app/src/exception/drawable/divider.xml
  5. 6 0
      app/src/exception/drawable/list_divider_horizontal.xml
  6. 7 0
      app/src/exception/drawable/safe_mode_drawable.xml
  7. 19 0
      app/src/exception/drawable/theme_stroke_selector.xml
  8. 66 0
      app/src/exception/layout/activity_safe_mode_warning.xml
  9. 21 0
      app/src/exception/layout/fragment_crash_log.xml
  10. 24 0
      app/src/exception/layout/item.xml
  11. 60 0
      app/src/exception/layout/item_crash_log.xml
  12. 16 0
      app/src/exception/layout/lifecycle_exception.xml
  13. 6 0
      app/src/exception/values/strings.xml
  14. 21 6
      app/src/main/AndroidManifest.xml
  15. 13 37
      app/src/main/java/com/edufound/reader/activity/CrashDialogActivity.java
  16. 37 0
      app/src/main/java/com/edufound/reader/activity/LoginAlertActivity.java
  17. 4 0
      app/src/main/java/com/edufound/reader/activity/MainActivity.java
  18. 36 7
      app/src/main/java/com/edufound/reader/adapter/MyCollectionItemAdapter.java
  19. 34 9
      app/src/main/java/com/edufound/reader/adapter/MyFollowItemAdapter.java
  20. 0 45
      app/src/main/java/com/edufound/reader/adapter/TestGridAdapter.java
  21. 71 1
      app/src/main/java/com/edufound/reader/application/EApplication.java
  22. 2 0
      app/src/main/java/com/edufound/reader/contract/MainContract.java
  23. 2 0
      app/src/main/java/com/edufound/reader/contract/MyTabFragmentContract.java
  24. 7 2
      app/src/main/java/com/edufound/reader/cusview/RvListJzvdStd.java
  25. 15 10
      app/src/main/java/com/edufound/reader/fragment/CharacterFragment.java
  26. 54 15
      app/src/main/java/com/edufound/reader/fragment/MyTabFragment.java
  27. 81 0
      app/src/main/java/com/edufound/reader/listener/ActivityKillerV15_V20.java
  28. 77 0
      app/src/main/java/com/edufound/reader/listener/ActivityKillerV21_V23.java
  29. 82 0
      app/src/main/java/com/edufound/reader/listener/ActivityKillerV24_V25.java
  30. 81 0
      app/src/main/java/com/edufound/reader/listener/ActivityKillerV26.java
  31. 91 0
      app/src/main/java/com/edufound/reader/listener/ActivityKillerV28.java
  32. 17 0
      app/src/main/java/com/edufound/reader/listener/IActivityKiller.java
  33. 7 0
      app/src/main/java/com/edufound/reader/listener/RecyclerItemClickListener.java
  34. 39 66
      app/src/main/java/com/edufound/reader/popwindow/PopWindowUtil.java
  35. 11 1
      app/src/main/java/com/edufound/reader/presenter/LoginAlertPresenter.java
  36. 17 0
      app/src/main/java/com/edufound/reader/presenter/MainPresenter.java
  37. 8 1
      app/src/main/java/com/edufound/reader/presenter/MyCollectionPresenter.java
  38. 13 0
      app/src/main/java/com/edufound/reader/presenter/MyFollowPresenter.java
  39. 19 3
      app/src/main/java/com/edufound/reader/presenter/MyTabFragmentPresenter.java
  40. 46 0
      app/src/main/java/com/edufound/reader/support/ActivityLifecycleCallbacksAdapter.java
  41. 10 0
      app/src/main/java/com/edufound/reader/support/ClientTransaction.java
  42. 95 0
      app/src/main/java/com/edufound/reader/support/CrashLog.java
  43. 246 0
      app/src/main/java/com/edufound/reader/support/CrashLogFragment.java
  44. 39 0
      app/src/main/java/com/edufound/reader/support/DebugSafeModeTipActivity.java
  45. 78 0
      app/src/main/java/com/edufound/reader/support/DebugSafeModeUI.java
  46. 247 0
      app/src/main/java/com/edufound/reader/util/Cockroach.java
  47. 10 0
      app/src/main/java/com/edufound/reader/util/Consts.java
  48. 59 0
      app/src/main/java/com/edufound/reader/util/ExceptionHandler.java
  49. 0 170
      app/src/main/res/drawable/ic_launcher_background.xml
  50. BIN
      app/src/main/res/drawable/splash_bg.jpg
  51. 3 1
      app/src/main/res/layout/activity_alert_login.xml
  52. 0 19
      app/src/main/res/layout/activity_crash_dialog.xml
  53. 0 2
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  54. 0 2
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  55. 1 1
      app/src/main/res/values/themes.xml
  56. 1 0
      build.gradle

+ 5 - 0
.idea/jarRepositories.xml

@@ -31,5 +31,10 @@
       <option name="name" value="maven" />
       <option name="url" value="https://oss.jfrog.org/libs-snapshot" />
     </remote-repository>
+    <remote-repository>
+      <option name="id" value="maven2" />
+      <option name="name" value="maven2" />
+      <option name="url" value="https://jitpack.io" />
+    </remote-repository>
   </component>
 </project>

+ 14 - 1
.idea/misc.xml

@@ -7,6 +7,15 @@
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/activityLoginAlert/drawable/activity_record_start_anim.xml" value="0.5" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/activityLoginAlert/drawable/popup_record_status_over_start_divider.xml" value="0.5" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/activityLoginAlert/drawable/popup_window_bind_wechat_qrcode_bg.xml" value="0.5048828125" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/drawable/divider.xml" value="0.49609375" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/drawable/list_divider_horizontal.xml" value="0.4699248120300752" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/drawable/safe_mode_drawable.xml" value="0.4699248120300752" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/drawable/theme_stroke_selector.xml" value="0.4699248120300752" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/layout/activity_safe_mode_warning.xml" value="0.5" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/layout/fragment_crash_log.xml" value="0.20924574209245742" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/layout/item.xml" value="0.20924574209245742" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/layout/item_crash_log.xml" value="0.20924574209245742" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/exception/layout/lifecycle_exception.xml" value="0.20924574209245742" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentRecommend/drawable/activity_comment_quick_item_bg.xml" value="0.4326171875" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentRecommend/drawable/activity_comment_quick_item_one_two.xml" value="0.4326171875" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentRecommend/drawable/activity_comment_quick_item_three_bg.xml" value="0.34609375" />
@@ -24,7 +33,7 @@
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/activity_mycollection.xml" value="0.18" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/activity_myfollow.xml" value="0.14" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/activity_smallfull_video.xml" value="0.1" />
-        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/adapter_item_record_authority.xml" value="1.0" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/adapter_item_record_authority.xml" value="0.5" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/fragment_user_rv_bottom.xml" value="0.2771317829457364" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/popup_window_bind_wechat.xml" value="0.25" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/fragmentUser/layout/popupwindow_cancellation_account.xml" value="0.5" />
@@ -35,6 +44,7 @@
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable-v24/popupwindow_select_grade_selector.xml" value="0.4443359375" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/activity_saffloer_sigin_layout_divier.xml" value="0.4296875" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/cusjzplayer_controller_seekbar.xml" value="0.2713541666666667" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/ic_launcher_background.xml" value="0.4931640625" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/main_left_tab_character_selector.xml" value="0.32421875" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/main_left_tab_divider.xml" value="0.4" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/drawable/main_left_tab_follow_selector.xml" value="0.1875" />
@@ -74,10 +84,13 @@
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/fragment_main_user.xml" value="0.25" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/fragment_user_rv_bottom.xml" value="0.30103359173126615" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/fragment_user_rv_header.xml" value="0.2" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/lifecycle_exception.xml" value="0.2396593673965937" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/player_controller.xml" value="0.13" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/popupwindow_comment.xml" value="0.16" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/popupwindow_exit_app.xml" value="0.25" />
         <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/layout/popupwindow_record_status.xml" value="0.33" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml" value="0.4931640625" />
+        <entry key="..\:/WorkSpace/Git_WorkSpace/efunboxReader-android/efunboxReader-android-master/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.4699248120300752" />
       </map>
     </option>
   </component>

+ 15 - 1
app/build.gradle

@@ -53,6 +53,12 @@ android {
 
             }
         }
+        debug {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+            signingConfig signingConfigs.efunbox
+            zipAlignEnabled true
+        }
     }
 
 
@@ -63,7 +69,8 @@ android {
                     'src/main/res', //默认只有这一个路径
                     'src/fragmentRecommend',   //首页推荐
                     'src/fragmentUser',//首页我的
-                    'src/activityLoginAlert'//登录弹窗
+                    'src/activityLoginAlert',//登录弹窗
+                    'src/exception'//登录弹窗
             ]
         }
     }
@@ -127,8 +134,15 @@ dependencies {
 
     //rxBind
     implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
+    implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2'
+    implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2'
+
 
     implementation "androidx.constraintlayout:constraintlayout:2.1.1"
     // To use constraintlayout in compose
     implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-rc01"
+
+
+    //解除Android P 反射机制
+    implementation 'com.github.tiann:FreeReflection:3.1.0'
 }

+ 6 - 0
app/src/exception/drawable/divider.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <solid android:color="#e1e1e1" />
+    <size android:height="10dp" />
+</shape>

+ 6 - 0
app/src/exception/drawable/list_divider_horizontal.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/white" />
+    <size android:height="1dp" />
+</shape>

+ 7 - 0
app/src/exception/drawable/safe_mode_drawable.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <gradient
+        android:angle="-90"
+        android:startColor="#0f0" />
+</shape>

+ 19 - 0
app/src/exception/drawable/theme_stroke_selector.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+    <item android:color="@color/colorPrimary" android:state_pressed="true">
+        <shape>
+            <stroke android:width="2dp" android:color="@color/colorAccent" />
+            <solid android:color="@color/white" />
+            <corners android:radius="2dp" />
+        </shape>
+    </item>
+
+    <item android:color="@color/white">
+        <shape>
+            <stroke android:width="2dp" android:color="@color/colorAccent" />
+            <corners android:radius="2dp" />
+        </shape>
+    </item>
+</selector>

+ 66 - 0
app/src/exception/layout/activity_safe_mode_warning.xml

@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#000"
+        android:gravity="center"
+        android:orientation="vertical"
+        tools:context=".support.DebugSafeModeTipActivity">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="#ec0000"
+            android:padding="10dp"
+            android:text="WARNING"
+            android:textColor="#fff"
+            android:textSize="30dp"
+            android:textStyle="bold" />
+
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:gravity="center"
+            android:padding="15dp"
+            android:text="@string/debug_safe_mode"
+            android:textColor="#fff"
+            android:textSize="18dp"
+            android:textStyle="bold" />
+
+        <TextView
+            android:id="@+id/log"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:background="@drawable/theme_stroke_selector"
+            android:clickable="true"
+            android:gravity="center"
+            android:padding="15dp"
+            android:text="查看历史崩溃记录"
+            android:textColor="@drawable/theme_stroke_selector"
+            android:textSize="18dp"
+            android:textStyle="bold" />
+
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:gravity="center"
+            android:padding="12dp"
+            android:text="开发阶段建议弹出该Activity,以免遗漏bug。线上版本就不要展示该页面了。当看到该提示时就说明APP已经崩溃了,开发者可以手动杀进程,不要再让APP继续运行了"
+            android:textColor="#fff"
+            android:textSize="18dp"
+            android:textStyle="bold" />
+
+
+    </LinearLayout>
+</FrameLayout>

+ 21 - 0
app/src/exception/layout/fragment_crash_log.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#000"
+        android:orientation="vertical">
+
+    <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:padding="10dp"
+            android:text="崩溃历史记录"
+            android:textColor="@color/white"
+            android:textSize="20dp" />
+
+    <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/recyclerview"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>
+</LinearLayout>

+ 24 - 0
app/src/exception/layout/item.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="#fff"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    android:padding="10dp">
+
+    <ImageView
+        android:layout_width="80dp"
+        android:layout_height="80dp"
+        android:src="@mipmap/ic_launcher" />
+
+    <TextView
+        android:id="@+id/txt"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="10dp"
+        android:textColor="#000"
+        android:textSize="18sp"
+        tools:text="hello" />
+</LinearLayout>

+ 60 - 0
app/src/exception/layout/item_crash_log.xml

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="#000"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:padding="10dp">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+
+            android:textColor="@color/white"
+            android:textSize="18dp"
+            tools:text="标题" />
+
+        <TextView
+            android:id="@+id/copy"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/theme_stroke_selector"
+            android:padding="8dp"
+            android:text="复制"
+            android:textColor="@color/white"
+            android:textSize="14dp"
+            android:visibility="invisible" />
+
+    </LinearLayout>
+
+
+    <HorizontalScrollView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="5dp"
+        android:background="@drawable/theme_stroke_selector">
+
+        <EditText
+            android:id="@+id/content"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@null"
+            android:editable="false"
+            android:inputType="none"
+            android:padding="10dp"
+            android:paddingLeft="20dp"
+            android:textColor="@color/white"
+            android:textIsSelectable="true"
+            android:textSize="13dp"
+            android:textStyle="bold"
+            tools:text="内容。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。" />
+    </HorizontalScrollView>
+</LinearLayout>

+ 16 - 0
app/src/exception/layout/lifecycle_exception.xml

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/tv"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="1"
+        android:textColor="#f00"
+        android:textSize="30dp" />
+
+</LinearLayout>

+ 6 - 0
app/src/exception/values/strings.xml

@@ -0,0 +1,6 @@
+<resources>
+    <string name="debug_safe_mode">APP已经崩溃了,请告知开发者!</string>
+    <string name="safe_mode_tips">已经进入安全模式</string>
+    <string name="safe_mode_excep_tips">捕获到导致崩溃的异常</string>
+    <string name="safe_mode_black_screen_tips">黑屏了</string>
+</resources>

+ 21 - 6
app/src/main/AndroidManifest.xml

@@ -38,9 +38,13 @@
                 android:maxAspectRatio="2.1"
                 android:resizeableActivity="true"
                 android:screenOrientation="landscape"
-                android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"
+                android:theme="@style/AppStartTheme"
                 android:windowSoftInputMode="adjustNothing|stateHidden">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
 
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
         </activity> <!-- 录音界面 -->
         <activity
                 android:name=".activity.RecordActivity"
@@ -60,11 +64,7 @@
                 android:screenOrientation="landscape"
                 android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"
                 android:windowSoftInputMode="adjustNothing|stateHidden">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
 
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
 
         </activity> <!-- 登录界面 -->
         <activity
@@ -182,7 +182,22 @@
                 android:resizeableActivity="true"
                 android:screenOrientation="landscape"
                 android:theme="@style/efunboxTransparentLoginAlert"
-                android:windowSoftInputMode="adjustNothing|stateHidden" /> <!-- 友盟start -->
+                android:windowSoftInputMode="adjustNothing|stateHidden" />
+
+
+        <activity
+                android:name=".support.DebugSafeModeTipActivity"
+                android:configChanges="screenLayout|screenSize|keyboardHidden|keyboard|orientation"
+                android:label=""
+                android:launchMode="singleTask"
+                android:maxAspectRatio="2.1"
+                android:resizeableActivity="true"
+                android:screenOrientation="landscape"
+                android:theme="@style/efunboxTransparentLoginAlert"
+                android:windowSoftInputMode="adjustNothing|stateHidden"></activity>
+
+
+        <!-- 友盟start -->
         <meta-data
                 android:name="UMENG_APPKEY"
                 android:value="5e34d2fb4ca3574b1800005b" />

+ 13 - 37
app/src/main/java/com/edufound/reader/activity/CrashDialogActivity.java

@@ -3,25 +3,17 @@ package com.edufound.reader.activity;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.DialogInterface;
-import android.util.DisplayMetrics;
 import android.view.ViewGroup;
-import android.widget.GridView;
-import android.widget.LinearLayout;
 
 import com.edufound.reader.R;
-import com.edufound.reader.adapter.TestGridAdapter;
-import com.edufound.reader.annotation.BindView;
 import com.edufound.reader.application.EApplication;
 import com.edufound.reader.base.BaseMvpActivity;
 import com.edufound.reader.contract.CrashDialogContract;
-import com.edufound.reader.cusview.AblGridView;
 import com.edufound.reader.presenter.CrashDialogPresenter;
 
 public class CrashDialogActivity extends BaseMvpActivity<CrashDialogPresenter> implements CrashDialogContract.View {
 
     Activity mActivity;
-    @BindView(id = R.id.test_gridview)
-    AblGridView mGridView;
 
     @Override
     public int getLayoutId() {
@@ -33,35 +25,19 @@ public class CrashDialogActivity extends BaseMvpActivity<CrashDialogPresenter> i
         mPresenter = new CrashDialogPresenter();
         mPresenter.attachView(this);
         mActivity = this;
-//        AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
-//        builder.setTitle("error");
-//        builder.setIcon(R.drawable.icon);
-//        builder.setMessage("出现异常");
-//        builder.setNegativeButton("退出", new DialogInterface.OnClickListener() {
-//            @Override
-//            public void onClick(DialogInterface dialogInterface, int i) {
-//                dialogInterface.dismiss();
-//                EApplication.killAppProcess(mActivity);
-//            }
-//        });
-//        builder.create().show();
-
-        int item = 50;
-        TestGridAdapter adapter = new TestGridAdapter(mActivity);
-        int length = 100;
-        DisplayMetrics dm = new DisplayMetrics();
-        getWindowManager().getDefaultDisplay().getMetrics(dm);
-        float density = dm.density;
-        int gridviewWidth = (int) (100 * (length + 4) * density);
-        int itemWidth = (int) (length * density);
-        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
-                gridviewWidth, LinearLayout.LayoutParams.FILL_PARENT);
-        mGridView.setLayoutParams(params); // 设置GirdView布局参数,横向布局的关键
-        mGridView.setColumnWidth(itemWidth); // 设置列表项宽
-        mGridView.setHorizontalSpacing(5); // 设置列表项水平间距
-        mGridView.setStretchMode(GridView.NO_STRETCH);
-        mGridView.setNumColumns(item / 2); // 设置列数量=列表集合数
-        mGridView.setAdapter(adapter);
+        AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
+        builder.setTitle("error");
+        builder.setIcon(R.drawable.icon);
+        builder.setMessage("出现异常");
+        builder.setNegativeButton("退出", new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialogInterface, int i) {
+                dialogInterface.dismiss();
+                EApplication.killAppProcess(mActivity);
+            }
+        });
+        builder.create().show();
+
 
     }
 

+ 37 - 0
app/src/main/java/com/edufound/reader/activity/LoginAlertActivity.java

@@ -1,8 +1,11 @@
 package com.edufound.reader.activity;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
+import android.content.Context;
 import android.os.Process;
 import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.CompoundButton;
 import android.widget.EditText;
 import android.widget.FrameLayout;
@@ -16,9 +19,13 @@ import com.edufound.reader.base.BaseActivity;
 import com.edufound.reader.base.BaseMvpActivity;
 import com.edufound.reader.contract.LoginAlertContract;
 import com.edufound.reader.presenter.LoginAlertPresenter;
+import com.edufound.reader.util.Consts;
+import com.jakewharton.rxbinding4.view.RxView;
+import com.jakewharton.rxbinding4.widget.RxTextView;
 
 import androidx.appcompat.widget.AppCompatCheckBox;
 import androidx.constraintlayout.widget.ConstraintLayout;
+import io.reactivex.rxjava3.functions.Consumer;
 
 public class LoginAlertActivity extends BaseMvpActivity<LoginAlertPresenter> implements LoginAlertContract.View {
 
@@ -48,6 +55,7 @@ public class LoginAlertActivity extends BaseMvpActivity<LoginAlertPresenter> imp
         return R.layout.activity_alert_login;
     }
 
+    @SuppressLint("AutoDispose")
     @Override
     public void initView() {
         mActivity = this;
@@ -64,6 +72,31 @@ public class LoginAlertActivity extends BaseMvpActivity<LoginAlertPresenter> imp
         addUiClickListener(mLoginBtn, o -> {
             mPresenter.Login(mEditPhone.getText().toString(), mEditVCode.getText().toString());
         });
+        RxTextView.textChanges(mEditPhone).subscribe(new Consumer<CharSequence>() {
+            @Override
+            public void accept(CharSequence text) throws Exception {
+            }
+        });
+        RxTextView.textChanges(mEditVCode).subscribe(new Consumer<CharSequence>() {
+            @Override
+            public void accept(CharSequence text) throws Exception {
+            }
+        });
+
+        RxView.focusChanges(mEditPhone).subscribe(hasFocus -> {
+            if (!hasFocus) {
+                InputMethodManager manager = ((InputMethodManager) Consts.getmApplicAtion().getSystemService(Context.INPUT_METHOD_SERVICE));
+                if (manager != null)
+                    manager.hideSoftInputFromWindow(mEditPhone.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+            }
+        });
+        RxView.focusChanges(mEditVCode).subscribe(hasFocus -> {
+            if (!hasFocus) {
+                InputMethodManager manager = ((InputMethodManager) Consts.getmApplicAtion().getSystemService(Context.INPUT_METHOD_SERVICE));
+                if (manager != null)
+                    manager.hideSoftInputFromWindow(mEditVCode.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+            }
+        });
     }
 
     @Override
@@ -119,6 +152,10 @@ public class LoginAlertActivity extends BaseMvpActivity<LoginAlertPresenter> imp
 
     @Override
     protected void onDestroy() {
+        InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+        if (imm != null) {
+            imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
+        }
         super.onDestroy();
         mPresenter.activityDestory();
     }

+ 4 - 0
app/src/main/java/com/edufound/reader/activity/MainActivity.java

@@ -37,6 +37,7 @@ public class MainActivity extends BaseMvpActivity<MainPresenter> implements Main
         mPresenter = new MainPresenter(getSupportFragmentManager());
         mPresenter.attachView(this);
         mActivity = this;
+//        mRadioGroupTab = null;
         mRadioGroupTab.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
             @Override
             public void onCheckedChanged(RadioGroup radioGroup, int id) {
@@ -45,6 +46,7 @@ public class MainActivity extends BaseMvpActivity<MainPresenter> implements Main
         });
         int defaultIndex = getIntent().getIntExtra("defaultIndex", 1);
         ((RadioButton) mRadioGroupTab.getChildAt(defaultIndex)).setChecked(true);
+        mPresenter.checkModelIsDebug();
 
     }
 
@@ -125,4 +127,6 @@ public class MainActivity extends BaseMvpActivity<MainPresenter> implements Main
     public ViewGroup getRootView() {
         return findViewById(android.R.id.content);
     }
+
+
 }

+ 36 - 7
app/src/main/java/com/edufound/reader/adapter/MyCollectionItemAdapter.java

@@ -7,15 +7,20 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.edufound.reader.R;
+import com.edufound.reader.listener.RecyclerItemClickListener;
 import com.edufound.reader.util.GlideUtils;
+import com.jakewharton.rxbinding4.view.RxView;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.RecyclerView;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import kotlin.Unit;
 
 public class MyCollectionItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
@@ -25,6 +30,7 @@ public class MyCollectionItemAdapter extends RecyclerView.Adapter<RecyclerView.V
     private LayoutInflater mLayoutInflater;
     private Context mContext;
     private List<Object> mListData;
+    private RecyclerItemClickListener mRecyclerItemClickListener;
 
     public MyCollectionItemAdapter(Context context, List<Object> listData) {
         mContext = context;
@@ -38,6 +44,11 @@ public class MyCollectionItemAdapter extends RecyclerView.Adapter<RecyclerView.V
         mListData = listData;
     }
 
+
+    public void setOnItemClickListener(RecyclerItemClickListener listener) {
+        mRecyclerItemClickListener = listener;
+    }
+
     @Override
     public int getItemViewType(int position) {
         return position;
@@ -54,12 +65,30 @@ public class MyCollectionItemAdapter extends RecyclerView.Adapter<RecyclerView.V
     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {
         ((MyCollectionItemHolder) holder).mItemName.setText(String.valueOf(mListData.get(position)));
         GlideUtils.loadImage(mContext, "http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640", ((MyCollectionItemHolder) holder).mItemIcon);
-        ((MyCollectionItemHolder) holder).mItemView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                Toast.makeText(mContext, "click :" + position, Toast.LENGTH_SHORT).show();
-            }
-        });
+        if (mRecyclerItemClickListener != null) {
+
+            RxView.clicks(((MyCollectionItemHolder) holder).mItemView).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Observer<Unit>() {
+                @Override
+                public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
+
+                }
+
+                @Override
+                public void onNext(@io.reactivex.rxjava3.annotations.NonNull Unit unit) {
+                    mRecyclerItemClickListener.onClickListener(position, ((MyCollectionItemHolder) holder).mItemView);
+                }
+
+                @Override
+                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
+
+                }
+
+                @Override
+                public void onComplete() {
+
+                }
+            });
+        }
     }
 
     @Override

+ 34 - 9
app/src/main/java/com/edufound/reader/adapter/MyFollowItemAdapter.java

@@ -12,12 +12,18 @@ import android.widget.Toast;
 
 import com.edufound.reader.R;
 import com.edufound.reader.activity.OthersRecordActivity;
+import com.edufound.reader.listener.RecyclerItemClickListener;
 import com.edufound.reader.util.GlideUtils;
+import com.jakewharton.rxbinding4.view.RxView;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import androidx.annotation.NonNull;
 import androidx.recyclerview.widget.RecyclerView;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import kotlin.Unit;
 
 public class MyFollowItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
 
@@ -29,6 +35,7 @@ public class MyFollowItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
     private List<Object> mListData;
     private int mHeaderCount = 0;//头部View个数
     private int mBottomCount = 0;//底部View个数
+    private RecyclerItemClickListener mRecyclerItemClickListener;
 
     public MyFollowItemAdapter(Context context, List<Object> listData) {
         mContext = context;
@@ -89,22 +96,40 @@ public class MyFollowItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
 
     }
 
+    public void setOnItemClickListener(RecyclerItemClickListener listener) {
+        mRecyclerItemClickListener = listener;
+    }
+
     @Override
     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, @SuppressLint("RecyclerView") int position) {
         if (holder instanceof MyCollectionHeaderViewHolder) {
 
         } else if (holder instanceof MyFollowItemHolder) {
             ((MyFollowItemHolder) holder).mItemName.setText(String.valueOf(mListData.get(position - mHeaderCount)));
-            ((MyFollowItemHolder) holder).mItemView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    Toast.makeText(mContext, "click:" + position, Toast.LENGTH_SHORT).show();
-                    Intent intent = new Intent(mContext, OthersRecordActivity.class);
-                    intent.putExtra("userId", position);
-                    mContext.startActivity(intent);
-                }
-            });
+            if (mRecyclerItemClickListener != null) {
+
+                RxView.clicks(((MyFollowItemHolder) holder).mItemView).throttleFirst(2, TimeUnit.SECONDS).subscribe(new Observer<Unit>() {
+                    @Override
+                    public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
+
+                    }
+
+                    @Override
+                    public void onNext(@io.reactivex.rxjava3.annotations.NonNull Unit unit) {
+                        mRecyclerItemClickListener.onClickListener(position, ((MyFollowItemHolder) holder).mItemView);
+                    }
+
+                    @Override
+                    public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
+
+                    }
+
+                    @Override
+                    public void onComplete() {
 
+                    }
+                });
+            }
         } else if (holder instanceof MyCollectionBottomViewHolder) {
 
         }

+ 0 - 45
app/src/main/java/com/edufound/reader/adapter/TestGridAdapter.java

@@ -1,45 +0,0 @@
-package com.edufound.reader.adapter;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.GridLayout;
-import android.widget.LinearLayout;
-import android.widget.Space;
-import android.widget.TextView;
-
-public class TestGridAdapter extends BaseAdapter {
-    Context mContext;
-
-    public TestGridAdapter(Context context) {
-        mContext = context;
-    }
-
-    @Override
-    public int getCount() {
-        return 50;
-    }
-
-    @Override
-    public Object getItem(int i) {
-        return i;
-    }
-
-    @Override
-    public long getItemId(int i) {
-        return i;
-    }
-
-    @Override
-    public View getView(int i, View view, ViewGroup viewGroup) {
-        TextView tv = new TextView(mContext);
-        tv.setText("i==============" + i);
-        GridLayout.LayoutParams mLayoutParams = new GridLayout.LayoutParams();
-        mLayoutParams.columnSpec = GridLayout.spec(GridLayout.UNDEFINED, 1, 1.0f);
-        mLayoutParams.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, 1, 1.0f);
-        tv.setLayoutParams(mLayoutParams);
-
-        return tv;
-    }
-}

+ 71 - 1
app/src/main/java/com/edufound/reader/application/EApplication.java

@@ -4,13 +4,24 @@ import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Application;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
 import android.os.Process;
-
+import android.widget.Toast;
+
+import com.edufound.reader.BuildConfig;
+import com.edufound.reader.R;
+import com.edufound.reader.support.CrashLog;
+import com.edufound.reader.support.DebugSafeModeTipActivity;
+import com.edufound.reader.support.DebugSafeModeUI;
+import com.edufound.reader.util.Cockroach;
 import com.edufound.reader.util.Consts;
 import com.edufound.reader.util.CrashHandler;
+import com.edufound.reader.util.ExceptionHandler;
 import com.edufound.reader.util.HttpInterceptor;
 import com.okhttplib.OkHttpUtil;
 import com.okhttplib.annotation.CacheType;
@@ -45,10 +56,12 @@ public class EApplication extends Application {
     public void onCreate() {
         super.onCreate();
         try {
+            Consts.setIsDebug(true);
             Consts.setmApplicAtion(this);
 
             //初始化异常监听
 //            CrashHandler.getInstance().init(this);
+            initException();
 
             XmlPullParserFactory.newInstance().setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
             //初始化OKHTTP
@@ -157,4 +170,61 @@ public class EApplication extends Application {
         public void onActivityDestroyed(Activity activity) {
         }
     };
+
+    private void initException() {
+        final Thread.UncaughtExceptionHandler sysExcepHandler = Thread.getDefaultUncaughtExceptionHandler();
+        final Toast toast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
+        DebugSafeModeUI.init(this);
+        Cockroach.install(this, new ExceptionHandler() {
+            @Override
+            protected void onUncaughtExceptionHappened(Thread thread, Throwable throwable) {
+                CrashLog.saveCrashLog(getApplicationContext(), throwable);
+                new Handler(Looper.getMainLooper()).post(new Runnable() {
+                    @Override
+                    public void run() {
+                        toast.setText(R.string.safe_mode_excep_tips);
+                        toast.show();
+                    }
+                });
+            }
+
+            @Override
+            protected void onBandageExceptionHappened(Throwable throwable) {
+                throwable.printStackTrace();//打印警告级别log,该throwable可能是最开始的bug导致的,无需关心
+                toast.setText("Cockroach Worked");
+                toast.show();
+            }
+
+            @Override
+            protected void onEnterSafeMode() {
+                int tips = R.string.safe_mode_tips;
+                Toast.makeText(Consts.getmApplicAtion(), getResources().getString(tips), Toast.LENGTH_LONG).show();
+                DebugSafeModeUI.showSafeModeUI();
+
+                if (Consts.isIsDebug()) {
+                    Intent intent = new Intent(Consts.getmApplicAtion(), DebugSafeModeTipActivity.class);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    startActivity(intent);
+                }
+//                if (BuildConfig.DEBUG) {
+//                    Intent intent = new Intent(Consts.getmApplicAtion(), DebugSafeModeTipActivity.class);
+//                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+//                    startActivity(intent);
+//                } else {
+//                    Intent intent = new Intent(Consts.getmApplicAtion(), DebugSafeModeTipActivity.class);
+//                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+//                    startActivity(intent);
+//                }
+            }
+
+            @Override
+            protected void onMayBeBlackScreen(Throwable e) {
+                Thread thread = Looper.getMainLooper().getThread();
+                //黑屏时建议直接杀死app
+                sysExcepHandler.uncaughtException(thread, new RuntimeException("black screen"));
+            }
+
+        });
+
+    }
 }

+ 2 - 0
app/src/main/java/com/edufound/reader/contract/MainContract.java

@@ -23,5 +23,7 @@ public interface MainContract {
         void activityPause();
 
         void activityResume();
+
+        void checkModelIsDebug();
     }
 }

+ 2 - 0
app/src/main/java/com/edufound/reader/contract/MyTabFragmentContract.java

@@ -21,6 +21,8 @@ public interface MyTabFragmentContract {
 
         void setUserInfo(UserInfoBean bean);
 
+        void loadMoreItem();
+
     }
 
     interface Presenter {

+ 7 - 2
app/src/main/java/com/edufound/reader/cusview/RvListJzvdStd.java

@@ -951,13 +951,18 @@ public class RvListJzvdStd extends Jzvd {
     @Override
     public void onError(int what, int extra) {
         super.onError(what, extra);
-        this.mCallBack.onError(what, extra);
+        if (this.mCallBack != null) {
+            this.mCallBack.onError(what, extra);
+        }
+
     }
 
     @Override
     public void onInfo(int what, int extra) {
         super.onInfo(what, extra);
-        this.mCallBack.onInfo(what, extra);
+        if (this.mCallBack != null) {
+            this.mCallBack.onInfo(what, extra);
+        }
     }
 
     @Override

+ 15 - 10
app/src/main/java/com/edufound/reader/fragment/CharacterFragment.java

@@ -1,5 +1,6 @@
 package com.edufound.reader.fragment;
 
+import android.annotation.SuppressLint;
 import android.graphics.Rect;
 import android.os.Build;
 import android.view.View;
@@ -14,6 +15,10 @@ import com.edufound.reader.base.BaseMvpFragment;
 import com.edufound.reader.contract.CharacterFragmentContract;
 import com.edufound.reader.presenter.CharacterFragmentPresenter;
 import com.edufound.reader.util.Consts;
+import com.jakewharton.rxbinding4.view.RxView;
+import com.jakewharton.rxbinding4.view.RxViewGroup;
+import com.jakewharton.rxbinding4.view.ViewGroupHierarchyChangeEvent;
+import com.orhanobut.logger.Logger;
 
 import androidx.annotation.RequiresApi;
 import io.reactivex.rxjava3.functions.Consumer;
@@ -51,22 +56,22 @@ public class CharacterFragment extends BaseMvpFragment<CharacterFragmentPresente
         return R.layout.fragment_main_character;
     }
 
+    @SuppressLint("AutoDispose")
     @RequiresApi(api = Build.VERSION_CODES.M)
     @Override
     protected void initViewListener() {
-        mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
-            @Override
-            public void onScrollChange(View view, int x, int y, int oldx, int oldy) {
-                if (mBottomView.getLocalVisibleRect(mScreenRect)) {
-                    if (isNeedLoad) {
-                        isNeedLoad = false;
-                        mPresenter.initGridLayout(mGridLayout);
-                    }
-                } else {
-                    isNeedLoad = true;
+        RxView.scrollChangeEvents(mScrollView).subscribe(viewScrollChangeEvent -> {
+            if (mBottomView.getLocalVisibleRect(mScreenRect)) {
+                if (isNeedLoad) {
+                    isNeedLoad = false;
+                    mPresenter.initGridLayout(mGridLayout);
                 }
+            } else {
+                isNeedLoad = true;
             }
         });
+
+    
     }
 
     @Override

+ 54 - 15
app/src/main/java/com/edufound/reader/fragment/MyTabFragment.java

@@ -1,8 +1,11 @@
 package com.edufound.reader.fragment;
 
+import android.animation.LayoutTransition;
+import android.annotation.SuppressLint;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -28,11 +31,26 @@ import com.edufound.reader.contract.MyTabFragmentContract;
 import com.edufound.reader.presenter.MyTabFragmentPresenter;
 import com.edufound.reader.util.Consts;
 import com.edufound.reader.util.GlideUtils;
+import com.jakewharton.rxbinding4.view.RxView;
+import com.jakewharton.rxbinding4.view.RxViewGroup;
+import com.jakewharton.rxbinding4.view.ViewGroupHierarchyChangeEvent;
+import com.jakewharton.rxbinding4.view.ViewGroupHierarchyChildViewAddEvent;
+import com.jakewharton.rxbinding4.view.ViewGroupHierarchyChildViewRemoveEvent;
 import com.orhanobut.logger.Logger;
+import com.trello.rxlifecycle4.android.ActivityEvent;
+import com.trello.rxlifecycle4.android.RxLifecycleAndroid;
+
+import java.util.concurrent.TimeUnit;
 
 import androidx.annotation.RequiresApi;
+import androidx.lifecycle.Lifecycle;
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.Observer;
 import io.reactivex.rxjava3.functions.Consumer;
 
+import static com.trello.rxlifecycle4.RxLifecycle.bindUntilEvent;
+
 public class MyTabFragment extends BaseMvpFragment<MyTabFragmentPresenter> implements MyTabFragmentContract.View {
 
 
@@ -97,26 +115,35 @@ public class MyTabFragment extends BaseMvpFragment<MyTabFragmentPresenter> imple
         return R.layout.fragment_main_user;
     }
 
+    @SuppressLint("AutoDispose")
     @RequiresApi(api = Build.VERSION_CODES.M)
     @Override
     protected void initViewListener() {
-        mScrollView.setOnScrollChangeListener(new View.OnScrollChangeListener() {
-            @Override
-            public void onScrollChange(View view, int x, int y, int oldx, int oldy) {
-                if (mBottomView.getLocalVisibleRect(mScreenRect)) {
-                    if (isNeedLoad) {
-                        isNeedLoad = false;
-                        mPresenter.initGridLayout(mGridLayout, mNoRecordLayout);
-                    }
-                } else {
-                    isNeedLoad = true;
-                }
-            }
-        });
 
-        addUiClick(mHeadUserSetting, o -> {
-            Toast.makeText(getActivity(), "click 设置", Toast.LENGTH_SHORT).show();
+
+        RxView.scrollChangeEvents(mScrollView).subscribe(viewScrollChangeEvent -> {
+            loadMoreItem();
         });
+
+//        RxViewGroup.changeEvents(mGridLayout).subscribe(viewGroupHierarchyChangeEvent -> {
+//            loadMoreItem();
+//        });
+
+//        Observable observable = RxView.clicks(mHeadUserSetting).share();
+//        observable.buffer(observable.debounce(200, TimeUnit.MILLISECONDS).compose(bindUntilEvent(new Observable<ActivityEvent>() {
+//            @Override
+//            protected void subscribeActual(@NonNull Observer<? super ActivityEvent> observer) {
+//                Logger.e("subscribeActual--subscribeActual--subscribeActual");
+//            }
+//        }, ActivityEvent.STOP)))
+//                .subscribe(list -> {
+//                    Logger.e("iv3连续点击次数:" + list.size());
+//                });//这里的时间指的是任意两次点击最长间隔时间);
+
+
+//        addUiClick(mHeadUserSetting, o -> {
+//            Toast.makeText(getActivity(), "click 设置", Toast.LENGTH_SHORT).show();
+//        });
         addUiClick(mHeadUserVip, o -> {
             Toast.makeText(getActivity(), "click vip", Toast.LENGTH_SHORT).show();
             toNextActivity(PayActivity.class);
@@ -194,4 +221,16 @@ public class MyTabFragment extends BaseMvpFragment<MyTabFragmentPresenter> imple
         super.onDestroyView();
         mPresenter.onDestory(mGridLayout);
     }
+
+    @Override
+    public void loadMoreItem() {
+        if (mBottomView.getLocalVisibleRect(mScreenRect) || mGridLayout.getChildCount() <= 2) {
+            if (isNeedLoad) {
+                isNeedLoad = false;
+                mPresenter.initGridLayout(mGridLayout, mNoRecordLayout);
+            }
+        } else {
+            isNeedLoad = true;
+        }
+    }
 }

+ 81 - 0
app/src/main/java/com/edufound/reader/listener/ActivityKillerV15_V20.java

@@ -0,0 +1,81 @@
+package com.edufound.reader.listener;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Message;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Created by wanjian on 2018/5/24.
+ * <p>
+ */
+
+public class ActivityKillerV15_V20 implements IActivityKiller {
+
+
+    @Override
+    public void finishLaunchActivity(Message message) {
+        try {
+            Object activityClientRecord = message.obj;
+
+            Field tokenField = activityClientRecord.getClass().getDeclaredField("token");
+
+            tokenField.setAccessible(true);
+            IBinder binder = (IBinder) tokenField.get(activityClientRecord);
+            finish(binder);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishResumeActivity(Message message) {
+
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishPauseActivity(Message message) {
+
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void finishStopActivity(Message message) {
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private void finish(IBinder binder) throws Exception {
+
+        Class activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
+
+        Method getDefaultMethod = activityManagerNativeClass.getDeclaredMethod("getDefault");
+
+        Object activityManager = getDefaultMethod.invoke(null);
+
+
+        Method finishActivityMethod = activityManager.getClass().getDeclaredMethod("finishActivity", IBinder.class, int.class, Intent.class);
+        finishActivityMethod.invoke(activityManager, binder, Activity.RESULT_CANCELED, null);
+
+    }
+
+}

+ 77 - 0
app/src/main/java/com/edufound/reader/listener/ActivityKillerV21_V23.java

@@ -0,0 +1,77 @@
+package com.edufound.reader.listener;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Message;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+public class ActivityKillerV21_V23 implements IActivityKiller {
+
+
+    @Override
+    public void finishLaunchActivity(Message message) {
+        try {
+            Object activityClientRecord = message.obj;
+
+            Field tokenField = activityClientRecord.getClass().getDeclaredField("token");
+
+            tokenField.setAccessible(true);
+            IBinder binder = (IBinder) tokenField.get(activityClientRecord);
+            finish(binder);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishResumeActivity(Message message) {
+
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishPauseActivity(Message message) {
+
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void finishStopActivity(Message message) {
+        try {
+            finish((IBinder) message.obj);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private void finish(IBinder binder) throws Exception {
+
+        Class activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
+
+        Method getDefaultMethod = activityManagerNativeClass.getDeclaredMethod("getDefault");
+
+        Object activityManager = getDefaultMethod.invoke(null);
+
+
+        Method finishActivityMethod = activityManager.getClass().getDeclaredMethod("finishActivity", IBinder.class, int.class, Intent.class, boolean.class);
+        finishActivityMethod.invoke(activityManager, binder, Activity.RESULT_CANCELED, null, false);
+
+    }
+
+}

+ 82 - 0
app/src/main/java/com/edufound/reader/listener/ActivityKillerV24_V25.java

@@ -0,0 +1,82 @@
+package com.edufound.reader.listener;
+
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Message;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+public class ActivityKillerV24_V25 implements IActivityKiller {
+
+
+    @Override
+    public void finishLaunchActivity(Message message) {
+        try {
+            Object activityClientRecord = message.obj;
+
+            Field tokenField = activityClientRecord.getClass().getDeclaredField("token");
+
+            tokenField.setAccessible(true);
+            IBinder binder = (IBinder) tokenField.get(activityClientRecord);
+            finish(binder);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishResumeActivity(Message message) {
+
+        finishSomeArgs(message);
+    }
+
+
+    @Override
+    public void finishPauseActivity(Message message) {
+
+        finishSomeArgs(message);
+    }
+
+    @Override
+    public void finishStopActivity(Message message) {
+        finishSomeArgs(message);
+    }
+
+
+    private void finishSomeArgs(Message message) {
+        try {
+            Object someArgs = message.obj;
+            Field arg1Field = someArgs.getClass().getDeclaredField("arg1");
+            arg1Field.setAccessible(true);
+            IBinder binder = (IBinder) arg1Field.get(someArgs);
+            finish(binder);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+
+    private void finish(IBinder binder) throws Exception {
+
+        /*
+         ActivityManagerNative.getDefault()
+                 .finishActivity(r.token, Activity.RESULT_CANCELED, null, Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
+         */
+        Class activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
+
+        Method getDefaultMethod = activityManagerNativeClass.getDeclaredMethod("getDefault");
+
+        Object activityManager = getDefaultMethod.invoke(null);
+
+
+        Method finishActivityMethod = activityManager.getClass().getDeclaredMethod("finishActivity", IBinder.class, int.class, Intent.class, int.class);
+        int DONT_FINISH_TASK_WITH_ACTIVITY = 0;
+        finishActivityMethod.invoke(activityManager, binder, Activity.RESULT_CANCELED, null, DONT_FINISH_TASK_WITH_ACTIVITY);
+
+    }
+
+}

+ 81 - 0
app/src/main/java/com/edufound/reader/listener/ActivityKillerV26.java

@@ -0,0 +1,81 @@
+package com.edufound.reader.listener;
+
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Message;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Created by wanjian on 2018/5/24.
+ * <p>
+ * <p>
+ * handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,msg.arg2, false);
+ * ActivityManager.getService().finishActivity(mToken, resultCode, resultData, finishTask)
+ */
+
+public class ActivityKillerV26 implements IActivityKiller {
+
+
+    @Override
+    public void finishLaunchActivity(Message message) {
+        try {
+            Object activityClientRecord = message.obj;
+
+            Field tokenField = activityClientRecord.getClass().getDeclaredField("token");
+
+            tokenField.setAccessible(true);
+            IBinder binder = (IBinder) tokenField.get(activityClientRecord);
+            finish(binder);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    public void finishResumeActivity(Message message) {
+
+        finishSomeArgs(message);
+    }
+
+
+    @Override
+    public void finishPauseActivity(Message message) {
+
+        finishSomeArgs(message);
+    }
+
+    @Override
+    public void finishStopActivity(Message message) {
+        finishSomeArgs(message);
+    }
+
+
+    private void finishSomeArgs(Message message) {
+        try {
+            Object someArgs = message.obj;
+            Field arg1Field = someArgs.getClass().getDeclaredField("arg1");
+            arg1Field.setAccessible(true);
+            IBinder binder = (IBinder) arg1Field.get(someArgs);
+            finish(binder);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+
+    private void finish(IBinder binder) throws Exception {
+        Method getServiceMethod = ActivityManager.class.getDeclaredMethod("getService");
+        Object activityManager = getServiceMethod.invoke(null);
+
+        Method finishActivityMethod = activityManager.getClass().getDeclaredMethod("finishActivity", IBinder.class, int.class, Intent.class, int.class);
+        finishActivityMethod.setAccessible(true);
+        int DONT_FINISH_TASK_WITH_ACTIVITY = 0;
+        finishActivityMethod.invoke(activityManager, binder, Activity.RESULT_CANCELED, null, DONT_FINISH_TASK_WITH_ACTIVITY);
+
+    }
+}

+ 91 - 0
app/src/main/java/com/edufound/reader/listener/ActivityKillerV28.java

@@ -0,0 +1,91 @@
+package com.edufound.reader.listener;
+
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Message;
+
+import com.edufound.reader.support.ClientTransaction;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+
+public class ActivityKillerV28 implements IActivityKiller {
+
+
+    @Override
+    public void finishLaunchActivity(Message message) {
+
+        try {
+            tryFinish1(message);
+            return;
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+
+        try {
+            tryFinish2(message);
+            return;
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+
+        try {
+            tryFinish3(message);
+            return;
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+
+    }
+
+    private void tryFinish1(Message message) throws Throwable {
+        ClientTransaction clientTransaction = (ClientTransaction) message.obj;
+        IBinder binder = clientTransaction.getActivityToken();
+        finish(binder);
+    }
+
+    private void tryFinish3(Message message) throws Throwable {
+        Object clientTransaction = message.obj;
+        Field mActivityTokenField = clientTransaction.getClass().getDeclaredField("mActivityToken");
+        IBinder binder = (IBinder) mActivityTokenField.get(clientTransaction);
+        finish(binder);
+    }
+
+    private void tryFinish2(Message message) throws Throwable {
+        Object clientTransaction = message.obj;
+        Method getActivityTokenMethod = clientTransaction.getClass().getDeclaredMethod("getActivityToken");
+        IBinder binder = (IBinder) getActivityTokenMethod.invoke(clientTransaction);
+        finish(binder);
+    }
+
+
+    @Override
+    public void finishResumeActivity(Message message) {
+
+    }
+
+
+    @Override
+    public void finishPauseActivity(Message message) {
+
+    }
+
+    @Override
+    public void finishStopActivity(Message message) {
+    }
+
+    private void finish(IBinder binder) throws Exception {
+        Method getServiceMethod = ActivityManager.class.getDeclaredMethod("getService");
+        Object activityManager = getServiceMethod.invoke(null);
+
+        Method finishActivityMethod = activityManager.getClass().getDeclaredMethod("finishActivity", IBinder.class, int.class, Intent.class, int.class);
+        finishActivityMethod.setAccessible(true);
+        int DONT_FINISH_TASK_WITH_ACTIVITY = 0;
+        finishActivityMethod.invoke(activityManager, binder, Activity.RESULT_CANCELED, null, DONT_FINISH_TASK_WITH_ACTIVITY);
+
+    }
+}

+ 17 - 0
app/src/main/java/com/edufound/reader/listener/IActivityKiller.java

@@ -0,0 +1,17 @@
+package com.edufound.reader.listener;
+
+
+import android.os.Message;
+
+public interface IActivityKiller {
+
+    void finishLaunchActivity(Message message);
+
+    void finishResumeActivity(Message message);
+
+    void finishPauseActivity(Message message);
+
+    void finishStopActivity(Message message);
+
+
+}

+ 7 - 0
app/src/main/java/com/edufound/reader/listener/RecyclerItemClickListener.java

@@ -0,0 +1,7 @@
+package com.edufound.reader.listener;
+
+import android.view.View;
+
+public interface RecyclerItemClickListener {
+    void onClickListener(int position, View view);
+}

+ 39 - 66
app/src/main/java/com/edufound/reader/popwindow/PopWindowUtil.java

@@ -15,8 +15,13 @@ import com.edufound.reader.cusview.GridRadioGroup;
 import com.edufound.reader.listener.PopUtilClickListener;
 import com.edufound.reader.listener.PopupRecordStatusListener;
 import com.edufound.reader.presenter.PopWindowPresneter;
+import com.jakewharton.rxbinding4.view.RxView;
 import com.orhanobut.logger.Logger;
 
+import java.util.concurrent.TimeUnit;
+
+import io.reactivex.rxjava3.functions.Consumer;
+
 public class PopWindowUtil {
     private static PopWindowPresneter mPresenter;
     private static PopupWindow mPopupWindow;
@@ -52,17 +57,11 @@ public class PopWindowUtil {
         ImageView image = dialog_view.findViewById(R.id.popupwindow_exit_app_image);
         FrameLayout exit = dialog_view.findViewById(R.id.popupwindow_exit_app_ok);
         FrameLayout cancel = dialog_view.findViewById(R.id.popupwindow_exit_app_cancel);
-        exit.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                EApplication.killAppProcess(context);
-            }
+        setClickListener(exit, o -> {
+            EApplication.killAppProcess(context);
         });
-        cancel.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-            }
+        setClickListener(cancel, o -> {
+            mPopupWindow.dismiss();
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -106,12 +105,9 @@ public class PopWindowUtil {
                 checkText[0] = String.valueOf(checkedId);
             }
         });
-        btn_ok.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickSubmit(checkText[0]);
-            }
+        setClickListener(btn_ok, o -> {
+            mPopupWindow.dismiss();
+            listener.clickSubmit(checkText[0]);
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -129,18 +125,12 @@ public class PopWindowUtil {
         ImageView image = dialog_view.findViewById(R.id.popupwindow_exit_login_image);
         FrameLayout exit = dialog_view.findViewById(R.id.popupwindow_exit_login_ok);
         FrameLayout cancel = dialog_view.findViewById(R.id.popupwindow_exit_login_cancel);
-        exit.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                listener.clickSubmit(null);
-            }
+        setClickListener(exit, o -> {
+            listener.clickSubmit(null);
         });
-        cancel.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickCancel();
-            }
+        setClickListener(cancel, o -> {
+            mPopupWindow.dismiss();
+            listener.clickCancel();
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -156,18 +146,12 @@ public class PopWindowUtil {
         dialog_view.setFocusable(true);
         FrameLayout exit = dialog_view.findViewById(R.id.popupwindow_cancellation_account_ok);
         FrameLayout cancel = dialog_view.findViewById(R.id.popupwindow_cancellation_account_cancel);
-        exit.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                listener.clickSubmit(null);
-            }
+        setClickListener(exit, o -> {
+            listener.clickSubmit(null);
         });
-        cancel.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickCancel();
-            }
+        setClickListener(cancel, o -> {
+            mPopupWindow.dismiss();
+            listener.clickCancel();
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -183,12 +167,9 @@ public class PopWindowUtil {
         View dialog_view = LayoutInflater.from(context).inflate(R.layout.popupwindow_bind_wechat, null);
         dialog_view.setFocusable(true);
         ImageView back = dialog_view.findViewById(R.id.popupwindow_bindwechat_back);
-        back.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickCancel();
-            }
+        setClickListener(back, o -> {
+            mPopupWindow.dismiss();
+            listener.clickCancel();
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -213,11 +194,8 @@ public class PopWindowUtil {
             }
         });
         ImageView back = dialog_view.findViewById(R.id.popupwindow_record_status_close);
-        back.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-            }
+        setClickListener(back, o -> {
+            mPopupWindow.dismiss();
         });
         mPresenter.initRecordStatusWindow(context, dialog_view, listener);
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
@@ -243,11 +221,8 @@ public class PopWindowUtil {
             }
         });
         ImageView back = dialog_view.findViewById(R.id.popupwindow_myorder_back);
-        back.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-            }
+        setClickListener(back, o -> {
+            mPopupWindow.dismiss();
         });
         mPresenter.myOrderWindowInit(context, dialog_view);
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
@@ -265,19 +240,14 @@ public class PopWindowUtil {
         dialog_view.setFocusable(true);
         FrameLayout ok = dialog_view.findViewById(R.id.popupwindow_record_remove_ok);
         FrameLayout cancel = dialog_view.findViewById(R.id.popupwindow_record_remove_cancel);
-        ok.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickSubmit(null);
-            }
+        setClickListener(ok, o -> {
+            mPopupWindow.dismiss();
+            listener.clickSubmit(null);
         });
-        cancel.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                mPopupWindow.dismiss();
-                listener.clickCancel();
-            }
+
+        setClickListener(cancel, o -> {
+            mPopupWindow.dismiss();
+            listener.clickCancel();
         });
         mPopupWindow = new PopupWindow(dialog_view, FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
         mPopupWindow.setFocusable(true);
@@ -285,6 +255,9 @@ public class PopWindowUtil {
     }
 
 
+    private static void setClickListener(View view, Consumer onNext) {
+        RxView.clicks(view).throttleFirst(2, TimeUnit.SECONDS).subscribe(onNext);
+    }
 }
 
 

+ 11 - 1
app/src/main/java/com/edufound/reader/presenter/LoginAlertPresenter.java

@@ -1,5 +1,6 @@
 package com.edufound.reader.presenter;
 
+import android.content.Context;
 import android.content.Intent;
 import android.graphics.Color;
 import android.os.Handler;
@@ -12,6 +13,7 @@ import android.text.method.LinkMovementMethod;
 import android.text.style.ClickableSpan;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebView;
 import android.widget.FrameLayout;
 import android.widget.TextView;
@@ -23,12 +25,15 @@ import com.edufound.reader.base.BasePresenter;
 import com.edufound.reader.contract.LoginAlertContract;
 import com.edufound.reader.model.LoginAlertModel;
 import com.edufound.reader.util.Consts;
+import com.jakewharton.rxbinding4.view.RxView;
 import com.orhanobut.logger.Logger;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.functions.Consumer;
 
 public class LoginAlertPresenter extends BasePresenter<LoginAlertContract.View> implements LoginAlertContract.Presenter {
 
@@ -56,7 +61,9 @@ public class LoginAlertPresenter extends BasePresenter<LoginAlertContract.View>
             style.setSpan(new ClickableSpan() {
                 @Override
                 public void onClick(@NonNull View widget) {
-                    lookPrivacy(finalI);
+                    setClickListener(widget, o -> {
+                        lookPrivacy(finalI);
+                    });
                 }
 
                 @Override
@@ -196,4 +203,7 @@ public class LoginAlertPresenter extends BasePresenter<LoginAlertContract.View>
     }
 
 
+    private void setClickListener(View view, Consumer onNext) {
+        RxView.clicks(view).throttleFirst(2, TimeUnit.SECONDS).subscribe(onNext);
+    }
 }

+ 17 - 0
app/src/main/java/com/edufound/reader/presenter/MainPresenter.java

@@ -1,9 +1,12 @@
 package com.edufound.reader.presenter;
 
 import android.content.Intent;
+import android.graphics.Color;
 import android.view.KeyEvent;
+import android.widget.FrameLayout;
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
+import android.widget.TextView;
 import android.widget.Toast;
 
 import com.edufound.reader.R;
@@ -18,6 +21,7 @@ import com.edufound.reader.model.MainModel;
 import com.edufound.reader.listener.PopUtilClickListener;
 import com.edufound.reader.popwindow.PopWindowUtil;
 import com.edufound.reader.util.Consts;
+import com.edufound.reader.util.SizeUtils;
 import com.orhanobut.logger.Logger;
 
 import androidx.fragment.app.Fragment;
@@ -140,6 +144,19 @@ public class MainPresenter extends BasePresenter<MainContract.View> implements M
 
     }
 
+    @Override
+    public void checkModelIsDebug() {
+        if (Consts.isIsDebug()) {
+            TextView tv = new TextView(mView.getActivity());
+            tv.setLayoutParams(new FrameLayout.LayoutParams(SizeUtils.px2dp(mView.getActivity(), 300), SizeUtils.px2dp(mView.getActivity(), 100)));
+            tv.setTextSize(SizeUtils.px2dp(mView.getActivity(), 30));
+            tv.setTextColor(Color.RED);
+            tv.setBackgroundColor(mView.getActivity().getResources().getColor(R.color.translucent_background));
+            tv.setText("当前在Debug模式下(->application->setIsDebug)");
+            mView.getRootView().addView(tv);
+        }
+    }
+
 
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {

+ 8 - 1
app/src/main/java/com/edufound/reader/presenter/MyCollectionPresenter.java

@@ -6,6 +6,7 @@ import android.view.View;
 import com.edufound.reader.adapter.MyCollectionItemAdapter;
 import com.edufound.reader.base.BasePresenter;
 import com.edufound.reader.contract.MyCollectionContract;
+import com.edufound.reader.listener.RecyclerItemClickListener;
 import com.edufound.reader.util.SizeUtils;
 import com.orhanobut.logger.Logger;
 
@@ -30,7 +31,6 @@ public class MyCollectionPresenter extends BasePresenter<MyCollectionContract.Vi
 
     @Override
     public void initRecyclerView(RecyclerView rv) {
-//
         myCollectionItemAdapter = new MyCollectionItemAdapter(mView.getActivity(), mDataList);
         GridLayoutManager gridLayoutManager = new GridLayoutManager(mView.getActivity(), 2);
         gridLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
@@ -49,6 +49,13 @@ public class MyCollectionPresenter extends BasePresenter<MyCollectionContract.Vi
 
             }
         });
+
+        myCollectionItemAdapter.setOnItemClickListener(new RecyclerItemClickListener() {
+            @Override
+            public void onClickListener(int position, View view) {
+                Logger.e("position:" + position);
+            }
+        });
         rv.setAdapter(myCollectionItemAdapter);
     }
 

+ 13 - 0
app/src/main/java/com/edufound/reader/presenter/MyFollowPresenter.java

@@ -1,11 +1,15 @@
 package com.edufound.reader.presenter;
 
+import android.content.Intent;
 import android.graphics.Rect;
 import android.view.View;
+import android.widget.Toast;
 
+import com.edufound.reader.activity.OthersRecordActivity;
 import com.edufound.reader.adapter.MyFollowItemAdapter;
 import com.edufound.reader.base.BasePresenter;
 import com.edufound.reader.contract.MyFollowContract;
+import com.edufound.reader.listener.RecyclerItemClickListener;
 import com.edufound.reader.util.SizeUtils;
 import com.orhanobut.logger.Logger;
 
@@ -55,6 +59,15 @@ public class MyFollowPresenter extends BasePresenter<MyFollowContract.View> impl
 
             }
         });
+        myFollowItemAdapter.setOnItemClickListener(new RecyclerItemClickListener() {
+            @Override
+            public void onClickListener(int position, View view) {
+                Toast.makeText(mView.getActivity(), "click:" + position, Toast.LENGTH_SHORT).show();
+                Intent intent = new Intent(mView.getActivity(), OthersRecordActivity.class);
+                intent.putExtra("userId", position);
+                mView.getActivity().startActivity(intent);
+            }
+        });
         rv.setAdapter(myFollowItemAdapter);
     }
 

+ 19 - 3
app/src/main/java/com/edufound/reader/presenter/MyTabFragmentPresenter.java

@@ -1,13 +1,16 @@
 package com.edufound.reader.presenter;
 
 import android.animation.Animator;
+import android.animation.LayoutTransition;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Message;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.GridLayout;
 import android.widget.ImageView;
@@ -23,6 +26,7 @@ import com.edufound.reader.model.MyTabFragmentModel;
 import com.edufound.reader.popwindow.PopWindowUtil;
 import com.edufound.reader.util.GlideUtils;
 import com.edufound.reader.util.SizeUtils;
+import com.orhanobut.logger.Logger;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -83,6 +87,15 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
             gridLayout.setVisibility(View.GONE);
             return;
         }
+        if (gridLayout.getLayoutTransition() == null) {
+            LayoutTransition transition = new LayoutTransition();
+            transition.setDuration(200);
+            transition.setAnimator(LayoutTransition.APPEARING, null);
+            transition.setAnimator(LayoutTransition.CHANGE_APPEARING, null);
+            transition.setAnimator(LayoutTransition.DISAPPEARING, null);
+            transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, transition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING));
+            gridLayout.setLayoutTransition(transition);
+        }
         gridLayout.setRowCount(2);
         int timeCount = 0;
         for (int j = mListStart; j < mListEnd; j++) {
@@ -119,6 +132,7 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
         if (mView == null) {
             return;
         }
+
         View view = LayoutInflater.from(mContext).inflate(R.layout.adapter_item_record_user, null);
         ImageView imgIcon = view.findViewById(R.id.adapter_item_record_user_icon);
         TextView name = view.findViewById(R.id.adapter_item_record_user_name);
@@ -126,7 +140,7 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
         ImageView imgPriv = view.findViewById(R.id.adapter_item_record_user_priv);
         FrameLayout checkLayout = view.findViewById(R.id.adapter_item_record_user_examine_layout);
         GlideUtils.loadRoundCircleImage(mContext, "http://p.qpic.cn/videoyun/0/2449_43b6f696980311e59ed467f22794e792_1/640", imgIcon, SizeUtils.dp2px(mContext, 20));
-        if (index < 3) {
+        if (index < 10) {
             //测试用
             checkLayout.setVisibility(View.GONE);
             imgPriv.setImageResource(R.drawable.adapter_item_record_pub);
@@ -140,7 +154,7 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
 
                 @Override
                 public void clickSubmit(Object object) {
-                    view.animate().scaleY(0).scaleX(0).setDuration(500).setListener(new Animator.AnimatorListener() {
+                    view.animate().scaleY(0).scaleX(0).setDuration(200).setListener(new Animator.AnimatorListener() {
                         @Override
                         public void onAnimationStart(Animator animator) {
 
@@ -149,6 +163,7 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
                         @Override
                         public void onAnimationEnd(Animator animator) {
                             gridLayout.removeView(view);
+                            mView.loadMoreItem();
                         }
 
                         @Override
@@ -243,4 +258,5 @@ public class MyTabFragmentPresenter extends BasePresenter<MyTabFragmentContract.
 ////            outRect.top = mRowSpacing + SizeUtils.dp2px(Consts.getmApplicAtion(), 50);
 ////        }
 //    }
-//}
+//}
+

+ 46 - 0
app/src/main/java/com/edufound/reader/support/ActivityLifecycleCallbacksAdapter.java

@@ -0,0 +1,46 @@
+package com.edufound.reader.support;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+/**
+ * Created by wanjian on 2018/5/21.
+ */
+
+public class ActivityLifecycleCallbacksAdapter implements Application.ActivityLifecycleCallbacks {
+    @Override
+    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+
+    }
+
+    @Override
+    public void onActivityStarted(Activity activity) {
+
+    }
+
+    @Override
+    public void onActivityResumed(Activity activity) {
+
+    }
+
+    @Override
+    public void onActivityPaused(Activity activity) {
+
+    }
+
+    @Override
+    public void onActivityStopped(Activity activity) {
+
+    }
+
+    @Override
+    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+    }
+
+    @Override
+    public void onActivityDestroyed(Activity activity) {
+
+    }
+}

+ 10 - 0
app/src/main/java/com/edufound/reader/support/ClientTransaction.java

@@ -0,0 +1,10 @@
+package com.edufound.reader.support;
+
+import android.os.IBinder;
+
+public class ClientTransaction {
+
+    public IBinder getActivityToken() {
+        return null;
+    }
+}

+ 95 - 0
app/src/main/java/com/edufound/reader/support/CrashLog.java

@@ -0,0 +1,95 @@
+package com.edufound.reader.support;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ */
+public class CrashLog {
+    public static final String TAG = "CrashLog";
+
+    public static void saveCrashLog(Context context, Throwable throwable) {
+        Map<String, String> map = collectDeviceInfo(context);
+        saveCrashInfo2File(context, throwable, map);
+    }
+
+
+    private static Map<String, String> collectDeviceInfo(Context ctx) {
+        Map<String, String> infos = new TreeMap<>();
+        try {
+
+            infos.put("systemVersion", Build.VERSION.RELEASE);
+            PackageManager pm = ctx.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
+            if (pi != null) {
+                String versionName = pi.versionName == null ? "null" : pi.versionName;
+                String versionCode = pi.versionCode + "";
+                infos.put("versionName", versionName);
+                infos.put("versionCode", versionCode);
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+        }
+        Field[] fields = Build.class.getDeclaredFields();
+        for (Field field : fields) {
+            try {
+                field.setAccessible(true);
+                infos.put(field.getName(), field.get(null).toString());
+            } catch (Exception e) {
+            }
+        }
+        return infos;
+    }
+
+    private static void saveCrashInfo2File(Context context, Throwable ex, Map<String, String> infos) {
+        StringBuilder sb = new StringBuilder();
+        for (Map.Entry<String, String> entry : infos.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+            sb.append(key).append("=").append(value).append("\n");
+        }
+
+        Writer writer = new StringWriter();
+        PrintWriter printWriter = new PrintWriter(writer);
+        ex.printStackTrace(printWriter);
+        Throwable cause = ex.getCause();
+        while (cause != null) {
+            cause.printStackTrace(printWriter);
+            cause = cause.getCause();
+        }
+        printWriter.close();
+        String result = writer.toString();
+        sb.append(result);
+
+        try {
+            long timestamp = System.currentTimeMillis();
+            String time = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date());
+            String fileName = "crash-" + time + "-" + timestamp + ".log";
+            String cachePath = crashLogDir(context);
+
+            File dir = new File(cachePath);
+            dir.mkdirs();
+            FileOutputStream fos = new FileOutputStream(cachePath + fileName);
+            fos.write(sb.toString().getBytes());
+            fos.close();
+        } catch (Exception e) {
+        }
+    }
+
+    public static String crashLogDir(Context context) {
+        return context.getCacheDir().getPath() + File.separator + "crash" + File
+                .separator;
+    }
+}

+ 246 - 0
app/src/main/java/com/edufound/reader/support/CrashLogFragment.java

@@ -0,0 +1,246 @@
+package com.edufound.reader.support;
+
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import android.widget.Toast;
+
+
+import com.edufound.reader.R;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.DividerItemDecoration;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import io.reactivex.rxjava3.annotations.NonNull;
+import io.reactivex.rxjava3.annotations.Nullable;
+
+
+public class CrashLogFragment extends Fragment {
+
+    RecyclerView recyclerView;
+    Handler fileReadHandler;
+    Handler uiHandler = new Handler();
+    LogAdapter adapter = new LogAdapter();
+
+    @Nullable
+    @Override
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_crash_log, container, false);
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        recyclerView = view.findViewById(R.id.recyclerview);
+        recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false));
+        recyclerView.setAdapter(adapter);
+
+        DividerItemDecoration decoration = new DividerItemDecoration(getContext(), RecyclerView.VERTICAL);
+        decoration.setDrawable(getResources().getDrawable(R.drawable.list_divider_horizontal));
+        recyclerView.addItemDecoration(decoration);
+
+        HandlerThread thread = new HandlerThread("crash_log_read") {
+            @Override
+            protected void onLooperPrepared() {
+                super.onLooperPrepared();
+                fileReadHandler = new Handler(getLooper());
+                readFileList();
+            }
+        };
+        thread.start();
+
+
+    }
+
+    private void readFileList() {
+        fileReadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                String dir = CrashLog.crashLogDir(getContext());
+                if (dir == null) {
+                    return;
+                }
+                File file = new File(dir);
+                List<File> fs = Arrays.asList(file.listFiles());
+
+                Collections.sort(fs, new Comparator<File>() {
+                    @Override
+                    public int compare(File o1, File o2) {
+                        return (int) (o2.lastModified() - o1.lastModified());
+                    }
+                });
+
+                final List<Log> logs = new ArrayList<>();
+                for (File f : fs) {
+                    logs.add(new Log(f, f.getName(), null));
+                }
+                setFileList(logs);
+            }
+        });
+    }
+
+    private void setFileList(final List<Log> logs) {
+
+        uiHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                adapter.setFileList(logs);
+            }
+        });
+    }
+
+    private void readFileContent(final File file) {
+
+        fileReadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    String content = read(file);
+                    update(file, content);
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+
+            }
+        });
+    }
+
+    private void update(final File file, final String content) {
+        if (content == null) {
+            return;
+        }
+
+        uiHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                for (Log log : adapter.logs) {
+                    if (log.file == file) {
+                        log.content = content;
+                        adapter.notifyDataSetChanged();
+                        return;
+                    }
+
+                }
+
+            }
+        });
+    }
+
+    private String read(File file) throws Exception {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
+        String line;
+
+        StringBuilder builder = new StringBuilder((int) file.length());
+        while ((line = reader.readLine()) != null) {
+            builder.append(line);
+            builder.append("\n");
+        }
+        return builder.toString();
+
+    }
+
+    class LogAdapter extends RecyclerView.Adapter<LogAdapter.LogVH> {
+
+        private List<Log> logs;
+
+        @NonNull
+        @Override
+        public LogVH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new LogVH();
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull LogVH holder, int position) {
+            holder.title.setTag(position);
+            Log log = getData(position);
+            holder.copy.setTag(log.content);
+            holder.title.setText(log.title);
+            if (log.content == null) {
+                holder.content.setVisibility(View.GONE);
+                holder.copy.setVisibility(View.INVISIBLE);
+            } else {
+                holder.content.setText(log.content);
+                holder.content.setVisibility(View.VISIBLE);
+                holder.copy.setVisibility(View.VISIBLE);
+            }
+        }
+
+        protected Log getData(int position) {
+            return logs.get(position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return logs == null ? 0 : logs.size();
+        }
+
+        public void setFileList(List<Log> fs) {
+            this.logs = fs;
+            notifyDataSetChanged();
+        }
+
+        class LogVH extends RecyclerView.ViewHolder {
+
+            TextView title;
+            TextView content;
+            TextView copy;
+
+            public LogVH() {
+                super(LayoutInflater.from(getContext()).inflate(R.layout.item_crash_log, recyclerView, false));
+                title = itemView.findViewById(R.id.title);
+                content = itemView.findViewById(R.id.content);
+                copy = itemView.findViewById(R.id.copy);
+                title.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        int position = ((int) v.getTag());
+                        if (logs.get(position).content == null) {
+                            readFileContent(logs.get(position).file);
+                        }
+                    }
+                });
+                copy.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        String log = ((String) v.getTag());
+                        ClipboardManager cmb = (ClipboardManager) v.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+                        cmb.setText(log);
+                        Toast.makeText(v.getContext(), "已经复制到粘贴板", Toast.LENGTH_SHORT).show();
+                    }
+                });
+            }
+        }
+
+
+    }
+
+    class Log {
+        File file;
+        String title;
+        String content;
+
+        public Log(File file, String title, String content) {
+            this.file = file;
+            this.title = title;
+            this.content = content;
+        }
+    }
+}
+

+ 39 - 0
app/src/main/java/com/edufound/reader/support/DebugSafeModeTipActivity.java

@@ -0,0 +1,39 @@
+package com.edufound.reader.support;
+
+import android.os.Bundle;
+import android.view.View;
+
+import com.edufound.reader.R;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import io.reactivex.rxjava3.annotations.Nullable;
+
+
+/**
+ * Created by wanjian on 2018/5/21.
+ */
+
+public class DebugSafeModeTipActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_safe_mode_warning);
+
+        findViewById(R.id.log).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Fragment fragment = getSupportFragmentManager().findFragmentByTag(CrashLogFragment.class.getName());
+                if (fragment == null) {
+                    fragment = new CrashLogFragment();
+                }
+                getSupportFragmentManager()
+                        .beginTransaction()
+                        .replace(R.id.container, fragment, CrashLogFragment.class.getName())
+                        .commit();
+            }
+        });
+    }
+
+
+}

+ 78 - 0
app/src/main/java/com/edufound/reader/support/DebugSafeModeUI.java

@@ -0,0 +1,78 @@
+package com.edufound.reader.support;
+
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.edufound.reader.R;
+import com.edufound.reader.util.Cockroach;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by wanjian on 2018/5/21.
+ * 进入安全模式后给所有act添加一个渐变的绿色顶栏
+ */
+
+public class DebugSafeModeUI {
+
+    private static int barHeight;
+    private static List<WeakReference<Activity>> sActivitysWRef = new ArrayList<>();
+
+    public static void init(Application application) {
+        application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacksAdapter() {
+            @Override
+            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+                super.onActivityCreated(activity, savedInstanceState);
+                sActivitysWRef.add(new WeakReference<>(activity));
+                if (Cockroach.isSafeMode()) {
+                    //进入安全模式后给新创建的act添加渐变绿色顶栏
+                    enterSafeMode(activity);
+                }
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                super.onActivityDestroyed(activity);
+                for (WeakReference<Activity> reference : sActivitysWRef) {
+                    Activity act = reference.get();
+                    if (act == activity) {
+                        sActivitysWRef.remove(reference);
+                        return;
+                    }
+                }
+            }
+        });
+        barHeight = (int) (application.getResources().getDisplayMetrics().density * 50);
+    }
+
+    /**
+     * 进入安全模式后给当前已存在的act添加渐变绿色顶栏
+     */
+    public static void showSafeModeUI() {
+        for (WeakReference<Activity> reference : sActivitysWRef) {
+            Activity activity = reference.get();
+            if (activity == null || activity.isFinishing()) {
+                continue;
+            }
+            enterSafeMode(activity);
+        }
+    }
+
+    public static void enterSafeMode(Activity activity) {
+        try {
+            View view = new View(activity);
+            FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, barHeight);
+            view.setLayoutParams(params);
+            view.setBackgroundResource(R.drawable.safe_mode_drawable);
+            ((ViewGroup) activity.getWindow().getDecorView()).addView(view);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+}

+ 247 - 0
app/src/main/java/com/edufound/reader/util/Cockroach.java

@@ -0,0 +1,247 @@
+package com.edufound.reader.util;
+
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+import com.edufound.reader.listener.ActivityKillerV15_V20;
+import com.edufound.reader.listener.ActivityKillerV21_V23;
+import com.edufound.reader.listener.ActivityKillerV24_V25;
+import com.edufound.reader.listener.ActivityKillerV26;
+import com.edufound.reader.listener.ActivityKillerV28;
+import com.edufound.reader.listener.IActivityKiller;
+
+import java.lang.reflect.Field;
+
+import me.weishu.reflection.Reflection;
+
+
+/**
+ * Created by wanjian on 2017/2/14.
+ */
+
+public final class Cockroach {
+
+    private static IActivityKiller sActivityKiller;
+    private static ExceptionHandler sExceptionHandler;
+    private static boolean sInstalled = false;//标记位,避免重复安装卸载
+    private static boolean sIsSafeMode;
+
+    private Cockroach() {
+    }
+
+    public static void install(Context ctx, ExceptionHandler exceptionHandler) {
+        if (sInstalled) {
+            return;
+        }
+        try {
+            //解除 android P 反射限制
+            Reflection.unseal(ctx);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+        sInstalled = true;
+        sExceptionHandler = exceptionHandler;
+
+        initActivityKiller();
+
+        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+            @Override
+            public void uncaughtException(Thread t, Throwable e) {
+                if (sExceptionHandler != null) {
+                    sExceptionHandler.uncaughtExceptionHappened(t, e);
+                }
+                if (t == Looper.getMainLooper().getThread()) {
+                    isChoreographerException(e);
+                    safeMode();
+                }
+            }
+        });
+
+    }
+
+    /**
+     * 替换ActivityThread.mH.mCallback,实现拦截Activity生命周期,直接忽略生命周期的异常的话会导致黑屏,目前
+     * 会调用ActivityManager的finishActivity结束掉生命周期抛出异常的Activity
+     */
+    private static void initActivityKiller() {
+        //各版本android的ActivityManager获取方式,finishActivity的参数,token(binder对象)的获取不一样
+        if (Build.VERSION.SDK_INT >= 28) {
+            sActivityKiller = new ActivityKillerV28();
+        } else if (Build.VERSION.SDK_INT >= 26) {
+            sActivityKiller = new ActivityKillerV26();
+        } else if (Build.VERSION.SDK_INT == 25 || Build.VERSION.SDK_INT == 24) {
+            sActivityKiller = new ActivityKillerV24_V25();
+        } else if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT <= 23) {
+            sActivityKiller = new ActivityKillerV21_V23();
+        } else if (Build.VERSION.SDK_INT >= 15 && Build.VERSION.SDK_INT <= 20) {
+            sActivityKiller = new ActivityKillerV15_V20();
+        } else if (Build.VERSION.SDK_INT < 15) {
+            sActivityKiller = new ActivityKillerV15_V20();
+        }
+
+        try {
+            hookmH();
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static void hookmH() throws Exception {
+
+        final int LAUNCH_ACTIVITY = 100;
+        final int PAUSE_ACTIVITY = 101;
+        final int PAUSE_ACTIVITY_FINISHING = 102;
+        final int STOP_ACTIVITY_HIDE = 104;
+        final int RESUME_ACTIVITY = 107;
+        final int DESTROY_ACTIVITY = 109;
+        final int NEW_INTENT = 112;
+        final int RELAUNCH_ACTIVITY = 126;
+        Class activityThreadClass = Class.forName("android.app.ActivityThread");
+        Object activityThread = activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null);
+
+        Field mhField = activityThreadClass.getDeclaredField("mH");
+        mhField.setAccessible(true);
+        final Handler mhHandler = (Handler) mhField.get(activityThread);
+        Field callbackField = Handler.class.getDeclaredField("mCallback");
+        callbackField.setAccessible(true);
+        callbackField.set(mhHandler, new Handler.Callback() {
+            @Override
+            public boolean handleMessage(Message msg) {
+                if (Build.VERSION.SDK_INT >= 28) {//android P 生命周期全部走这
+                    final int EXECUTE_TRANSACTION = 159;
+                    if (msg.what == EXECUTE_TRANSACTION) {
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishLaunchActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    }
+                    return false;
+                }
+                switch (msg.what) {
+                    case LAUNCH_ACTIVITY:// startActivity--> activity.attach  activity.onCreate  r.activity!=null  activity.onStart  activity.onResume
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishLaunchActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    case RESUME_ACTIVITY://回到activity onRestart onStart onResume
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishResumeActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    case PAUSE_ACTIVITY_FINISHING://按返回键 onPause
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishPauseActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    case PAUSE_ACTIVITY://开启新页面时,旧页面执行 activity.onPause
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishPauseActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    case STOP_ACTIVITY_HIDE://开启新页面时,旧页面执行 activity.onStop
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            sActivityKiller.finishStopActivity(msg);
+                            notifyException(throwable);
+                        }
+                        return true;
+                    case DESTROY_ACTIVITY:// 关闭activity onStop  onDestroy
+                        try {
+                            mhHandler.handleMessage(msg);
+                        } catch (Throwable throwable) {
+                            notifyException(throwable);
+                        }
+                        return true;
+                }
+                return false;
+            }
+        });
+    }
+
+
+    private static void notifyException(Throwable throwable) {
+        if (sExceptionHandler == null) {
+            return;
+        }
+        if (isSafeMode()) {
+            sExceptionHandler.bandageExceptionHappened(throwable);
+        } else {
+            sExceptionHandler.uncaughtExceptionHappened(Looper.getMainLooper().getThread(), throwable);
+            safeMode();
+        }
+    }
+
+    public static boolean isSafeMode() {
+        return sIsSafeMode;
+    }
+
+    private static void safeMode() {
+        sIsSafeMode = true;
+        if (sExceptionHandler != null) {
+            sExceptionHandler.enterSafeMode();
+        }
+        while (true) {
+            try {
+                Looper.loop();
+            } catch (Throwable e) {
+                isChoreographerException(e);
+                if (sExceptionHandler != null) {
+                    sExceptionHandler.bandageExceptionHappened(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * view measure layout draw时抛出异常会导致Choreographer挂掉
+     * <p>
+     * 建议直接杀死app。以后的版本会只关闭黑屏的Activity
+     *
+     * @param e
+     */
+    private static void isChoreographerException(Throwable e) {
+        if (e == null || sExceptionHandler == null) {
+            return;
+        }
+        StackTraceElement[] elements = e.getStackTrace();
+        if (elements == null) {
+            return;
+        }
+
+        for (int i = elements.length - 1; i > -1; i--) {
+            if (elements.length - i > 20) {
+                return;
+            }
+            StackTraceElement element = elements[i];
+            if ("android.view.Choreographer".equals(element.getClassName())
+                    && "Choreographer.java".equals(element.getFileName())
+                    && "doFrame".equals(element.getMethodName())) {
+                sExceptionHandler.mayBeBlackScreen(e);
+                return;
+            }
+
+        }
+    }
+
+
+}

+ 10 - 0
app/src/main/java/com/edufound/reader/util/Consts.java

@@ -11,6 +11,8 @@ public class Consts {
 
     private static UserInfoBean mConstsUserBean;
 
+    private static boolean isDebug = false;
+
 
     private static String privService = "http://m-xyyf-web.ai160.com/res/protocol/private.htm";
     private static String agreementServices = "http://m-xyyf-web.ai160.com/res/protocol/service.htm";
@@ -46,4 +48,12 @@ public class Consts {
     public static String getAgreementServicesUrl() {
         return agreementServices;
     }
+
+    public static boolean isIsDebug() {
+        return isDebug;
+    }
+
+    public static void setIsDebug(boolean isDebug) {
+        Consts.isDebug = isDebug;
+    }
 }

+ 59 - 0
app/src/main/java/com/edufound/reader/util/ExceptionHandler.java

@@ -0,0 +1,59 @@
+package com.edufound.reader.util;
+
+
+public abstract class ExceptionHandler {
+    final void uncaughtExceptionHappened(Thread thread, Throwable throwable) {
+        try {//捕获监听中异常,防止使用方代码抛出异常时导致的反复调用
+            onUncaughtExceptionHappened(thread, throwable);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+
+    final void bandageExceptionHappened(Throwable throwable) {
+        try {//捕获监听中异常,防止使用方代码抛出异常时导致的反复调用
+            onBandageExceptionHappened(throwable);
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+    }
+
+    final void enterSafeMode() {
+        try {
+            onEnterSafeMode();
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+
+    final void mayBeBlackScreen(Throwable e) {
+        try {
+            onMayBeBlackScreen(e);
+        } catch (Throwable throwable) {
+            throwable.printStackTrace();
+        }
+    }
+
+    /**
+     * 子线程抛出异常时始终调用该方法。主线程只有第一次抛出异常时才会调用该方法,该方法中到的throwable都会上报到bugly。以后主线程的异常只调用 {@link #onBandageExceptionHappened(Throwable)}
+     *
+     * @param thread
+     * @param throwable
+     */
+    protected abstract void onUncaughtExceptionHappened(Thread thread, Throwable throwable);
+
+    /**
+     * 当原本导致app崩溃的主线程异常发生后,主线程再次抛出导致app崩溃异常时会调用该方法。(自己try catch住的异常不会导致app崩溃)
+     * (该方法中到的throwable不会上报到bugly,也无需上报到bugly,因为本次异常可能是由于第一次主线程异常时app没有崩溃掉才发生的,只要修复了bug就不会发生该异常了)
+     *
+     * @param throwable 主线程的异常
+     */
+    protected abstract void onBandageExceptionHappened(Throwable throwable);
+
+    protected abstract void onEnterSafeMode();
+
+    protected void onMayBeBlackScreen(Throwable e) {
+
+    }
+}

+ 0 - 170
app/src/main/res/drawable/ic_launcher_background.xml

@@ -1,170 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="108dp"
-        android:height="108dp"
-        android:viewportWidth="108"
-        android:viewportHeight="108">
-    <path
-            android:fillColor="#3DDC84"
-            android:pathData="M0,0h108v108h-108z" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M9,0L9,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,0L19,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M29,0L29,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M39,0L39,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M49,0L49,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M59,0L59,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M69,0L69,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M79,0L79,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M89,0L89,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M99,0L99,108"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,9L108,9"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,19L108,19"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,29L108,29"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,39L108,39"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,49L108,49"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,59L108,59"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,69L108,69"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,79L108,79"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,89L108,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M0,99L108,99"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,29L89,29"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,39L89,39"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,49L89,49"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,59L89,59"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,69L89,69"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M19,79L89,79"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M29,19L29,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M39,19L39,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M49,19L49,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M59,19L59,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M69,19L69,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-    <path
-            android:fillColor="#00000000"
-            android:pathData="M79,19L79,89"
-            android:strokeWidth="0.8"
-            android:strokeColor="#33FFFFFF" />
-</vector>

BIN
app/src/main/res/drawable/splash_bg.jpg


+ 3 - 1
app/src/main/res/layout/activity_alert_login.xml

@@ -4,7 +4,9 @@
         android:id="@+id/activity_loginalert_rootview"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@color/translucent_background">
+        android:background="@color/translucent_background"
+        android:clickable="true"
+        android:focusableInTouchMode="true">
 
 
     <FrameLayout

+ 0 - 19
app/src/main/res/layout/activity_crash_dialog.xml

@@ -7,23 +7,4 @@
         android:background="@color/transparent">
 
 
-    <HorizontalScrollView
-            android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            app:layout_constraintBottom_toBottomOf="parent"
-            app:layout_constraintEnd_toEndOf="parent"
-            app:layout_constraintStart_toStartOf="parent"
-            app:layout_constraintTop_toTopOf="parent">
-
-        <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="fill_parent">
-
-            <com.edufound.reader.cusview.AblGridView
-                    android:id="@+id/test_gridview"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"></com.edufound.reader.cusview.AblGridView>
-        </LinearLayout>
-    </HorizontalScrollView>
-
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 2
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@@ -1,5 +1,3 @@
 <?xml version="1.0" encoding="utf-8"?>
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
 </adaptive-icon>

+ 0 - 2
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@@ -1,5 +1,3 @@
 <?xml version="1.0" encoding="utf-8"?>
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
-    <background android:drawable="@drawable/ic_launcher_background" />
-    <foreground android:drawable="@drawable/ic_launcher_foreground" />
 </adaptive-icon>

+ 1 - 1
app/src/main/res/values/themes.xml

@@ -17,7 +17,7 @@
     <style name="AppStartTheme" parent="@style/Theme.AppCompat.Light">
         <item name="windowNoTitle">true</item>
         <item name="android:windowFullscreen">true</item>
-        <item name="android:windowBackground">@drawable/openimg</item>
+        <item name="android:windowBackground">@drawable/splash_bg</item>
     </style>
 
 

+ 1 - 0
build.gradle

@@ -19,6 +19,7 @@ allprojects {
         jcenter()
         mavenCentral()
         maven { url "https://oss.jfrog.org/libs-snapshot" }
+        maven { url 'https://jitpack.io' }
     }
 }