拆分api

增加umeng
This commit is contained in:
mwang 2019-05-11 23:21:57 +08:00
parent 3c4872a58e
commit 3a26f670c4
38 changed files with 1606 additions and 207 deletions

View File

@ -12,23 +12,82 @@ android {
versionName "1.0"
// testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// vectorDrawables.useSupportLibrary = true
vectorDrawables.useSupportLibrary = true
renderscriptTargetApi 24 //blurkit
renderscriptSupportModeEnabled true //blurkit
multiDexEnabled true //65535
manifestPlaceholders = [UMENG_CHANNEL_CALUE:"umeng"] //uMeng
flavorDimensions "default"
}
buildTypes {
release {
debug {
// Log
buildConfigField "boolean", "LOG_DEBUG", "true"
versionNameSuffix "-debug"
minifyEnabled false
zipAlignEnabled false
shrinkResources false
signingConfig signingConfigs.debug
}
release {
// Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//
minifyEnabled true
//Zipalign优化
zipAlignEnabled true
// resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
applicationVariants.all{ variant ->
variant.outputs.all{ output ->
def outFile = output.outputFile
if (outFile != null && outFile.name.endsWith(".apk")){
def fileName = "${variant.productFlavors[0].name}" + ".apk"
outputFileName = fileName;
// output.outputFile = new File(outFile.parent, fileName);
}
}
}
}
}
//
productFlavors {
// googleplay {}
huawei { applicationId "com.novelbook.android.huawei"
versionName "version-a-1.0"}
xiaomi { applicationId "com.novelbook.android.xiaomi"
versionName "version-a-1.0"}
/* wandoujia {}
baidu {}
yingyongbao {}
android360 {}
uc {}
umeng {}
meizu{}
*/
//
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}
android {
lintOptions {
abortOnError false
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
@ -40,9 +99,14 @@ android {
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
@ -84,4 +148,6 @@ dependencies {
// implementation 'com.github.tangguna:SearchBox:1.0.1'
implementation 'com.github.chengzipi:Searchbox:v1.0.0'
implementation 'com.github.ixiaow:multilayout:1.0.0'
implementation 'com.umeng.umsdk:analytics:8.0.2'
implementation 'com.umeng.umsdk:common:2.0.2'
}

View File

@ -1,21 +1,273 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
# By default, the flags in this file are appended to flags specified
# in D:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *;
}
#指定代码的压缩级别
-optimizationpasses 5
#包明不混合大小写
-dontusemixedcaseclassnames
#不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#优化 不优化输入的类文件
# -dontoptimize
#预校验
-dontpreverify
#混淆时是否记录日志
-verbose
# 混淆时所采用的算法
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护注解
-keepattributes *Annotation*
# 保持哪些类不被混淆
-keep public class * extends android.app.Fragment
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
#如果有引用v4包可以添加下面这行
-keep public class * extends android.support.v4.app.Fragment
#忽略警告
-ignorewarning
##记录生成的日志数据,gradle build时在本项目根目录输出##
#apk 包内所有 class 的内部结构
-dump proguard/class_files.txt
#未混淆的类和成员
-printseeds proguard/seeds.txt
#列出从 apk 中删除的代码
-printusage proguard/unused.txt
#混淆前后的映射
-printmapping proguard/mapping.txt
########记录生成的日志数据gradle build时 在本项目根目录输出-end######
#如果引用了v4或者v7包
-dontwarn android.support.**
-keep class com.google.** { *; }
-keep class android.support.v4.**
-dontwarn android.support.v4.**
-keep class android.support.v7.**
-dontwarn android.support.v7.**
####混淆保护自己项目的部分代码以及引用的第三方jar包library-end####
#保持 native 方法不被混淆
-keepclasseswithmembernames class * {
native <methods>;
}
#保持自定义控件类不被混淆
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
#保持自定义控件类不被混淆
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
#保持 Parcelable 不被混淆
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#保持 Serializable 不被混淆
-keepnames class * implements java.io.Serializable
#保持 Serializable 不被混淆并且enum 类也不被混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
!private <fields>;
!private <methods>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
#保持枚举 enum 类不被混淆
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * {
public void *ButtonClicked(android.view.View);
}
#不混淆资源类
-keepclassmembers class **.R$* {
public static <fields>;
}
#避免混淆泛型 如果混淆报错建议关掉
#-keepattributes Signature
#移除Log类打印各个等级日志的代码打正式包的时候可以做为禁log使用这里可以作为禁止log打印的功能使用另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制
#-assumenosideeffects class android.util.Log {
# public static *** v(...);
# public static *** i(...);
# public static *** d(...);
# public static *** w(...);
# public static *** e(...);
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
#############################################################################################
######################## 以上通用 ##################################
#############################################################################################
####################### 常用第三方模块的混淆选项 ###################################
#gson
#如果用用到Gson解析包的直接添加下面这几行就能成功混淆不然会报错
-keepattributes Signature
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.** { *; }
-keep class com.google.gson.stream.** { *; }
-keep class com.google.**{*;}
#butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
@butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
@butterknife.* <methods>;
}
######引用的其他Module可以直接在app的这个混淆文件里配置
# 如果使用了Gson之类的工具要使被它解析的JavaBean类即实体类不被混淆
-keep class com.novelbook.android.bean.** { *; }
-keep class com.novelbook.android.db.** { *; }
#####混淆保护自己项目的部分代码以及引用的第三方jar包library#######
#如果在当前的application module或者依赖的library module中使用了第三方的库并不需要显式添加规则
#-libraryjars xxx
#添加了反而有可能在打包的时候遭遇同一个jar多次被指定的错误一般只需要添加忽略警告和保持某些class不被混淆的声明
#以libaray的形式引用了开源项目,如果不想混淆 keep 在引入的module的build.gradle中设置minifyEnabled=false
# banner
-keep class com.youth.banner** { *; }
-keep interface com.youth.banner.** { *; }
-dontwarn com.youth.banner.**
#LitePal
-keep class org.litepal.** { *; }
-keep class * extends org.litepal.crud.DataSupport { *; }
#pagerslidingtabstrip
-keep class com.astuetz.** { *; }
#UMENG
-keep class com.umeng.** {*;}
-keepclassmembers class * {
public <init> (org.json.JSONObject);
}
#okhttp3
-dontwarn okio.**
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
-dontwarn com.squareup.okhttp3.**
-keep class com.squareup.okhttp3.** { *;}
-dontwarn okhttp3.logging.**
-keep class okhttp3.internal.**{*;}
# -keep class com.novelbook.android.netapi.**{*;}
# Retrofit
-dontwarn retrofit2.**
-keep class retrofit2.** { *; }
-keepattributes Signature
-keepattributes Exceptions
-keepclasseswithmembers class * {
@retrofit2.http.* <methods>;
}
# RxJava RxAndroid
-dontwarn sun.misc.**
-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
long producerIndex;
long consumerIndex;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
rx.internal.util.atomic.LinkedQueueNode producerNode;
}
-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
rx.internal.util.atomic.LinkedQueueNode consumerNode;
}
#glide
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String,int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -6,6 +6,9 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name=".MyApp"
@ -75,6 +78,13 @@
<service
android:name=".service.ServiceDownload"
android:exported="false" />
<!-- UMENG -->
<meta-data android:value="5cd6238a570df375c3000cc9" android:name="UMENG_APPKEY"/>
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}"/>
</application>
</manifest>

View File

@ -26,10 +26,12 @@ import com.novelbook.android.db.Novel;
import com.novelbook.android.netsubscribe.MovieSubscribe;
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.upgrade.UpdateManager;
import com.novelbook.android.utils.ImageUtil;
import com.novelbook.android.utils.MyImageLoader;
import com.novelbook.android.utils.OnItemClickListener;
import com.novelbook.android.adapter.BookListAdapter;
import com.umeng.analytics.MobclickAgent;
import java.util.ArrayList;
import java.util.List;
@ -71,6 +73,7 @@ public abstract class Activity_base extends AppCompatActivity {
setTitle();
initData();
initViews();
}
protected void setupToolbar(){
@ -85,11 +88,13 @@ public abstract class Activity_base extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
// MobclickAgent.onResume(this);
}
@Override
protected void onPause(){
super.onPause();
hideProgress();
// MobclickAgent.onPause(this);
}
protected BookListAdapter getBookListAdapter(List<Novel> mDatas,int itemResourceId){
BookListAdapter mAdapter = new BookListAdapter(this ,mDatas,itemResourceId,new OnItemClickListener()
@ -252,6 +257,13 @@ public abstract class Activity_base extends AppCompatActivity {
ImageUtil.loadImage( this, url , imageView);
}
public void checkUpdate(boolean isSilence){
UpdateManager manager = new UpdateManager(this);
if(isSilence)
manager.checkUpdateSilence();
else
manager.checkUpdate();
}
/*
class BookListAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final int EMPTY_VIEW = 1;

View File

@ -6,6 +6,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
@ -26,11 +27,14 @@ import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.DownloadTask;
import com.novelbook.android.db.Novel;
import com.novelbook.android.service.ServiceDownload;
import com.novelbook.android.utils.FileUtils;
import com.novelbook.android.utils.Fileutil;
import com.novelbook.android.utils.ImageUtil;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import butterknife.BindView;
@ -40,6 +44,8 @@ public class Activity_cache extends Activity_base {
public static final String TAG=Activity_cache.class.getSimpleName();
@BindView(R.id.recycleView)
RecyclerView mRecyclerView;
@BindView(R.id.tvMsg)
TextView tvMsg;
private List<DownloadTask> mData;
private CacheAdapter mAdapter;
@Override
@ -60,7 +66,33 @@ public class Activity_cache extends Activity_base {
@Override
protected void initData() {
initiDownloadReceiver();
mData = LitePal.findAll(DownloadTask.class);
showProgressDialog(true,"正在加载...");
new Thread() {
@Override
public void run() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mData = LitePal.where("id >0").order("id desc").find(DownloadTask.class);//findAll(DownloadTask.class);
/* mData.sort(new Comparator<DownloadTask>(){
public int compare(DownloadTask arg0, DownloadTask arg1) {
int i = arg0.getFinishedChpats()/arg0.getTotalChapts() > arg1.getFinishedChpats()/arg1.getTotalChapts() ?1:-1;
return i; }});*/
// }
handler.sendEmptyMessage(1);
}
}.start();
}
@Override
public void fillData() {
mAdapter = new CacheAdapter(this,mData,R.layout.recycle_list_item_cache,new OnItemClickLitener() {
@Override
@ -115,13 +147,6 @@ public class Activity_cache extends Activity_base {
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setAdapter(mAdapter );
}
@Override
public void fillData() {
}
private IntentFilter filter;
@ -137,6 +162,16 @@ public class Activity_cache extends Activity_base {
public void onReceive(Context context, Intent intent){
int taskId =0;
int progress=0;
int status=0;
tvMsg.setVisibility(View.GONE);
if( intent.hasExtra("network")){
String txt = intent.getStringExtra("network");
tvMsg.setText(txt);
tvMsg.setVisibility(View.VISIBLE);
return;
}
if( intent.hasExtra("progress")){
progress = intent.getIntExtra("progress",0);
@ -144,16 +179,28 @@ public class Activity_cache extends Activity_base {
if( intent.hasExtra("taskId")){
taskId = intent.getIntExtra("taskId",0);
}
if( intent.hasExtra("status")){
status = intent.getIntExtra("status",0);
}
Log.d(TAG, String.format("onReceive: taskId %s progress %s ",taskId,progress));
for(DownloadTask dt : mData){
if(taskId == dt.getId()){
dt.setFinishedChpats(progress);
if(dt.getDownSatus()!=DownloadTask.DownStatus.等待下载) {
if(status==1){
dt.setStatus(1);
dt.setDownSatus(DownloadTask.DownStatus.下载完成);
}else
if(dt.getDownSatus()!=DownloadTask.DownStatus.暂停下载) {
dt.setDownSatus(DownloadTask.DownStatus.正在下载);
dt.setStatus(0);
}
// dt = LitePal.find(DownloadTask.class,taskId);
}else{
if(dt.getDownSatus()!=DownloadTask.DownStatus.正在下载) {
if(dt.getDownSatus()==DownloadTask.DownStatus.正在下载) {
dt.setDownSatus(DownloadTask.DownStatus.排队中);
}
}
@ -240,28 +287,36 @@ public class Activity_cache extends Activity_base {
holder.tvTitle.setText(mDatas.get(position).getNovelTitle());
holder.tvSource.setText(mDatas.get(position).getDomainName());
boolean finished = mData.get(position).getFinishedChpats() == mData.get(position).getTotalChapts();
holder.tvSize.setText( FileUtils.getCacheSizeK(mData.get(position).getNovelId()));
if( mData.get(position).getTotalChapts() >0) {
float progress = mData.get(position).getFinishedChpats() *100/ mData.get(position).getTotalChapts() ;
holder.tvProgress.setText(String.format("%s/%s",mData.get(position).getFinishedChpats() , mData.get(position).getTotalChapts()));
holder.tvProgress.setText(String.format("%s/%s",mData.get(position).getFinishedChpats() >mData.get(position).getTotalChapts()?mData.get(position).getTotalChapts():mData.get(position).getFinishedChpats() , mData.get(position).getTotalChapts()));
holder.barProgress.setProgress((int) progress);
holder.tvStatus.setText( mData.get(position).getDownSatus() == DownloadTask.DownStatus.正在下载 ?"正在下载"
: mData.get(position).getDownSatus() == DownloadTask.DownStatus.等待下载? "暂停下载" :"休眠中");
: mData.get(position).getDownSatus() == DownloadTask.DownStatus.暂停下载? "暂停下载" :"休眠中");
holder.tvStatus.setText( mData.get(position).getStatus()==0 || mData.get(position).getFinishedChpats() >=mData.get(position).getTotalChapts()
? holder.tvStatus.getText():"下载完成" );
holder.tvStatus.setText( mData.get(position).getStatus()==1 || mData.get(position).getFinishedChpats() >=mData.get(position).getTotalChapts()
? "下载完成" : holder.tvStatus.getText() );
holder.tvStatus.setText( mData.get(position).getStatus()==0? holder.tvStatus.getText():"下载完成" );
holder.tvStatus.setText( mData.get(position).getDownSatus() == DownloadTask.DownStatus.排队中?"排队中": holder.tvStatus.getText() );
holder.barProgress.setProgress((int)progress);
}
// holder.imgStart.setVisibility(View.GONE);
int img = R.mipmap.play;
img = mData.get(position).getDownSatus() == DownloadTask.DownStatus.正在下载 ? R.mipmap.pause : R.mipmap.play;
holder.imgStart.setImageResource( img);
holder.imgStart.setEnabled(true);
if( mData.get(position).getStatus()==1|| mData.get(position).getFinishedChpats() >=mData.get(position).getTotalChapts()) {
holder.tvStatus.setText( "下载完成");
holder.imgStart.setEnabled(false);
holder.imgStart.setImageResource( R.mipmap.pause);
}
}
// holder.imgStart.setVisibility(View.GONE);
holder.imgStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -275,7 +330,7 @@ public class Activity_cache extends Activity_base {
}else{
startDownloadService(mData.get(pos).getId(),false);
holder.imgStart.setImageResource( R.mipmap.play);
mData.get(pos).setDownSatus(DownloadTask.DownStatus.等待下载);
mData.get(pos).setDownSatus(DownloadTask.DownStatus.暂停下载);
}
mData.get(pos).update( mData.get(pos).getId());
@ -339,6 +394,8 @@ public class Activity_cache extends Activity_base {
ImageView imgStart;
@BindView(R.id.tvSource)
TextView tvSource;
@BindView(R.id.tvSize)
TextView tvSize;
public MyViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);

View File

@ -497,7 +497,8 @@ public class BookActivity extends Activity_base {
private void startDownloadService(int taskId) {
Intent serviceIntent = getSvrIntent();
serviceIntent.putExtra("taskId",taskId);
// serviceIntent.putExtra("taskId",taskId);
// serviceIntent.putExtra("start",true);
startService(serviceIntent);
}
@ -758,7 +759,11 @@ void onResponseProcess( String content ,String url){
}
if(novelId == mNovel.getId()){
btnCach.setText(progress +"/" +pageFactory.getChapters().size());
try {
btnCach.setText(progress + "/" + pageFactory.getChapters().size());
}catch (Exception e){
Log.e(TAG, "onReceive: ", e);
}
}

View File

@ -54,6 +54,7 @@ import com.novelbook.android.utils.ImageUtil;
import com.novelbook.android.utils.MyImageLoader;
import com.novelbook.android.utils.OnItemClickListener;
import com.novelbook.android.utils.PageFactory;
import com.umeng.analytics.MobclickAgent;
import com.youth.banner.loader.ImageLoader;
import org.litepal.LitePal;
@ -391,4 +392,16 @@ public abstract class BasicFragment extends Fragment {
public void loadData() {
initData();
} //on tab changed
@Override
public void onResume() {
super.onResume();
MobclickAgent.onPageStart(TAG);
}
@Override
public void onPause(){
super.onPause();
hideProgress();
MobclickAgent.onPageEnd(TAG);
}
}

View File

@ -356,9 +356,8 @@ void test(int maxAge){
}
});
TextView tvCache =(TextView) bottomSheetDialog.findViewById(R.id.tvCache);
long size = FileUtils.getCacheSize(bookLists.get(position).getId());
size = size/1024;
tvCache.setText(String.format("%sK",size));
tvCache.setText(FileUtils.getCacheSizeK(bookLists.get(position).getId()));
LinearLayout llClearCache =(LinearLayout) bottomSheetDialog.findViewById(R.id.llClearCache);
llClearCache.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {

View File

@ -274,7 +274,7 @@ public class Fragment_booklist extends BasicFragment {
}else if(!TextUtils.isEmpty(keyWord)){ //搜索
// showProgressDialog(true, "正在加载搜索");
mAdapter.setShowTop(true);
// mAdapter.setShowTop(true);
BookSubscribe.getSearchNovelList( keyWord,pageNo, Constants.SEX, new OnSuccessAndFaultSub(successAndFaultListener, getActivity()));
}else if(!TextUtils.isEmpty(history)){
loadHistory();

View File

@ -20,6 +20,7 @@ import com.novelbook.android.R;
import com.novelbook.android.adapter.JudgeNestedScrollView;
import com.novelbook.android.bean.Progress;
import com.novelbook.android.db.Novel;
import com.novelbook.android.netapi.RandomHost;
import com.novelbook.android.netsubscribe.BookSubscribe;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
@ -498,6 +499,8 @@ final String TAG = Fragment_paihang.class.getSimpleName();
}
void getSearchTabTtitle(){
BookSubscribe.getSearchTitles(new OnSuccessAndFaultSub(new OnSuccessAndFaultListener() {
@Override
public void onSuccess(String result) {
@ -508,17 +511,6 @@ final String TAG = Fragment_paihang.class.getSimpleName();
Constants.lstSex = GsonUtil.parserStringBlocks(result,"sex");
Constants.lstNt =GsonUtil.parserStringBlocks(result,"nt");
// Constants.lstProgress =GsonUtil.parserProgressBlocks(result,"progress");
/* getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
initTabs(); // refresh ui 的操作代码
}
});*/
initTabs();
loadSearchData();
} catch (Exception e) {
@ -533,8 +525,8 @@ final String TAG = Fragment_paihang.class.getSimpleName();
public void onFault(String errorMsg) {
//失败
Log.d(TAG, "error on get firstpage: " + errorMsg);
// getSearchTabTtitle();
handler.sendEmptyMessage(0);
}
},getActivity()));

View File

@ -69,6 +69,7 @@ public class Main2Activity extends Activity_base
@Override
protected void onCreate(Bundle savedInstanceState) {
getHostPolicy();
super.onCreate(savedInstanceState);
//PageFactory.createPageFactory(this);
app =(MyApp) getApplicationContext();
@ -77,6 +78,7 @@ public class Main2Activity extends Activity_base
// ButterKnife.bind(this);
initialSexOption();
checkUpdate(true);
// getSearchTabTtitle();
}
@ -532,8 +534,10 @@ private int bottomSelectedIndex;
// mFirstPage= gson.fromJson(result, FirstPage.class);
try {
JSONObject jsonObject = new JSONObject(result);
String resultstr = jsonObject.getString("nts");
String resultstr = jsonObject.getString("hosts");
Config config =Config.createConfig(Main2Activity.this);
config.setBaseUrl(resultstr);
// config.setRootUrl( jsonObject.getString("masterDomains"));
} catch (Exception e) {
e.printStackTrace();

View File

@ -3,9 +3,13 @@ package com.novelbook.android;
import android.app.Application;
import android.content.Context;
import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.utils.Config;
import com.novelbook.android.utils.LogcatHelper;
import com.novelbook.android.utils.PageFactory;
import com.umeng.analytics.MobclickAgent;
import com.umeng.commonsdk.UMConfigure;
import org.litepal.LitePal;
@ -14,6 +18,7 @@ public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
HttpMethods.USERAGENT = NetUtil.getUserAgent();
applicationContext = getApplicationContext();
Config.createConfig(this);
PageFactory.createPageFactory(this);
@ -23,6 +28,10 @@ public class MyApp extends Application {
LitePal.initialize(this);
}
public void initApi(){
UMConfigure.init(applicationContext,UMConfigure.DEVICE_TYPE_PHONE,null);
MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.AUTO);
}
public boolean exit() {
System.exit(0);
return true;

View File

@ -91,7 +91,7 @@ public class DownloadTask extends LitePalSupport implements Serializable {
}
public static enum DownStatus{
初始状态,等待下载, 正在下载,排队中,下载完成
初始状态,暂停下载, 正在下载,排队中,下载完成
}
}

View File

@ -91,7 +91,8 @@ public interface HttpApi {
@GET("page/hot-keywords")
Observable<ResponseBody> getSearchHotKeys();
@GET("download/version.xml")
Observable<ResponseBody> getVersion();
}

View File

@ -0,0 +1,70 @@
package com.novelbook.android.netapi;
import java.util.Random;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class RandomHost {
private static final int MAX = 10;
private static final Random random = new Random();
//private static final Map<String, int[]> indexsMap = new HashMap<String, int[]>();
private JSONObject hosts = null;
private String uri = null;
private int[] indexs = new int[10];
public RandomHost(JSONObject hosts, String uri) throws JSONException {
this.hosts = hosts;
this.uri = uri;
String hostName = UrlFactory.getHost(uri);
indexs = new int[MAX];
JSONArray us = hosts.getJSONArray(hostName);
int maxFixIndex = us == null ||us.length()==0 ? 0 :us.length();
if (maxFixIndex > 0) {
randomFill(indexs, 0, 0, maxFixIndex - 1);
}
for (int i = maxFixIndex; i < 10; i++) {
indexs[i] = i;
}
//randomFill(indexs, maxFixIndex, maxFixIndex, MAX - 1);
}
private static boolean in(int[] values, int maxIndex, int value) {
for (int i = 0; i <= maxIndex; i++) {
if (values[i] == value) return true;
}
return false;
}
private static void randomFill(int[] indexs, int fromIndex, int min, int max) {
for (int i = min; i <= max; i++) {
while (true) {
int value = random.nextInt(max + 1);
if (value < min) continue;
if (in(indexs, fromIndex + i - min - 1, value)) continue;
indexs[ fromIndex + i - min] = value;
break;
}
}
}
private int currentIndex = 0;
public String next() {
if (currentIndex >= indexs.length )
return "";
else {
try {
return UrlFactory.getUrl(hosts, uri, indexs[currentIndex++]);
} catch (JSONException e) {
e.printStackTrace();
}
}
return "";
}
}

View File

@ -4,13 +4,17 @@ import android.text.TextUtils;
import com.novelbook.android.utils.Config;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by 眼神 on 2018/3/27.
*/
public class URLConstant {
//存放全部的URL可分为开发测试正式
private static String BASE_URL = Config.getInstance().getBaseUrl() ;//https://api.douban.com/v2/movie/";
private static String ROOT_URL = Config.getInstance().getRootUrl() ;//https://api.douban.com/v2/movie/";
public static String[] BASE_URLS = {"http://xiaoshuofenxiang.com/api/"};
@ -18,29 +22,29 @@ public class URLConstant {
* 取新的baseURL
* @return
*/
public static String newBaseUrl(){
public static String newRootUrl(){
for (String url:BASE_URLS) {
if(!url.equals(BASE_URL)){
BASE_URL = url;
if(!url.equals(ROOT_URL)){
ROOT_URL = url;
break;
}
}
if(! Config.getInstance().getBaseUrl().equals(BASE_URL)){
Config.getInstance().setBaseUrl(BASE_URL);
if(! Config.getInstance().getBaseUrl().equals(ROOT_URL)){
Config.getInstance().setBaseUrl(ROOT_URL);
}
return BASE_URL;
return ROOT_URL;
}
/**
* app初始化取上次保存的baseurl
* @return
*/
public static String getBaseUrl(){
BASE_URL=Config.getInstance().getBaseUrl();
if(TextUtils.isEmpty(BASE_URL)){
BASE_URL = newBaseUrl();
}
return BASE_URL;
public static String getRootUrl() {
ROOT_URL=Config.getInstance().getRootUrl();
return ROOT_URL;
}

View File

@ -0,0 +1,61 @@
package com.novelbook.android.netapi;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class UrlFactory {
public static String getHost(String uri) {
String key = "master";
if (uri.startsWith("/api/search/")) {
key = "search";
} else if (uri.startsWith("/api/n/")) {
key = "novel";
} else if (uri.startsWith("/api/novels/")) {
key = "novelsbydot";
} else if (uri.startsWith("/api/r/")) {
key = "report";
} else if (uri.startsWith("/api/page/")) {
key = "page";
} else if (uri.startsWith("/api/u/")) {
key = "user";
}
return key;
}
public static String getUrl(JSONObject host, String uri, int index) throws JSONException {
if (uri == null) return "";
String key = getHost(uri);
JSONArray us = null;
if (host != null) {
us = host.getJSONArray(key);
if (us != null && us.length() > index) {
return us.getString(index) ;//+ uri;
}
}
int value = (us == null || us.length()==0) ? index : index - us.length();
int second = 90 + 7;
int a1 = value / 2 +1;
int a2 = value % 2;
return String.format("http://%s%s%s.%s%s%s%s.com", key.charAt(0), (char)(second + a2), a1, "xiao", "shuo", "fen", "xiang");
}
public static void main(String[] args) {
/*String[] keys = new String[] {"/api/search/", "/api/n/", "/api/novels/", "/api/r/", "/api/page/", "/api/u/", "/api/g/"};
String text = FileUtil.read("C:\\MyWorkSpace\\WorkRoom\\cms4\\app\\xiaoshuofenxiang\\web\\api\\g\\Setting.json", "utf-8");
JSONObject hosts = JSONObject.parseObject(text).getJSONObject("data").getJSONObject("hosts");
for (String key : keys ) {
RandomHost rh = new RandomHost(hosts, key);
for (int i = 0; i < 11; i++) {
String url = rh.next();
System.out.println(String.format("for %s and index = %s, url=%s", key, i, url));
}
}*/
}
}

View File

@ -18,74 +18,78 @@ public class BookSubscribe {
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getMastDomain(DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getMasterDomain();
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/g").getHttpApi().getMasterDomain();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovel(int novelId,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovel(novelId);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/n/%s",novelId)).getHttpApi().getNovel(novelId);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelSites(int novelId,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelSites(novelId);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/n/%s/mulu-urls",novelId)).getHttpApi().getNovelSites(novelId);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getSiteRule(String domain,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelRule(domain);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/s/%s.json",domain)).getHttpApi().getNovelRule(domain);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getFirstPage(int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getFirstPage(sex);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/page/index" )).getHttpApi().getFirstPage(sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getCates(int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getCates(sex);
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/noveltype").getHttpApi().getCates(sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getCateNovelList(String cate,int pageno,int sex,int progress,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getCateNovels(cate,pageno,sex,progress);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/search/nt/%s/%s",cate,pageno ) ).getHttpApi().getCateNovels(cate,pageno,sex,progress);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelPaihang(String fn,int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelPaihang(fn,sex);
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/rank").getHttpApi().getNovelPaihang(fn,sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelsRelated(int novelId,int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelsRelated(novelId,sex);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/n/%s/about",novelId ) ).getHttpApi().getNovelsRelated(novelId,sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelsSameAuthor(int novelId,int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelsSameAuthor(novelId,sex);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/n/%s/author",novelId ) ).getHttpApi().getNovelsSameAuthor(novelId,sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getSiteRanks( int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSiteRanks(sex);
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/siteranks").getHttpApi().getSiteRanks(sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getSiteRankDetail( String fn,int pageNo,int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSiteRankDetail(fn,pageNo,sex);
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/siteranks").getHttpApi().getSiteRankDetail(fn,pageNo,sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getSearchNovelList( String keyWord,int pageNo,int sex,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSeachNolvelist(keyWord,pageNo,sex);
Observable<ResponseBody> observable = HttpMethods.getInstance(String.format("/api/search/%s/%s",keyWord ,pageNo)).getHttpApi().getSeachNolvelist(keyWord,pageNo,sex);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getSearchTitles(DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSearchTitles();
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/topdata").getHttpApi().getSearchTitles();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getHotKeyWords(DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getSearchHotKeys();
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/page/hot-keywords").getHttpApi().getSearchHotKeys();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getNovelsByIds(String ids,DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance().getHttpApi().getNovelsByIds(ids);
Observable<ResponseBody> observable = HttpMethods.getInstance("/api/novels").getHttpApi().getNovelsByIds(ids);
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}
public static void getVersion(DisposableObserver<ResponseBody> subscriber){
Observable<ResponseBody> observable = HttpMethods.getInstance("download/version.xml").getHttpApi().getVersion();
HttpMethods.getInstance().toSubscribe(observable, subscriber);
}

View File

@ -6,12 +6,13 @@ import android.util.Log;
import com.novelbook.android.MyApp;
import com.novelbook.android.netapi.HttpApi;
import com.novelbook.android.netapi.RandomHost;
import com.novelbook.android.netapi.URLConstant;
import com.novelbook.android.utils.CommonUtil;
import com.novelbook.android.utils.FileUtils;
import org.json.JSONException;
import java.io.File;
import java.io.IOException;
@ -42,8 +43,8 @@ import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import static com.novelbook.android.netapi.URLConstant.getBaseUrl;
import static com.novelbook.android.netapi.URLConstant.newBaseUrl;
import static com.novelbook.android.netapi.URLConstant.getRootUrl;
import static com.novelbook.android.netapi.URLConstant.newRootUrl;
public class HttpMethods {
public String TAG = "HttpMethods";
@ -52,6 +53,7 @@ public class HttpMethods {
private static final int DEFAULT_CONNECT_TIMEOUT = 5;
private static final int DEFAULT_WRITE_TIMEOUT = 5;
private static final int DEFAULT_READ_TIMEOUT = 5;
public static String USERAGENT="";
private Retrofit retrofit;
private HttpApi httpApi;
/**
@ -70,7 +72,7 @@ public class HttpMethods {
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())//json转换成JavaBean
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl(getBaseUrl())
.baseUrl(getRootUrl())
.build();
httpApi = retrofit.create(HttpApi.class);
}
@ -81,6 +83,12 @@ public class HttpMethods {
}
//获取单例
public static HttpMethods getInstance(String keyUrl) {
SingletonHolder.INSTANCE.changeBaseUrl(NetUtil.getUrl(keyUrl));
return SingletonHolder.INSTANCE;
}
//获取单例
public static HttpMethods getInstance() {
return SingletonHolder.INSTANCE;
@ -104,6 +112,8 @@ public class HttpMethods {
}
public void changeBaseUrl(String baseUrl) {
okHttpBuilder.addInterceptor(new RetryInterceptor());
// okHttpBuilder.retryOnConnectionFailure(false);
retrofit = new Retrofit.Builder()
.client(okHttpBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
@ -112,9 +122,9 @@ public class HttpMethods {
.build();
httpApi = retrofit.create(HttpApi.class);
}
public void changeBaseUrl() {
/* public void changeBaseUrl() {
changeBaseUrl(newBaseUrl());
}
}*/
/**
* 获取httpService
*
@ -167,7 +177,7 @@ public class HttpMethods {
// .addHeader("Accept", "application/json")
// .addHeader("Content-Type", "application/json; charset=utf-8")
// .addHeader("Device", "Android")
.removeHeader("User-Agent").addHeader("User-Agent",NetUtil.getUserAgent()) // 随机agent
.removeHeader("User-Agent").addHeader("User-Agent",USERAGENT) // 随机agent
.tag(NetUtil.currentRequestTag)
.method(originalRequest.method(), originalRequest.body());
@ -207,6 +217,8 @@ public class HttpMethods {
//错误重连
okHttpBuilder.retryOnConnectionFailure(true);
// Install the all-trusting trust manager
final SSLContext sslContext;
try {

View File

@ -8,6 +8,12 @@ import android.util.Log;
import android.widget.ImageView;
import com.novelbook.android.MyApp;
import com.novelbook.android.netapi.RandomHost;
import com.novelbook.android.netapi.URLConstant;
import com.novelbook.android.utils.Config;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Random;
@ -22,10 +28,45 @@ public class NetUtil {
private static final String TAG= NetUtil.class.getSimpleName();
public static int currentRequestTag =0;
public static String hosts;
public static String getUrl(String key){
try {
JSONObject jsonObject = getHost();
if(jsonObject==null && key == "/api/g"){
return URLConstant.getRootUrl();
}
RandomHost rh = new RandomHost(jsonObject,key);
String url = rh.next();
if(!url.endsWith("/api/")){
url+="/api/";
}
return url;
} catch (JSONException e) {
e.printStackTrace();
}
return "";
}
public static JSONObject getHost() {
if (TextUtils.isEmpty(hosts)) {
Config config = Config.getInstance();
hosts = config.getBaseUrl();
}
Log.d(TAG, "getUrl: host is " + hosts);
if (TextUtils.isEmpty(hosts)) {
Log.e(TAG, "getHosts: error on get hosts");
}
try {
return new JSONObject(hosts);
} catch (Exception er) {
}
return null;
}
/**
* 判断是否有网络连接
*

View File

@ -14,8 +14,10 @@ import java.net.UnknownHostException;
import javax.net.ssl.SSLHandshakeException;
import io.reactivex.observers.DisposableObserver;
import okhttp3.HttpUrl;
import okhttp3.ResponseBody;
import retrofit2.HttpException;
import retrofit2.Response;
/**
* Created by 眼神 on 2018/3/27.
@ -125,6 +127,16 @@ public class OnSuccessAndFaultSub extends DisposableObserver<ResponseBody>
mOnSuccessAndFaultListener.onFault("安全证书异常");
} else if (e instanceof HttpException) {//请求的地址不存在
int code = ((HttpException) e).code();
Response<?> response = ((HttpException) e).response();
HttpUrl url= response.raw().request().url();
String host = url.host();
String key = url.query();
if (code == 504) {
Toast.makeText(context,"网络异常,请检查您的网络状态",Toast.LENGTH_LONG).show();
mOnSuccessAndFaultListener.onFault("网络异常,请检查您的网络状态");
@ -142,7 +154,7 @@ public class OnSuccessAndFaultSub extends DisposableObserver<ResponseBody>
//sleep 200
mOnSuccessAndFaultListener.onFault("服务限制");
}else if(code == 502) {
HttpMethods.getInstance().changeBaseUrl(); //更新基本信息
// HttpMethods.getInstance().changeBaseUrl(); //更新基本信息
try {
Toast.makeText(context, "服务器开小差了,请重试", Toast.LENGTH_LONG).show();
}catch (Exception e3){

View File

@ -0,0 +1,124 @@
package com.novelbook.android.netutils;
import android.text.TextUtils;
import android.util.Log;
import com.novelbook.android.netapi.RandomHost;
import org.json.JSONException;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class RetryInterceptor implements Interceptor {
private static final String TAG=RetryInterceptor.class.getSimpleName();
int RetryCount = 13;
RandomHost rh ;
public RetryInterceptor(){
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// try the request
Response response = doRequest(chain, request);
if(response!=null &&( response.isSuccessful() || response.code() ==200)){
return response;
}
int tryCount = 0;
String oldUrl = request.url().toString();
String key = oldUrl.substring(oldUrl.lastIndexOf(".com/")+5,oldUrl.length());
if(rh==null)
{
try {
rh = new RandomHost(NetUtil.getHost(), key);
Log.d(TAG, "HttpMethods intercept: create new RandomHost--------------------------");
} catch (JSONException e) {
Log.e(TAG, "intercept: ", e);
}
}
String url =oldUrl;
while ( (response==null ||!response.isSuccessful()) && tryCount <= RetryCount) {
// if(tryCount>3)
{ //三次不成功后换其他url
url = switchServer(key);
if (url.equals(oldUrl)) {
url = switchServer(key);
}
if(TextUtils.isEmpty(url)){
return null;
}
}
Request newRequest = null;
try {
newRequest = request.newBuilder().url(url).build();
} catch (Exception e) {
Log.e(TAG, "HttpMethods intercept: "+url);
Log.e(TAG, "HttpMethods intercept: ", e);
return null;
}
Log.d("HttpMethods intercept", "Request is not successful - " + tryCount);
Log.d(TAG, "HttpMethods intercept: trying url is "+url);
tryCount++;
// retry the request
response = doRequest(chain, newRequest);
}
if (response == null) {
throw new IOException();
}
return response;
}
private Response doRequest(Chain chain, Request request) {
Response response = null;
try {
response = chain.proceed(request);
} catch (Exception e) {
}
return response;
}
private String switchServer(String key) {
String newUrl = rh.next();
if(TextUtils.isEmpty(newUrl)){
return newUrl;
}
if(!newUrl.endsWith("/")){
newUrl+="/";
}
return newUrl +key;
}
}

View File

@ -15,6 +15,7 @@ import com.novelbook.android.db.Chapter;
import com.novelbook.android.db.DownloadTask;
import com.novelbook.android.db.SiteRule;
import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.NetUtil;
import com.novelbook.android.utils.BookUtil;
import com.novelbook.android.utils.NovelParseUtil;
@ -146,7 +147,7 @@ public class ServiceDownload extends Service {
cancelId.add(taskId);
for(DownloadTask t : downloadTasks){
if( t.getId() == taskId){
t.setDownSatus(DownloadTask.DownStatus.等待下载);
t.setDownSatus(DownloadTask.DownStatus.暂停下载);
break;
}
}
@ -246,11 +247,20 @@ public class ServiceDownload extends Service {
/* if(msg.what ==1){
startTask();
}else*/
if(msg.what==2){
if (msg.what == 2) {
if(!NetUtil.isNetworkConnected()) {
/* Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ServiceDownload.ChapterContent.finished");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("network", "没有网络了,下载失败");
sendBroadcast(broadcastIntent);*/
return;
}
int tIndex = msg.getData().getInt("tIndex");
if(tIndex>=downloadTasks.size()) {
if (tIndex >= downloadTasks.size()) {
return;
}
int taskId = downloadTasks.get(tIndex).getId();
@ -262,13 +272,13 @@ public class ServiceDownload extends Service {
}
*/
if(tasksMap.get(taskId)==null){
if (tasksMap.get(taskId) == null) {
return;
}
Log.d(TAG,String.format("%s start new chapt download---- taskId :%s, chapter count %s,chaptIndex %s",TAG
Log.d(TAG, String.format("%s start new chapt download---- taskId :%s, chapter count %s,chaptIndex %s", TAG
, processingTask.getId(),
tasksMap.get(processingTask.getId()).size(),chaptIndex ));
tasksMap.get(processingTask.getId()).size(), chaptIndex));
// if(taskIndex==tIndex+1){
@ -276,47 +286,84 @@ public class ServiceDownload extends Service {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ServiceDownload.ChapterContent.finished");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("progress", processingTask.getFinishedChpats()>processingTask.getTotalChapts() ?processingTask.getTotalChapts():processingTask.getFinishedChpats());
broadcastIntent.putExtra("progress", processingTask.getFinishedChpats() > processingTask.getTotalChapts() ? processingTask.getTotalChapts() : processingTask.getFinishedChpats());
broadcastIntent.putExtra("novelId", processingTask.getNovelId());
broadcastIntent.putExtra("taskId", processingTask.getId());
sendBroadcast(broadcastIntent);
// }
//
if (downloadTasks.get(tIndex).getDownSatus() != DownloadTask.DownStatus.正在下载) {
if( tasksMap.get(taskId).size()-1 > chaptIndex){
if( downloadTasks.get(tIndex).getDownSatus() == DownloadTask.DownStatus.正在下载) {
chaptIndex++;
}else{
startNewTask();
return;
}
}else{
Log.d(TAG,String.format("%s task done ---- taskId :%s, chapter count %s,chaptIndex %s",TAG , processingTask.getId(),
tasksMap.get(processingTask.getId()).size(),chaptIndex ));
}
// if( Chapter.getUnCachedChapters(taskId).size() >0 ){
//if( tasksMap.get(taskId).size()-1 > chaptIndex){
if (tasksMap.get(taskId).size() - 1 > chaptIndex) {
chaptIndex++;
// }
/* else{
startNewTask();
return;
}*/
} else {
Log.d(TAG, String.format("%s task done ---- taskId :%s, chapter count %s,chaptIndex %s", TAG, processingTask.getId(),
tasksMap.get(processingTask.getId()).size(), chaptIndex));
//章节全部处理完毕了
if(taskId == processingTask.getId()) {
if (taskId == processingTask.getId()
&& tasksMapDone.get(taskId) != null
&& tasksMapDone.get(taskId).size() == tasksMap.get(taskId).size()) {
int abc = 1;
abc++;
if(tasksMap.get(taskId).size() == tasksMapDone.get(taskId).size()) {
processingTask.setFinishedChpats(processingTask.getTotalChapts());
processingTask.setStatus(1);
processingTask.setDownSatus(DownloadTask.DownStatus.下载完成);
processingTask.update(processingTask.getId());
// tasksMap.remove(processingTask.getId()); //会不会线程冲突
}
tasksMap.remove(taskId);
broadcastIntent = new Intent();
broadcastIntent.setAction("ServiceDownload.ChapterContent.finished");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("progress", processingTask.getTotalChapts());
broadcastIntent.putExtra("status", processingTask.getStatus());
broadcastIntent.putExtra("taskId", processingTask.getId());
sendBroadcast(broadcastIntent);
}
//startTask(); //auto start next task
startNewTask();
return;
}
doDownloadContent(tIndex,chaptIndex);
doDownloadContent(tIndex, chaptIndex);
}
}
};
void startNewTask(){
if(!NetUtil.isNetworkConnected()){
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("ServiceDownload.ChapterContent.finished");
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra("network", "没有网络了,下载失败");
sendBroadcast(broadcastIntent);
return;
}
taskIndex=0;
startTask(); //auto start next task
}
private void stopTask(int taskId) {
@ -354,7 +401,9 @@ public class ServiceDownload extends Service {
* auto next task
*/
private void startTask() {
if ( downloadTasks.size()==0){
if ( downloadTasks.size()==0 || downloadTasks.size() <=taskIndex){
Log.d(TAG,"ServiceDownload No Task to do, exit.");
return;
}
if(processingTask!=null) {
@ -363,15 +412,17 @@ public class ServiceDownload extends Service {
Log.d(TAG,"ServiceDownload start task to download,index " +taskIndex);
if(downloadTasks.size() <=taskIndex){
/* if(downloadTasks.size() <=taskIndex){
taskIndex=0;
processingTask =null;
// Log.d(TAG,"No task to download.");
// return;
}
}*/
processingTask = downloadTasks.get(taskIndex);
if(processingTask.getDownSatus()== DownloadTask.DownStatus.等待下载){
if(processingTask.getDownSatus()== DownloadTask.DownStatus.暂停下载
||processingTask.getDownSatus()== DownloadTask.DownStatus.下载完成
){
taskIndex++;
startTask();
return;
@ -397,7 +448,15 @@ public class ServiceDownload extends Service {
if(chps!=null && chps.size()>0 && chps.size() >chaptIndex) {
Chapter chapter = chps.get(chaptIndex);
if (TextUtils.isEmpty(chapter.getChapterPath())) {
/* while(!NetUtil.isNetworkConnected() ){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
if (NetUtil.isNetworkConnected() && TextUtils.isEmpty(chapter.getChapterPath())) {
try {
ServiceDownload(taskIndex,chapter);
} catch (JSONException e) {
@ -510,7 +569,8 @@ public class ServiceDownload extends Service {
}
try {
String bodyStr = body.string();
// NovelParseUtil.enconding(body, siteRuleMap.get(chapter.getNovelId()).getEncoding());
String bodyStr =NovelParseUtil.enconding(body, siteRuleMap.get(chapter.getNovelId()).getEncoding());; //body.string();
String title = chapter.getChapterName();
String chapterContent = title+ "\n" + NovelParseUtil.getChapterContent(bodyStr, siteJson);
char[] buf = chapterContent.toCharArray();

View File

@ -155,7 +155,7 @@ public class ServiceDownloadIntent extends IntentService {
private void stopTask(int taskId) {
for(DownloadTask dt : downloadTasks){
if(dt.getId() == taskId){
dt.setDownSatus(DownloadTask.DownStatus.等待下载);
dt.setDownSatus(DownloadTask.DownStatus.暂停下载);
}
}
@ -169,7 +169,7 @@ public class ServiceDownloadIntent extends IntentService {
startTask();
}else if(msg.what==2){
if( downloadTasks.get(taskIndex).getDownSatus() == DownloadTask.DownStatus.等待下载){
if( downloadTasks.get(taskIndex).getDownSatus() == DownloadTask.DownStatus.暂停下载){
return;
}
if(tasksMap.get(processingTask.getId())==null){
@ -229,7 +229,7 @@ public class ServiceDownloadIntent extends IntentService {
}
processingTask = downloadTasks.get(taskIndex);
if(processingTask.getDownSatus()== DownloadTask.DownStatus.等待下载){
if(processingTask.getDownSatus()== DownloadTask.DownStatus.暂停下载){
taskIndex++;
startTask();
return;

View File

@ -0,0 +1,67 @@
package com.novelbook.android.upgrade;
import java.io.InputStream;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
*/
public class ParseXmlService
{
public HashMap<String, String> parseXml(InputStream inStream) throws Exception
{
HashMap<String, String> hashMap = new HashMap<String, String>();
// 实例化一个文档构建器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 通过文档构建器工厂获取一个文档构建器
DocumentBuilder builder = factory.newDocumentBuilder();
// 通过文档通过文档构建器构建一个文档实例
Document document = builder.parse(inStream);
//获取XML文件根节点
Element root = document.getDocumentElement();
//获得所有子节点
NodeList childNodes = root.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++)
{
//遍历子节点
Node childNode = childNodes.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE){
Element childElement = (Element) childNode;
hashMap.put(childElement.getNodeName(),childElement.getFirstChild().getNodeValue());
}
/*if (childNode.getNodeType() == Node.ELEMENT_NODE)
{
Element childElement = (Element) childNode;
//版本号
if ("version".equals(childElement.getNodeName()))
{
hashMap.put("version",childElement.getFirstChild().getNodeValue());
}
//软件名称
else if (("name".equals(childElement.getNodeName())))
{
hashMap.put("name",childElement.getFirstChild().getNodeValue());
}
//下载地址
else if (("url".equals(childElement.getNodeName())))
{
hashMap.put("url",childElement.getFirstChild().getNodeValue());
}
else if (("details".equals(childElement.getNodeName())))
{
hashMap.put("details",childElement.getFirstChild().getNodeValue());
}
}*/
}
return hashMap;
}
}

View File

@ -0,0 +1,440 @@
package com.novelbook.android.upgrade;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.novelbook.android.R;
import com.novelbook.android.ReadActivity;
import com.novelbook.android.db.Novel;
import com.novelbook.android.netsubscribe.BookSubscribe;
import com.novelbook.android.netutils.HttpMethods;
import com.novelbook.android.netutils.OnSuccessAndFaultListener;
import com.novelbook.android.netutils.OnSuccessAndFaultSub;
import com.novelbook.android.utils.Constants;
import com.novelbook.android.utils.GsonUtil;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
import static com.novelbook.android.netapi.URLConstant.getRootUrl;
public class UpdateManager {
public static final String TAG ="com.qiyou.UpdateManager";
public static final String dTAG ="com.qiyou";
private static final int DOWNLOAD = 1;
private static final int DOWNLOAD_FINISH = 2;
private static final int showDialog =3;
HashMap<String, String> mHashMap;
private String mSavePath;
private int progress;
private boolean cancelUpdate = false;
private Context mContext;
private ProgressBar mProgress;
private Dialog mDownloadDialog;
private Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
switch (msg.what)
{
case DOWNLOAD:
mProgress.setProgress(progress);
break;
case DOWNLOAD_FINISH:
installApk();
break;
case showDialog:
showNoticeDialog();
break;
default:
break;
}
};
};
public UpdateManager(Context context)
{
this.mContext = context;
// app =(QiYouApplication)context;
}
/**
* 拷绁存潪顖欐閺囧瓨鏌<EFBFBD>
*/
public void checkUpdate()
{
String urlStr = getRootUrl()+ Constants.VERSION_ADDRESS;
urlStr ="http://xiaoshuofenxiang.com/version.xml";
checkUpdate(urlStr);
/*if (isUpdate())
{
showNoticeDialog();
} else
{
Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();
}*/
}
boolean isSilence =false;
public void checkUpdateSilence()
{
isSilence=true;
checkUpdate();
}
void checkUpdate(String url){
Request request = new Request.Builder()
.url(url).build();
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d(TAG, " 版本检查错误 onFailure(int, Header[],byte[], Throwable ) was received");
if(!isSilence)
Toast.makeText(mContext, "版本检查出错了", Toast.LENGTH_LONG).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if(response.code()!=200) {
Log.e(TAG, "check update onResponse:return code" +response.code() );
}
ResponseBody body = response.body();
try {
byte[] bytes = body.bytes();
// String s = body.string();
// Log.d(TAG, "onSuccess: response is " + s);
if (bytes != null) {
processTxtOnSuccess(bytes);
}
// body.close();
}catch (Exception e){
Log.e(TAG, "onResponse: ",e );
}finally {
}
}
});
}
void processTxtOnSuccess(byte[] paramArrayOfByte) {
boolean isUpdate=false;
int versionCode = getVersionCode(mContext);
InputStream inputStream = null;
inputStream =new ByteArrayInputStream(paramArrayOfByte);
ParseXmlService service = new ParseXmlService();
try
{
if(inputStream!=null)
mHashMap = service.parseXml(inputStream);
} catch (Exception e)
{
e.printStackTrace();
}
if (null != mHashMap)
{
int serviceCode = Integer.valueOf(mHashMap.get("version"));
// need update or not
isUpdate =serviceCode > versionCode;
}
if (isUpdate)
{
mHandler.sendEmptyMessage(showDialog);
} else
{
if(!isSilence)
Toast.makeText(mContext, R.string.soft_update_no, Toast.LENGTH_LONG).show();
}
}
/**
* 閼惧嘲褰囨潪顖欐閻楀牊婀伴崣锟<EFBFBD> *
* @param context
* @return
*/
public int getVersionCode(Context context)
{
int versionCode = 0;
try
{
// 閼惧嘲褰囨潪顖欐閻楀牊婀伴崣鍑ょ礉鐎电懓绨睞ndroidManifest.xml娑撳獘ndroid:versionCode
versionCode = context.getPackageManager().getPackageInfo("com.novelbook.android", 0).versionCode;
} catch (NameNotFoundException e)
{
Log.e(TAG, "getVersionCode: ",e);
}
return versionCode;
}
/**
* 閼惧嘲褰囨潪顖欐閻楀牊婀伴崣锟<EFBFBD> *
* @param context
* @return
*/
public static String getVersionName(Context context)
{
String versionName = "";
try
{
// 閼惧嘲褰囨潪顖欐閻楀牊婀伴崣鍑ょ礉鐎电懓绨睞ndroidManifest.xml娑撳獘ndroid:versionCode
versionName = context.getPackageManager().getPackageInfo("com.qiyou.mb.android", 0).versionName;
} catch (NameNotFoundException e)
{
Log.e(TAG, "getVersionCode: ",e);
}
return versionName;
}
/**
* 閺勫墽銇氭潪顖欐閺囧瓨鏌婄<EFBFBD>纭呯樈濡楋拷
*/
private void showNoticeDialog()
{
/*final AlertDialog.Builder normalDialog =
new AlertDialog.Builder(mContext);
normalDialog.setTitle("退出阅读");
normalDialog.setMessage("确定退出阅读吗?");
normalDialog.setPositiveButton("继续阅读",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
normalDialog.setNegativeButton("退出阅读",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
normalDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
});
// 显示
normalDialog.show();
*/
// 閺嬪嫰锟界<EFBFBD>纭呯樈濡楋拷
Builder builder = new Builder(mContext);
builder.setTitle(R.string.soft_update_title);
String upgradeDetails=mHashMap.get("details");
builder.setMessage( mContext.getString(R.string.soft_update_info) +upgradeDetails );
builder.setPositiveButton(R.string.soft_update_updatebtn, new OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
showDownloadDialog();
}
});
// 缁嬪秴鎮楅弴瀛樻煀
builder.setNegativeButton(R.string.soft_update_later, new OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
});
Dialog noticeDialog = builder.create();
noticeDialog.show();
}
/**
* 閺勫墽銇氭潪顖欐娑撳娴囩<EFBFBD>纭呯樈濡楋拷
*/
private void showDownloadDialog()
{
// 閺嬪嫰锟芥潪顖欐娑撳娴囩<EFBFBD>纭呯樈濡楋拷
Builder builder = new Builder(mContext);
builder.setTitle(R.string.soft_updating);
// 缂佹瑤绗呮潪钘夘嚠鐠囨繃顢嬫晶鐐插稑瀹抽弶锟<EFBFBD>
final LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.softupgrade_progress, null);
mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
builder.setView(v);
// 閸欐牗绉烽弴瀛樻煀
builder.setNegativeButton(R.string.soft_update_cancel, new OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
// 鐠佸墽鐤嗛崣鏍ㄧХ閻樿埖锟<EFBFBD>
cancelUpdate = true;
}
});
mDownloadDialog = builder.create();
mDownloadDialog.setCancelable(false);
mDownloadDialog.show();
// 閻滄澘婀弬鍥
downloadApk();
}
/**
* 娑撳娴嘺pk閺傚洣娆<EFBFBD>
*/
private void downloadApk()
{
// 閸氼垰濮弬鎵殠缁嬪绗呮潪鍊熻拫娴狅拷
new downloadApkThread().start();
}
/**
* 娑撳娴囬弬鍥缁捐法鈻<EFBFBD>
*/
private class downloadApkThread extends Thread
{
@Override
public void run()
{
try
{
// 閸掋倖鏌嘢D閸椻剝妲搁崥锕<EFBFBD>摠閸煉绱濋獮鏈电瑬閺勵垰鎯侀崗閿嬫箒鐠囪鍟撻弶鍐
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
// 閼惧嘲绶辩<EFBFBD>妯哄亶閸楋紕娈戠捄顖氱窞
String sdpath = Environment.getExternalStorageDirectory() + "/";
mSavePath = sdpath + "download";
URL url = new URL(mHashMap.get("url"));
// 閸掓稑缂撴潻鐐村复
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
// 閼惧嘲褰囬弬鍥婢堆冪毈
int length = conn.getContentLength();
// 閸掓稑缂撴潏鎾冲弳濞达拷
InputStream is = conn.getInputStream();
File file = new File(mSavePath);
// 閸掋倖鏌囬弬鍥喖缍嶉弰顖氭儊鐎涙ê婀<EFBFBD>
if (!file.exists())
{
file.mkdir();
}
File apkFile = new File(mSavePath, mHashMap.get("name"));
FileOutputStream fos = new FileOutputStream(apkFile);
int count = 0;
// 缂傛挸鐡<EFBFBD>
byte buf[] = new byte[1024];
// 閸愭瑥鍙嗛崚鐗堟瀮娴犳湹鑵<EFBFBD>
do
{
int numread = is.read(buf);
count += numread;
// 鐠侊紕鐣绘潻娑樺閺夆<EFBFBD>缍呯純锟<EFBFBD>
progress = (int) (((float) count / length) * 100);
// 閺囧瓨鏌婃潻娑樺
mHandler.sendEmptyMessage(DOWNLOAD);
if (numread <= 0)
{
// 娑撳娴囩<EFBFBD>灞惧灇
mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
break;
}
// 閸愭瑥鍙嗛弬鍥
fos.write(buf, 0, numread);
} while (!cancelUpdate);// 閻愮懓鍤崣鏍ㄧХ鐏忓崬浠犲顤嶇瑓鏉烇拷
fos.close();
is.close();
}
} catch (MalformedURLException e)
{
Log.e(TAG, "run: ", e);
} catch (IOException e)
{
Log.e(TAG, "run: ", e);
}
// 閸欐牗绉锋稉瀣祰鐎电鐦藉鍡樻<EFBFBD>
mDownloadDialog.dismiss();
}
};
/**
* 鐎瑰顥朅PK閺傚洣娆<EFBFBD>
*/
private void installApk()
{
File apkfile = new File(mSavePath, mHashMap.get("name"));
if (!apkfile.exists())
{
return;
}
// 俺绻僆ntent鐎瑰顥朅PK閺傚洣娆<EFBFBD>
Intent i = new Intent(Intent.ACTION_VIEW);
i.setDataAndType(Uri.parse("file://" + apkfile.toString()), "application/vnd.android.package-archive");
mContext.startActivity(i);
}
}

View File

@ -11,6 +11,7 @@ import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
@ -749,7 +750,7 @@ int muluRetryCount =0;
return;
}
String url = mSite.getMuluUrl();
Request request = getTagRequest(url,mNovel.getMaxAge());
Request request = getTagRequest(url,mSite.getDomain(), mNovel.getMaxAge());
mMuluStatus = MuluStatus.isDownloading;
long startTime= new Date().getTime();
@ -1345,7 +1346,7 @@ int muluRetryCount =0;
String targetSiteName = msg.getData().getString("siteName");
Log.d(TAG, String.format("prepare book changing Source:target %s -- %s to open chapter %s"
,mNovel.getDomain(),targetSiteName,msg.arg1));
if(pagefactory!=null)
pagefactory.changeSource(targetSiteName, mNovel.getDomain(),msg.arg1,getChapter(msg.arg1).getChapterName());
@ -1436,7 +1437,7 @@ int muluRetryCount =0;
char[] block=null;
if(chaptCache.containsKey(Integer.valueOf(index))) {
block = chaptCache .get(index).getData().get();
// Log.d(TAG, String.format("prepare book get block in cache, chapter: %s", index));
Log.d(TAG, String.format("read content get block in cache, chapter: %s", index));
}
// Log.d(TAG, String.format("prepare book begin to load content for chapter %s", index));
if (block == null) {
@ -1626,6 +1627,10 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
}
Chapter chapter = mChapters.get(index -1);
String refUrl="";
if(index>1){
refUrl = mChapters.get(index -2).getChapterUrl();
}
String url = chapter.getChapterUrl();
if( TextUtils.isEmpty( url)){
handler.sendEmptyMessage(1);
@ -1640,7 +1645,7 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
JSONObject siteJson = new JSONObject();
siteJson.put("chapterContentRegex", mSiteRule.getChapterContentRegex());
siteJson.put("chapterContentDumpRegex", mSiteRule.getChapterContentDumpRegex());
Request request = getTagRequest(url, -1);
Request request = getTagRequest(url, refUrl,-1);
HttpMethods.getOkClient().newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
@ -1742,13 +1747,17 @@ private void loadChaptContent(final int chapterIndex) throws JSONException, Inte
* @param maxAge
* @return
*/
private Request getTagRequest(String url, int maxAge) {
private Request getTagRequest(String url, String refUrl ,int maxAge) {
Request.Builder builder = new Request.Builder()
.tag(mNovel.getNovelId()) //标记 请求的tag,切换小说或离开小说界面(BookActivity) 取消未执行完毕的 此tag的所有请求
.url(url)
.removeHeader("Pragma");
if(!TextUtils.isEmpty(refUrl)){
builder.header("Referer",refUrl);
}
for (int i = 0; i < mSiteRule.getHeaders().length; i += 2) {
builder.header(mSiteRule.getHeaders()[i], mSiteRule.getHeaders()[i + 1]);

View File

@ -18,7 +18,7 @@ public class Config {
private final static String SYSTEM_LIGHT_KEY = "systemlight";
private final static String PAGE_MODE_KEY = "pagemode";
private final static String KEY_BASE_URY = "baseurl";
private final static String KEY_ROOT_URL = "rooturl";
public final static String FONTTYPE_DEFAULT = "";
public final static String FONTTYPE_QIHEI = "font/qihei.ttf";
public final static String FONTTYPE_WAWA = "font/font1.ttf";
@ -182,13 +182,22 @@ public class Config {
}
public String getBaseUrl(){
return sp.getString(KEY_BASE_URY,"");
}
public void setBaseUrl(String baseUrl){
sp.edit().putString(KEY_BASE_URY,baseUrl).commit();
}
public String getBaseUrl(){
return sp.getString(KEY_BASE_URY,"");
}
public String getRootUrl(){
return sp.getString(KEY_ROOT_URL,"http://xiaoshuofenxiang.com/api/");
}
public void setRootUrl(String baseUrl){
sp.edit().putString(KEY_ROOT_URL,baseUrl).commit();
}
}

View File

@ -11,6 +11,7 @@ public class Constants {
public static final boolean SHOWAD =false ;
public static final int MAXAGE_MAX =60*60*24*28; //28 ;
public static final int MAXAGE_MULU = 60*60*24*7*2; //2周;;
public static final String VERSION_ADDRESS ="version.xml";
public static String[] HOT_KEYS_VALUE = {};
public static int SEX=1; //1 2女
public static String A_Regex = "<a[^>]+href[\\s]*=[\\s]*['\"]?([^'\"]+)['\"\\s]?[^>]*>([^<]+)<"; //TODO: 从服务器更新
@ -24,4 +25,5 @@ public class Constants {
// public static List<String> lstProgress=null;
public static boolean showDialogOnUi =true;
public static boolean showDialogOnUiPage =false;
}

View File

@ -109,7 +109,16 @@ public class FileUtils {
Fileutil.deleteDir(getNovelDir(novelId));
}
public static String getCacheSizeK(int noveId) {
float size = getCacheSize( noveId) ;
size = size/1024.00f;
if(size >1024){
size = size/1024.00f;
return String.format("%.1fM",size);
}
return String.format("%.1fK",size);
}
public static long getCacheSize(int noveId) {
return Fileutil.getDirSize(getNovelDir(noveId));
}

View File

@ -332,22 +332,6 @@ public static String enconding(ResponseBody body, String encode) throws Unsupp
}
return s;
/* //Log.i(TAG, " encoding covert from :" +source );
long st = new java.util.Date().getTime();
byte[] b = source.getBytes("utf-8");
// String info = new String(b, "utf-8");
String info = new String(b);
//Log.i(TAG, " encoding covert to :" +info );
//Log.i(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
return info;*/
/* long st = new java.util.Date().getTime();
byte[] b = source.getBytes(encode);
// String info = new String(b, "utf-8");
String info = new String(b,"utf-8");
//Log.i(TAG, " encoding covert to :" +info );
//Log.i(TAG, "encoding covert :" + encode +", cost " +( new Date().getTime() -st));
return info;*/
}

View File

@ -232,7 +232,7 @@ public class PageFactory implements ChangeSource{
chaptId = chaptId > 0 ? chaptId : 1;
final File file = new File(getChapterFileName(chaptId));
if (!file.exists()) { //待下载
if (!file.exists() && getChapters().size()>0) { //待下载
chaptId = chaptId > getChapters().size() ? getChapters().size() : chaptId;
chaptId = chaptId > 0 ? chaptId : 1;
@ -290,7 +290,7 @@ public class PageFactory implements ChangeSource{
@Override
public void run() {
Log.d(TAG, String.format("prepare book to download chapter %s ,thread.name %s",chid,Thread.currentThread().getName() ) );
mBookUtil.chaptChars(chid);
mBookUtil.chaptChars(chid); //TODO: 读取到上一章block后,file还是不存在的现在就死循环了
super.run();
}}.start();
@ -891,6 +891,7 @@ public static boolean busy(){
m_islastPage = false;
if(null == currentPage){
changeChapter(mBookUtil.getChapterNo());
return;
}
if(mBookUtil.isBusy()){
@ -900,7 +901,7 @@ public static boolean busy(){
if (currentPage.getEnd() >= mBookUtil.getBookLen()) {
Log.d(TAG,"已经是本章最后一页了");
m_islastPage =currentChapter >= mBookUtil.getChapters().size();
m_islastPage =currentChapter == mBookUtil.getChapters().size();
if ( m_islastPage){
Toast.makeText(mContext, "已经是最后一页了", Toast.LENGTH_SHORT).show();
return;

View File

@ -23,6 +23,14 @@
</android.support.design.widget.AppBarLayout>
<TextView
android:id="@+id/tvMsg"
android:textColor="@color/red"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycleView"
style="@style/llOutside"

View File

@ -42,6 +42,7 @@
android:textColor="@color/grey" />
</LinearLayout>
<LinearLayout
android:layout_marginTop="5dp"
android:orientation="horizontal"
@ -64,10 +65,23 @@
android:layout_height="20dp"
android:textSize="12sp"
android:gravity="right"
android:layout_marginStart="50dp"
android:layout_marginStart="0dp"
android:text="未知"
android:layout_weight="0"
android:textColor="@color/grey" />
<TextView
android:id="@+id/tvSize"
android:layout_width="match_parent"
android:layout_height="20dp"
android:textSize="12sp"
android:gravity="right"
android:layout_marginStart="0dp"
android:text="未知"
android:layout_weight="1"
android:textColor="@color/grey" />
</LinearLayout>
@ -87,9 +101,9 @@
<ImageView
android:clickable="true"
android:id="@+id/imgStart"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="10dp"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_margin="15dp"
android:src="@mipmap/play"
/>

View File

@ -4,22 +4,16 @@
tools:showIn="navigation_view">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_camera"
android:icon="@drawable/ic_mood_black_24dp"
android:title="消息通知" />
<item
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_mood_black_24dp"
android:title="最近浏览" />
<item
android:id="@+id/nav_slideshow"
android:icon="@drawable/ic_mood_black_24dp"
android:title="我的书单" />
<item
android:id="@+id/nav_huancun"
android:icon="@drawable/ic_mood_black_24dp"
android:title="缓存管理" />
android:title="下载管理" />
<item
android:id="@+id/nav_haoping"
android:icon="@drawable/ic_mood_black_24dp"
@ -32,10 +26,7 @@
android:id="@+id/nav_advice"
android:icon="@drawable/ic_mood_black_24dp"
android:title="意见反馈" />
<item
android:id="@+id/nav_nightmode"
android:icon="@drawable/ic_mood_black_24dp"
android:title="夜间模式" />
<item
android:id="@+id/nav_setup"
android:icon="@drawable/ic_menu_send"

View File

@ -112,7 +112,7 @@
<string name="title_activity_main5">Main5Activity</string>
<string name="title_on_shelf">加入书架</string>
<string name="title_read">立即阅读</string>
<string name="title_download">下载序列</string>
<string name="title_download">下载管理</string>
<string name="title_activity_paihangbang"></string>
<string name="title_activity_main6">Main6Activity</string>
<string name="section_format">Hello World from section: %1$d</string>
@ -191,6 +191,13 @@
<string name="noRecordInshelf">书架空空如也</string>
<string name="msgLoading">正在加载...</string>
<string name="refresh">重试</string>
<string name="soft_update_no">已是最新版本</string>
<string name="soft_update_title">有新版本了</string>
<string name="soft_update_info">更新日志</string>
<string name="soft_update_updatebtn">更新</string>
<string name="soft_update_later">以后再说</string>
<string name="soft_updating">正在更新</string>
<string name="soft_update_cancel">取消更新</string>
<string-array name="voicer_cloud_entries">
<item>小燕—女青、中英、普通话</item>

View File

@ -8,11 +8,11 @@
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SELECTED_BUILD_VARIANT" value="huaweiDebug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleHuaweiDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileHuaweiDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
<task>generateHuaweiDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
@ -23,23 +23,65 @@
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/debugUnitTest/compileDebugUnitTestJavaWithJavac/classes" />
<output url="file://$MODULE_DIR$/build/intermediates/javac/huaweiDebug/compileHuaweiDebugJavaWithJavac/classes" />
<output-test url="file://$MODULE_DIR$/build/intermediates/javac/huaweiDebugUnitTest/compileHuaweiDebugUnitTestJavaWithJavac/classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debug/compileDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/debugAndroidTest/compileDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/debugAndroidTest/compileDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/huawei/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/huaweiDebug/compileHuaweiDebugAidl/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/huawei/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/huaweiDebug/compileHuaweiDebugRenderscript/out" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/huawei/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/huawei/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huaweiDebug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/huawei/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/aidl_source_output_dir/huaweiDebugAndroidTest/compileHuaweiDebugAndroidTestAidl/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/huawei/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/renderscript_source_output_dir/huaweiDebugAndroidTest/compileHuaweiDebugAndroidTestRenderscript/out" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/huawei/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/huawei/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuaweiDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/huawei/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuaweiDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/huawei/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestHuawei/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testHuawei/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
@ -104,13 +146,17 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged-not-compiled-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/metadata_feature_manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/prebuild" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/processed_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-files" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res_stripped" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
@ -120,6 +166,8 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/reports" />
<excludeFolder url="file://$MODULE_DIR$/build/test-results" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
@ -173,6 +221,7 @@
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout-solver:1.1.3@jar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: net.sf.kxml:kxml2:2.3.0@jar" level="project" />
<orderEntry type="library" name="Gradle: io.reactivex.rxjava2:rxandroid:2.1.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.umeng.umsdk:analytics:8.0.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife-annotations:9.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.jakewharton:butterknife:9.0.0@aar" level="project" />
@ -189,6 +238,7 @@
<orderEntry type="library" name="Gradle: com.timqi.collapsibletextview:library:1.1.2@aar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.retrofit2:converter-gson:2.5.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.umeng.umsdk:common:2.0.2@jar" level="project" />
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:logging-interceptor:3.14.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support.constraint:constraint-layout:1.1.3@aar" level="project" />