[android开发]小说下载软件
前言
今天闲来无事就将上个月写的一款小的app介绍一下吧,这款app是用来下载小说,小说来源是无限小说网,原理自然是直接扒掉了人家 的html页面,然后从html源码里面寻找出来小说的下载地址,里面用到了三个开源库,一个是设置状态栏变色的(有bug,不太通用),另一个是下拉刷新的开源库,第三个解析xml的库jsoup(源代码在文末)
app效果图
源码介绍
下面简单介绍一下源码:
- 自定义进度条:
自定义进度条可以参考我前面的代码
http://blog.csdn.net/supervictim/article/details/53907393
我在这个基础上增加了自定义属性,用来设置旋转的进度条图片和文字,使用过程中变成了如下形式:
<cn.karent.downloadtxt.UI.ProgressViewInResultandroid:id="@+id/result_progress"android:layout_centerInParent="true"android:layout_width="70dp"android:layout_height="70dp"wan:bitmap="@drawable/pic_dlg_loading"wan:text="载"/>
自定义属性需要在values文件夹中创建一个叫做attrs.xml的文件:
<resources><declare-styleable name="ProgressBitmap"><!--显示的是哪个背景图的id--><attr name="bitmap" format="reference"/><!--要绘制在中心的字符串--><attr name="text" format="string"/></declare-styleable></resources>
这样就可以在上面的使用了,下面搬上最终的进度条代码:
public class ProgressViewInResult extends View {private Bitmap mBitmap;private Matrix mMatrix;private int mCurrent = 0;private Progress mProgress;private boolean mContinue = true;private Paint mTextPaint;private String mText;public ProgressViewInResult(Context context) {super(context);init();}public ProgressViewInResult(Context context, AttributeSet attrs) {super(context, attrs);mTextPaint = new Paint();mTextPaint.setTextSize(ScreenUtil.dp2px(18));mTextPaint.setColor(Color.rgb(0xa6, 0xa6, 0xa6));//获取自定义属性TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressBitmap);if( typedArray != null) {int res = typedArray.getResourceId(R.styleable.ProgressBitmap_bitmap, R.drawable.abs__spinner_48_inner_holo);mBitmap = BitmapFactory.decodeResource(context.getResources(), res);mText = typedArray.getString(R.styleable.ProgressBitmap_text);} else {mBitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.abs__spinner_48_inner_holo);}init();}private void init() {mMatrix = new Matrix();mProgress = new Progress();//执行操作mProgress.execute();}public Bitmap getmBitmap() {return mBitmap;}public void setmBitmap(Bitmap mBitmap) {this.mBitmap = mBitmap;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mMatrix.setRotate( (mCurrent ++) * 6, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);//旋转之后将图片缩小mMatrix.postScale(0.7f, 0.7f);canvas.drawBitmap(mBitmap, mMatrix, null);//绘制文字if( mText == null)return;Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();float strWidth = mTextPaint.measureText(mText);float y = mBitmap.getHeight() * 0.7f / 2;y += (Math.abs(fontMetrics.ascent) - fontMetrics.descent) / 2;float x = ( mBitmap.getWidth() * 0.7f - strWidth ) / 2;canvas.drawText(mText, x, y, mTextPaint);}public void setContinue(boolean c) {mContinue = c;}class Progress extends AsyncTask<Void, Void, Void> {@Overrideprotected void onProgressUpdate(Void... values) {super.onProgressUpdate(values);invalidate();}@Overrideprotected Void doInBackground(Void... params) {while( mContinue ) {try {Thread.sleep(50);} catch (Exception e) {e.printStackTrace();}publishProgress();}return null;}}
}
- 下载功能:创建了一个service(service的执行也是在UI线程里面)在后台下载。
DownloadService.java
public class DownloadService extends Service {private NotificationManager mNotifyManager;private DownloadBinder mBinder = new DownloadBinder();private NotificationCompat.Builder mBuilder;private Integer mLength = 0;private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {if( msg.what == 0x123) {int length = (Integer)msg.obj;mBuilder.setProgress(100, length, false);mBuilder.setContentText(length + "%");if( length != 100) {mBuilder.setContentInfo("正在下载...");} else {mBuilder.setContentInfo("下载完成!");}mNotifyManager.notify(0, mBuilder.build());}}};@Overridepublic void onCreate() {
Log.d("service", "onCreate....");mNotifyManager = (NotificationManager) getSystemService(Activity.NOTIFICATION_SERVICE);mBuilder = new NotificationCompat.Builder(this);mBuilder.setProgress(100,0,false).setSmallIcon(R.drawable.paper_flight).setContentInfo("下载中...").setContentTitle("正在下载");super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {
Log.d("service", "onStartCommand.....");return super.onStartCommand(intent, flags, startId);}@Nullable@Overridepublic IBinder onBind(Intent intent) {return mBinder;}public class DownloadBinder extends Binder {public void startDownload(final String url,final String name) {if( url == null) {Toast.makeText(DownloadService.this, "sorry,下载地址没有找到!", Toast.LENGTH_SHORT).show();return;}new Thread(new Runnable() {@Overridepublic void run() {//开启事件循环,使线程能够显示UI提示Looper.prepare();//下载小说Http.downloadTxt(url, name, new RefreshListenerImpl());Looper.loop();}}).start();}}public class RefreshListenerImpl implements RefreshListener {@Overridepublic void refresh(int length) {Message msg = new Message();msg.what = 0x123;msg.obj = length;mHandler.sendMessage(msg);}@Overridepublic void finish() {}}}
Http.downloadTxt():
public static void downloadTxt(String url, String name, DownloadService.RefreshListenerImpl refresh) {String path = "/mnt/sdcard/小说下载/";String filePath = path + name + ".zip";try {File directory = new File(path);if( !directory.exists() )directory.mkdirs();File file = new File(filePath);if( !file.exists())file.createNewFile();FileOutputStream fos = new FileOutputStream(filePath);URL u = new URL(url);HttpURLConnection conn = (HttpURLConnection) u.openConnection();conn.setRequestMethod("GET");conn.setRequestProperty("Charset", "UTF-8");conn.setDoInput(true);//禁止转发conn.setInstanceFollowRedirects(false);conn.connect();//获取转发后的真正地址String location = conn.getHeaderField("Location");//说明下载地址不存在if( location == null) {Toast.makeText(MyApplication.getContext(), "小说不存在!", Toast.LENGTH_SHORT).show();return;}//小米手机获取的中文地址是以ISO-8859-1为编码的,需要将其转换为utf8,否则找不到真正的下载地址
// location = new String(location.getBytes("ISO-8859-1"), "utf8");
System.out.println("location:" + location);String url1 = StringUtil.encodeUrl(location);url1 += ".zip";
//System.out.println("url1:" + url1);URL u2 = new URL(url1);HttpURLConnection conn1 =(HttpURLConnection) u2.openConnection();InputStream is = conn1.getInputStream();//获取文件长度int fileLength = conn1.getContentLength();byte[] bytes = new byte[1024];int total = 0;int length = -1;int currentProgress = 0;int downloadPrecent = 0;while( (length = is.read(bytes)) != -1) {
//System.out.println("bytes:" + bytes);total += length;//更新进度//卡顿解决方案,当进度积累到一定量才更新,不要频繁调用更新currentProgress = total * 100 / fileLength;if( currentProgress - downloadPrecent >= 2) {refresh.refresh(currentProgress);downloadPrecent = currentProgress;}fos.write(bytes, 0, length);}is.close();fos.close();
System.out.println("下载完成...");} catch (Exception e) {e.printStackTrace();}}
在真正下载小说的时候我获取到了下载地址,点击之后会发现无限小说网的后台重定向了:
如上图,在获取到了访问地址之后返回的状态码是302,而真正的地址就藏在返回头的Location字段里面,所以下载的代码才需要获取Location字段进而进行真正的下载
String location = conn.getHeaderField("Location");//说明下载地址不存在if( location == null) {Toast.makeText(MyApplication.getContext(), "小说不存在!", Toast.LENGTH_SHORT).show();return;}//小米手机获取的中文地址是以ISO-8859-1为编码的,需要将其转换为utf8,否则找不到真正的下载地址
// location = new String(location.getBytes("ISO-8859-1"), "utf8");
System.out.println("location:" + location);String url1 = StringUtil.encodeUrl(location);url1 += ".zip";
//System.out.println("url1:" + url1);URL u2 = new URL(url1);HttpURLConnection conn1 =(HttpURLConnection) u2.openConnection();InputStream is = conn1.getInputStream();
获取Location字段还有一个问题,那就是Location字段里面确实是小说的地址,但是却含有中文,小米、vivo手机必须要将其再用ISO-8859-1才能使用,否则就会找不到地址,其他的华为、模拟器等就直接是utf8就行
最后
上面代码可用,但是不要用于商业用途,出了问题概不负责
源代码:点我下载
[android开发]小说下载软件相关推荐
- 老罗android开发视频教程 下载地址
感觉老罗android开发视频教程讲得挺好挺全面的,适合新手学习.分享 老罗android开发视频教程 下载地址: 电驴:http://www.verycd.com/topics/2929580/ 老 ...
- LPC1768处理器开发板下载软件的使用方法
介绍LPC1768开发板下载软件 文章目录 前言 软件包 二.软件内选择 1.界面 2.读入数据 总结 前言 LPC1768开发板下载过程与单片机下载过程极为相似 软件包 链接:https://pan ...
- 基于Android开发的备忘录软件(创建、通知)
基于Android开发的备忘录软件(创建.通知) 系统概述 系统总体设计 系统设计与实现部分 关键代码及说明 程序运行截图 学习点 系统概述 结合本学期课程所学的关于Android通知的知识以及期中期 ...
- 【Android 应用开发】Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载
. 最新下载 : 2017年 8 月 28 日 : 平台 Android Studio 软件包 大小 SHA-1 校验和 Windows (64 位) android-studio-bundle-16 ...
- 【Android 应用开发】Android 开发环境下载地址
此文章来自于[http://blog.csdn.net/shulianghan/article/details/38023959] 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+ ...
- Android开发之在软件内录屏录画面,直接CV就能用
关于Android开发录屏的资料,真的是很难找到那种拿来就能用的,不是付费专栏就是要积分才能下载源码,起不到任何帮助.我需要的是录制软件画面,找到的几个例子都是录制时返回桌面,然后弹出小窗口开始录制桌 ...
- Android开发工具下载及环境配置
工作一年,家里出了点事,回家发展,找到一份Android开发,大恩大德不嫌弃我菜,而且公司规模在本地来说同行业内是比较大的了,挺好的,今天刚来,发现电脑没安装开发软件,遂着手先把吃饭的工具先下下来,难 ...
- Android 开发环境下载地址
Android 开发环境介绍 : 目前 Android 有两种开发环境, 一种是传统的 Eclipse + ADT, 一种就是目前最新并且得到 Google 推荐的 Android Studio; - ...
- 【转载】 Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载
本文转自http://blog.csdn.net/shulianghan/article/details/38023959 Android Studio 最详细开发环境下载 (特别推荐) : http ...
最新文章
- android View.isShown() 和 getVisibility() 的区别
- MediaWiki 1.19.2 发布 - 开源 Wiki 系统
- [译]Speeding up your PHP scripts
- 新功能:阿里云负载均衡SLB支持HTTP访问强制跳转HTTPS
- python如何生成随机数_python如何生成随机数
- 简单mysql优化_MySQL简单优化
- 手机java版怎么换皮肤_手机QQ皮肤更换方法(安卓版)
- 史上最全的 struts2 面试题
- ILSVRC2016
- pimple idiom
- CentOS 7 安装rar解压rar
- 【Scratch案例实操】Scratch字母排序 scratch编程案例教学 scratch创意编程 少儿编程教案
- 【TypeError: Descriptors cannot not be created directly. 】解决方法
- 位置在此计算机上运行程序灰色,Win10电脑中定位服务按钮灰色无法开启的2种解决方法...
- 51单片机——定时器的原理和使用
- 【179期】这些最常用的Linux命令都不会,你怎么敢去面试?
- 盘点OLED显示技术的几大优势
- php artisan命令表,php artisan 命令列表
- 基金知识汇总和实战经验分享
- Row Migration和row chained
热门文章
- CodeForces 1253C Sweets Eating
- 阿帕奇php,阿帕奇如何摆脱index.php
- html转换成xsl,xml+xsl转换为html
- Dos下怎么返回上一级目录(DOS命令大全)
- 【小强推歌】---邓丽君演绎古词专集《淡淡幽情》
- 眼镜猴--Tarsius syrichta ( Philippine tarsier )
- metro 风格 php源码,Win8 Metro UI风格Web素材样式资源合集
- 圣邦微电子FAE_信号链笔试记录
- 【转】FAE及其发展前景
- 网络攻防实验:aircrack-ng实验