Android实战之小说阅读器,带有水平翻页,记录上次读取页码数_安卓怎么计算小说章节页码-程序员宅基地

技术标签: android应用  阅读器  SQLite  小说  Android  

实现的效果图:


实现的步骤:

一,建立布局文件:3个布局xml

1,activity_main.xml:显示sdcard卡中所有的文件夹及文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/title_text"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:text="当前位置: /mnt/sdcard"
        android:textSize="14sp" />
    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
        android:cacheColorHint="#00000000" >
    </ListView>
</LinearLayout>

2.file_line.xml主要填充list中的文本数据

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
    <TextView
        android:id="@+id/file_img"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1" />
    <TextView
        android:id="@+id/file_name"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="4"
        android:textSize="14sp" />
</LinearLayout>

3.activity_detail.xml:这是小说显示的显示界面

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical" >
    <TextView
        android:id="@+id/txt_title"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" /> 

//这里自定义一个MyView用以显示小说的文本内容
    <com.example.ebook.view.MyView
        android:id="@+id/txt_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="8"
       />
<TextView
        android:id="@+id/txt_page"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:textColor="#000000"
        android:textSize="14sp" />
</LinearLayout>

二、java代码部分:现在com.example.ebook.dbc包中创建DataBaseConnection类中建两个数据库:txt.db  和  page.db

package com.example.ebook.dbc;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBaseConnection extends SQLiteOpenHelper {
public DataBaseConnection(Context ctx){
super(ctx,"txt.db",null,1);
}
public DataBaseConnection(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
//初始化文本表
String sql = "CREATE TABLE txt (" +
"id integerprimarykey," +
"full_path text ," +
"now_page integer ," +
"over_flag integer " +
")";
db.execSQL(sql);
//初始化页码表
sql ="CREATE TABLE page(" +
"id integerprimary key," +
"txt_id integer ," +
"page_num integer ," +
"content text " +
")";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

}
}

2.在util包中建类Globals:

package com.example.ebook.util;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import com.example.ebook.R;
import com.example.ebook.dbc.DataBaseConnection;
public class Globals {
public static int SCREEN_WIDTH;
public static int SCREEN_HEIGHT;

//建立一个map集合,里面封装了所有的扩展名对应的图片,以便进行文件图片的显示
public static Map<String,Integer> allIconImgs = new HashMap<String,Integer>();
public static DataBaseConnection dbc;
//每行显示的字数
public static int LINE_CHAR_COUNT = 20;
//字符间隔
public static int CHAR_SEP = 2;
//页边距
public static int PAGE_SEP = 20;
//每个字的大小
public static int CHAR_SIZE;
//行间隔
public static int LINE_SEP;
//计算行数
public static int LINE_COUNT;
//每一行文本之间的间隔文字
public static String TXT_SEP_FLAG = "LINE_SEP_FLAG_BU_NENG_CHONG_FU";

public static void init(Activity a){
SCREEN_WIDTH = a.getWindowManager().getDefaultDisplay().getWidth();
SCREEN_HEIGHT = a.getWindowManager().getDefaultDisplay().getHeight();

//初始化数据库
dbc = new DataBaseConnection(a);
dbc.getWritableDatabase();

//初始化所有扩展名和图片的对应的关系
allIconImgs.put("txt", R.drawable.txt_file);
allIconImgs.put("mp3", R.drawable.mp3_file);
allIconImgs.put("mp4", R.drawable.mp4_file);
allIconImgs.put("bmp", R.drawable.image_file);
allIconImgs.put("gif", R.drawable.image_file);
allIconImgs.put("png", R.drawable.image_file);
allIconImgs.put("jpg", R.drawable.image_file);
allIconImgs.put("dir_open", R.drawable.open_dir);
allIconImgs.put("dir_close", R.drawable.close_dir);

//计算数字= 屏幕宽度“字”总宽度/行字数 
//屏幕宽度“字”总宽度 = 屏幕宽度 - 页边距 * 2 - 字符间隔宽度
//字符间隔宽度 = (字符数-1)* 字符间距
CHAR_SIZE =(SCREEN_WIDTH - (PAGE_SEP * 2) - (LINE_CHAR_COUNT - 1)
* CHAR_SEP)/LINE_CHAR_COUNT;
//只使用屏幕高度的4/5来显示文字内容,计算所显示出的行数
//行数 = (屏幕*4/5)/(字的高度+行间距)
LINE_COUNT = SCREEN_HEIGHT * 4 / 5 / (CHAR_SIZE + LINE_SEP);
}

}

3.在com.example.ebook.util中添加TxtDAOUtil类

package com.example.ebook.util;
import java.util.HashMap;
import java.util.Map;
import android.database.Cursor;
public class TxtDAOUtil {
public static void insertData(String fullPath){
//先判断之前是否添加过
String sql = "SELECT id FROM txt WHERE full_path =?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[]{fullPath});

if(!c.moveToFirst()){
//数据库中没有这条数据,就需要添加,默认设置用户打开的页面是第一页, 同时还没有完成分页的操作
sql = "INSERT INTO txt (full_path,now_page,over_flag) VALUES (?,1,0)";

Globals.dbc.getWritableDatabase().execSQL(sql,new Object[]{fullPath});
}
c.close();
}

public static void updateOverFlag(int id){
String sql = "UPDATE txt SET over_flag =1 WHERE id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[]{id});
}

public static void updateNowPage(int id,int nowPage){
String sql = "UPDATE txt SET now_page =? WHERE id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[]{nowPage,id});
}

public static Map<String,Object> getTxtDataByFullPath(String fullPath){
Map<String,Object> map = new HashMap<String,Object>();
String sql = "SELECT id,now_page,over_flag FROM txt WHERE full_path = ?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[]{fullPath});
c.moveToFirst();
map.put("id", c.getInt(0));
map.put("nowPage", c.getInt(1));
map.put("overFlag", c.getInt(2));

return map;
}
}

4在com.example.ebook.util中建立PageDAOUtil

package com.example.ebook.util;
import java.util.Map;
import android.database.Cursor;
public class PageDAOUtils {
public static void insertData(Map<String, Object> map) {
String sql = "INSERT INTO page (txt_id,page_num,content) VALUES (?,?,?)";
Globals.dbc.getWritableDatabase().execSQL(
sql,
new Object[] { map.get("txtId"), map.get("pageNum"),
map.get("content") });
}
public static int getAllCount(int txtId) {
String sql = "SELECT COUNT(*) FROM page WHERE txt_id = ?";
Cursor c = Globals.dbc.getReadableDatabase().rawQuery(sql,
new String[] { String.valueOf(txtId) });
c.moveToFirst();
int count = c.getInt(0);
c.close();
return count;
}

public static void deletePageData(int txtId) {
String sql = "DELETE FROM page WHERE txt_id =?";
Globals.dbc.getWritableDatabase().execSQL(sql, new Object[] { txtId });
}

public static String getPageContent(int txtId, int pageNum) {
String sql = "SELECT content FROM page WHERE txt_id = ? AND page_num = ?";
Cursor c = Globals.dbc.getReadableDatabase()
.rawQuery(
sql,
new String[] { String.valueOf(txtId),
String.valueOf(pageNum) });

c.moveToFirst();
String content = c.getString(0);

c.close();
return content;
}
}

5. com.example.ebook.adapter中建立FileAdapter,这是解决sdcard卡显示布局的

package com.example.ebook.adapter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.example.ebook.R;
import com.example.ebook.util.Globals;
import android.content.ContentValues;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class FileAdapter extends BaseAdapter {
private Context ctx;
private List<Map<String,Object>> allValues = new ArrayList<Map<String,Object>>();
public FileAdapter(Context ctx, List<Map<String, Object>> allValues) {
this.ctx = ctx;
this.allValues = allValues;
}

@Override
public int getCount() {
return allValues.size();
}

@Override
public Object getItem(int position) {
return allValues.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(ctx).inflate(R.layout.file_line, 
null);

//设置高度
convertView.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT, Globals.SCREEN_HEIGHT /9));
}

//取得图片组件
TextView fileImg = (TextView) convertView.findViewById(R.id.file_img);
fileImg.getLayoutParams().height = Globals.SCREEN_HEIGHT/9;
TextView fileName = (TextView) convertView.findViewById(R.id.file_name);
//取得数据,设置到组件里
Map<String,Object> map = allValues.get(position);
//设置内容,文字
fileName.setText(map.get("fileName").toString());
//图片要根据扩展名取得
String extName = map.get("extName").toString();
//取得图片的id
int imgId = Globals.allIconImgs.get(extName);
//设置图片
fileImg.setBackgroundResource(imgId);
return convertView;
}
}

6.在package com.example.ebook中建立一个MainActivity类

package com.example.ebook;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.app.AlertDialog.Builder;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import android.widget.TextView;
import com.example.ebook.adapter.FileAdapter;
import com.example.ebook.util.Globals;
import com.example.ebook.util.TxtDAOUtil;

public class MainActivity extends Activity {
private TextView titleText;
private ListView list;
private FileAdapter adapter;
private List<Map<String,Object>> allValues = new ArrayList<Map<String,Object>>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

Globals.init(this);
setContentView(R.layout.activity_main);
//取得组件
titleText = (TextView) findViewById(R.id.title_text);
list = (ListView) findViewById(R.id.list);

//准备数据
//取得SD卡根目录
File root = Environment.getExternalStorageDirectory();
loadFileData(root);

//建立Adapter
adapter = new FileAdapter(this, allValues);
list.setAdapter(adapter);
//加入监听事件
list.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
//取得当前操作的数据
Map<String,Object> map = allValues.get(arg2);
//判断所有点的是文件还是文件夹
boolean dirFlag = (Boolean) map.get("dirFlag");
if(dirFlag){
//文件夹
//建立该文件的File对象
//取得绝对路劲
String fullPath = (String) map.get("fullPath");
//建立File
File dir = new File(fullPath);

//先清空原有的数据
allValues.clear();

if(!Environment.getExternalStorageDirectory()
.getAbsolutePath().equals(fullPath)){

//加入返回上一级的操作数
Map<String,Object> parent = new HashMap<String,Object>();
parent.put("fileName", "返回上一级");
parent.put("extName", "dir_open");
parent.put("dirFlag", true);
parent.put("fullPath", dir.getParent());

//保存一个标志
parent.put("flag", "TRUE");
//将这一行加入到数据集合中
allValues.add(parent);
}

//加入新数据
loadFileData(dir);
//使用Adapter通知界面ListView,数据已经被修改了,你也要一起改
adapter.notifyDataSetChanged();
}else{
//将该文件保存到文本表中
TxtDAOUtil.insertData(map.get("fullPath").toString());

//切换界面
Intent in = new Intent(MainActivity.this,DetailActivity.class);
in.putExtra("fullPath", map.get("fullPath").toString());
startActivity(in);
}
}
});
list.setOnItemLongClickListener(new OnItemLongClickListener() {

@Override
public boolean onItemLongClick(AdapterView<?> arg0, View arg1,
final int arg2, long arg3) {
//取得数据
Map<String,Object> map = allValues.get(arg2);
final File f = new File(map.get("fullPath").toString());

if(f.isFile()){
//弹出确认框
Builder builder = new Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("确认要删除该文件(" + f.getName() + ")吗?");
builder.setPositiveButton("确定",new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
//将SD卡中的文件删除
if(f.exists()){
f.delete();
}

//将列表中的数据删除
allValues.remove(arg2);
//通知
adapter.notifyDataSetChanged();
}
});
builder.setNegativeButton("取消", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

}
});
builder.create().show();
}
return false;
}
});
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//根据keyCode判断用户按下了那个键
if(keyCode == KeyEvent.KEYCODE_BACK){
//判断当前是否在SD卡根目录下。
//取得第一行数据
Map<String,Object> map = allValues.get(0);
if("TRUE".equals(map.get("flag"))){
//里面,需要返回上一级
list.performItemClick(list.getChildAt(0),
0, list.getChildAt(0).getId());
}else{
//弹出提示框
Builder builder = new Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("亲,真的要离开我吗?");
builder.setPositiveButton("真的", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.setNegativeButton("取消", new OnClickListener() {

@Override
public void onClick(DialogInterface dialog, int which) {

}
});
builder.create().show();
}
return false;
}

return super.onKeyDown(keyCode, event);
}

private void loadFileData(File dir) {
//列出该目录下的所有文件
File[] allFiles = dir.listFiles();
//设置当前位置的提示信息
titleText.setText("当前位置:"+ dir.getAbsolutePath());

//判断
if(allFiles != null){
//循环
for(int i=0;i<allFiles.length;i++){
File f = allFiles[i];
Map<String,Object> map = new HashMap<String,Object>();
map.put("fileName", f.getName());
//多保存一个文件的绝对路径,方便在进行点击时使用
map.put("fullPath", f.getAbsolutePath());
//判断是文件夹还是文件
if(f.isDirectory()){
//是文件夹
map.put("extName", "dir_close");
map.put("dirFlag", true);
}else{
//是文件,截取出扩展名
String extName = f.getName()
.substring(f.getName().lastIndexOf(".")+1)
.toLowerCase();
map.put("extName", extName);
map.put("dirFlag", false);
}
//只有文件夹或是文本文件才要显示
if(f.isDirectory() || "txt".equals(map.get("extName"))){
allValues.add(map);
}
}
}
}
}


7.在 com.example.ebook.view中建立MyView类

package com.example.ebook.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import com.example.ebook.DetailActivity;
import com.example.ebook.R;
import com.example.ebook.util.Globals;
import com.example.ebook.util.PageDAOUtils;
public class MyView extends View {
private int pageNum;
private int txtId;

// 多查询上一页和下一页的文本,作为缓存保存下来,一边翻页时显示使用
private String preContent;
private String content;
private String nextContent;

// 加入监听,可以让当前的内容,跟着手指一起移动
// 开始时按下的位置
private float startX = 0;
// 移动后的位置
private float nowX = 0;
// 准备好TxtPage
private TextView txtPage;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// 为自己加入监听,这里的点击事件不需要实现,但是要写
this.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
}
});
this.setOnTouchListener(new OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// 判断当前操作的状态
if (event.getAction() == MotionEvent.ACTION_DOWN) {
// 按下是,记录横坐标的位置
startX = event.getX();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
nowX = event.getX();
// 平移界面中绘制的内容。
postInvalidate();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
// 翻页操作
// 判断手指的位置
nowX = event.getX();
if (Math.abs(nowX - startX) < 50) {
// 不变
} else if (nowX > startX) {
// 翻上一页
if (pageNum > 1) {
pageNum--;
// 重新查询当前页的数据
changePage();
}
} else {
// 翻下一页
if (pageNum < PageDAOUtils.getAllCount(txtId)) {
pageNum++;
changePage();
}
}
nowX = 0;
startX = 0;
}
return false;
}

});
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}

public void initPage(int txtId, int pageNum) {
this.txtId = txtId;
this.pageNum = pageNum;
changePage();
}
private void changePage() {
// 查询当前页的文本内容,并刷新显示到界面上
content = PageDAOUtils.getPageContent(txtId, pageNum);
// 同时查询出上一页和下一页的数据
if (pageNum > 1) {
// 有上一页
preContent = PageDAOUtils.getPageContent(txtId, pageNum - 1);
} else {
preContent = null;
}
if (pageNum < PageDAOUtils.getAllCount(txtId)) {
// 有下一页
nextContent = PageDAOUtils.getPageContent(txtId, pageNum + 1);
} else {
nextContent = null;
}

DetailActivity a = (DetailActivity) getContext();

if (txtPage == null) {
txtPage = (TextView) a.findViewById(R.id.txt_page);
}
// 改变底部的显示文字
txtPage.setText("分页完成,当前:" + pageNum + "/"
+ PageDAOUtils.getAllCount(txtId));

// 修改Activity中的nowPage
a.setNowPage(pageNum);
// 刷新显示内容
super.postInvalidate();
}
// 绘制组件中的具体内容
@Override
protected void onDraw(Canvas canvas) {
// 先清空之前绘制的所有内容
super.onDraw(canvas);
if (content != null) {
// 拆分每页的文本,变成每行的文本形式
String[] allStr = content.split(Globals.TXT_SEP_FLAG);

// 建立绘制参数对象
Paint paint = new Paint();
// 通过该对象设置绘制的颜色,文字大小,填充状态等信息
paint.setTextSize(Globals.CHAR_SIZE);
paint.setColor(Color.BLACK);
// 循环绘制 当前页的文字
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP + j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX), (i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}

// 绘制上一页或下一页的文字
if (nowX < startX && nextContent != null) {
allStr = nextContent.split(Globals.TXT_SEP_FLAG);

// 正在翻向下一页,需要将下一页的内容显示出来
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(
String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP
+ j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX)
+ Globals.SCREEN_WIDTH,
(i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}
}
if (nowX > startX && preContent != null) {
allStr = preContent.split(Globals.TXT_SEP_FLAG);
// 正在翻向上一頁,需要將上一頁的內容显示出来
for (int i = 0; i < allStr.length; i++) {
for (int j = 0; j < allStr[i].length(); j++) {
// 文字需要根据手指的移动位置有一个偏移
canvas.drawText(
String.valueOf(allStr[i].charAt(j)),
Globals.PAGE_SEP
+ j
* (Globals.CHAR_SIZE + Globals.CHAR_SEP)
+ (nowX - startX)
- Globals.SCREEN_WIDTH,
(i + 1)
* (Globals.CHAR_SIZE + Globals.LINE_SEP),
paint);
}
}
}
}
}
}

8。最后建立DetailActivity

package com.example.ebook;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import android.R.integer;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
import com.example.ebook.util.Globals;
import com.example.ebook.util.PageDAOUtils;
import com.example.ebook.util.TxtDAOUtil;
import com.example.ebook.view.MyView;
public class DetailActivity extends Activity {

//声明这个handler类
private Handler handler;
//文本信息
private Map<String,Object> txtMap;
private Map<String,Object> pageMap = new HashMap<String,Object>();

private int lineCount;
private int pageNum;
private StringBuilder builder;
private String fullPath;
//取得底部显示分页的信息
private TextView txtPage;
//显示文本内容的标志
private boolean showedFlag = false;
//当前的页数
private int nowPage = 1;
public int getNowPage() {
return nowPage;
}

public void setNowPage(int nowPage) {
this.nowPage = nowPage;
}
private MyView txtContent;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
txtPage = (TextView) findViewById(R.id.txt_page);
txtContent = (MyView) findViewById(R.id.txt_content);

//接受传入的文本,查询数据库中该文件是否完成了分页
fullPath = getIntent().getStringExtra("fullPath");
txtMap  = TxtDAOUtil.getTxtDataByFullPath(fullPath);
//建立Handler
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if(msg.what == 0){
//显示已经处理好的页面
txtPage.setText("已经处理好了:"+(pageNum - 1)+"页的数据");
}else{
txtPage.setText("分页完成,当前:1/"+(pageNum-1));
}
}
};

//判断当前的文本是否被分页完成,如果没有被分页过,就需要自己进行分页处理
if((Integer)(txtMap.get("overFlag"))==0){
//首先这里必须子进程对内容进行读取,防止主线程读取卡屏
Thread t = new Thread(){
@Override
public void run() {
//进行分页的处理,就是要读取文本
try{
//将之前分页处理的结果删除,防止之前分页到一半,用户退出造成问题
PageDAOUtils.deletePageData((Integer) txtMap.get("id"));

//windows上的文本必须转码 
BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(
new File(fullPath)),"GBK"));
String line = null;
builder = new StringBuilder();

//计算已经读取的内容,在手机上显示的行数,当满足一页时,将其保存到数据库里,再重新计算行数,以便保存下一页
lineCount = 0;
//当前加入了的页数
pageNum = 1;

while((line = reader.readLine()) != null){
//对line进行拆分
//通过一个循环来截取内容
while(line.length() > 20){
//截取出一行
String tempStr = line.substring(0, 20);
addPageLineData(tempStr);

//截取后半部分,继续循环
line = line.substring(20);
}
//这里应该剩下一行,对该行也进行相同的处理
addPageLineData(line);
}
//剩下不到一页的内容,也要保存到数据库里
pageMap.put("txtId", txtMap.get("id"));
pageMap.put("pageNum", pageNum++);
pageMap.put("content", builder.toString());

PageDAOUtils.insertData(pageMap);
//如果整个文件都读取完成了,但还没有显示数据,就需要自己进行显示处理
if(!showedFlag){
showedFlag = true;
txtContent.initPage((Integer) txtMap.get("id"), 1);
}
//修改状态
TxtDAOUtil.updateOverFlag((Integer) txtMap.get("id"));
handler.sendEmptyMessage(1);
reader.close();
}catch(Exception e){
e.printStackTrace();
}
}
};
t.start();
}else{
//如果已经初始化好了分页
//需要显示出上次看到的位置
showedFlag = true;
txtContent.initPage((Integer)txtMap.get("id"), (Integer)txtMap.get("nowPage"));
}
}
@Override
protected void onDestroy() {
//退出时,需要记录下当前看到的页数
TxtDAOUtil.updateNowPage((Integer) txtMap.get("id"), nowPage);
super.onDestroy();
}
private void addPageLineData(String lineData) throws InterruptedException {
lineCount++;
builder.append(lineData);
builder.append(Globals.TXT_SEP_FLAG);

if(lineCount == Globals.LINE_COUNT){
//满一页,就需要保存
pageMap.put("txtId", txtMap.get("id"));
pageMap.put("pageNum", pageNum++);
pageMap.put("content", builder.toString());

PageDAOUtils.insertData(pageMap);

handler.sendEmptyMessage(0);
//如果已经够了10页,就可以显示了
if(!showedFlag){
showedFlag =  true;
txtContent.initPage((Integer) txtMap.get("id"), 1);
}

Thread.sleep(5);
//添加后,都需要将一些数据清空
builder = new StringBuilder();
lineCount = 0;
}
}
}

全部代码上传完毕,在翻页效果时,有那种说面的效果必须是需要算法的。这里后期的文章里将尝试解决。需要素材或是源码,评价中说明下



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014078192/article/details/23605819

智能推荐

JavaDemo——读取硬盘物理序列号_java 硬盘物理序列号-程序员宅基地

文章浏览阅读1.2k次。通过调用wmic命令获取硬盘序列号,wmic命令很强大。Demo:/** * 2019年3月13日下午3:48:22 */package testReadDiskInfo;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;..._java 硬盘物理序列号

CentOS 编译Hadoop 2.6 32位_32位linux系统 编译hadoop-程序员宅基地

文章浏览阅读2.2k次。本文采用CenOS 6 32位,JDK1.7进行编译 (1)安装编译库yum install cmake lzo-devel zlib-devel gcc gcc-c++ autoconf automake libtool ncurses-devel openssl-devel libXtst(2)安装mavenwget http://repos.fedorapeople.org/repos/dc_32位linux系统 编译hadoop

bind mysql web_基于的django的bind dns管理平台-程序员宅基地

文章浏览阅读422次。BIND(Berkeley internet Name Daemon)也叫做NAMED,是现今互联网上使用最为广泛的DNS 服务器程序,本项目旨在更简单的维护我们内部的dns系统。环境:数据库: mysql5.6应用: bind-9.11.2环境: python3.8 , django30x01 安装数据库bash sql 建库语句use mysqlcreate database bind9; -..._使用web管理bind

Jvm基础篇-02-自动内存管理-程序员宅基地

文章浏览阅读282次。对于Java程序员来说,在虚拟机自动内存管理机制的帮助下,不再需要为每一个new操作去写配对的delete/free代码,不容易出现内存泄漏和内存溢出问题。不过,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那排查错误、修正问题将会成为一项异常艰难的工作。====从新生代出发-XX:+UseSerialGC 可互相激活新生代 :Serial + 老年代: Serial Old 都是串行-XX:+UseParNewGC 可互相激活。_自动内存管理

自己写的轮播图,原生JavaScript,支持移动端触摸滑动。分页器圆点可以支持mouseover鼠标移入和click点击,面向对象思路_轮播图无缝链接带有小圆点且支持移动端触频滑动-程序员宅基地

文章浏览阅读529次。自己用原生javascript写的轮播图,分页器按钮Click点击与mouseover鼠标悬浮导航都支持。同时支持移动端触摸操作,自己写得感觉不足之处是图片滚动动画还不够平滑,再改改间隔与偏移量应该可以。函数接受参数应该改成对象更好,还没有改。感觉这次写的轮播图功能比较全面了哈。高手们请别笑话,不足请指正.上源码:先HTML:&lt;!DOCTYPE html&gt;&lt;html&gt;&..._轮播图无缝链接带有小圆点且支持移动端触频滑动

LAMP服务架构之传统缓存机制(Ngins+PHP+Memcache)-程序员宅基地

文章浏览阅读339次。nginx - fastcgi - php - memcache 协同下的 请求的完整访问过程用户发送http请求报文给nginx服务器nginx会根据文件url和后缀来判断请求如果请求的是静态内容,nginx会将结果直接返回给用户; 如果请求的是动态内容,nginx会将请求交给 fastcgi客户端 ,通过 fastcgi_pass 将这个请求发送给 php-fpmphp-fpm 会将请求交给 wrapperwrapper 收到请求会生成新的线程调用 php动态程序解析服务器如果用

随便推点

Android音乐播放器_登录即可查找最新的android应用、游戏、电影、音乐等精彩内容-程序员宅基地

文章浏览阅读939次。该音乐播放器是我研究生开学前做出来的,花了我将近一个月的闲余时间,算是有模有样的了。现在算起来,应该有一年多没搞Android,所以现在看回以前的程序已经比较模糊了,整个工程的代码量还是比较庞大的,就不把代码贴出来了,感兴趣的可以自行下载代码。欢迎先体验我的App,来一场听觉与视觉的享受吧!视觉????嗯,你没看错,安装后有惊喜,让你欲罢不能!(貌似有点夸张了)Apk下载地址:ht_登录即可查找最新的android应用、游戏、电影、音乐等精彩内容

无法注册 URL http://+:8735/Service/。另一应用程序已使用 HTTP.SYS 注册了该 URL。的解决办法。_无法注册应用去处理url地址-程序员宅基地

文章浏览阅读1.1w次。 弄了一上午,终于把使用NetTcpBinding的双工通讯给弄清楚了,也算是对wcf有所掌握了,为了解决穿透防火墙的问题,所以决定尝试一下WsDualHttpBinding的双工通信,结果问题来了。。。 “无法注册 URL http://+:8735/Service/。另一应用程序已使用 HTTP.SYS 注册了该 URL。” 晕了一种个下午,百_无法注册应用去处理url地址

Python学习资料全面总结,真的对零基础很有用-程序员宅基地

文章浏览阅读4.5k次,点赞5次,收藏52次。把手里积累了这么久的Python入门资料整理了一下,发现其实,有了这些,python入门真的不难,每天花点时间学,真的不会影响工作。下面一起来看看这些资料吧!可以学习python的地方 Python学习资料全部整理 Python可以做的事情 关于python的一些文章一、可以学习Python的地方1、实验楼:【Python基础+项目实战课程】https://www.lanqiao.cn/courses/13302、《笨办法学 Python》:这本书绝对是最简单的学习 Pyth.._python学习资料

Linux Centos yum/rpm 设置代理_linux 代理 rpm-程序员宅基地

文章浏览阅读1.2k次。yum 设置代理:vim /etc/yum.conf添加形如:proxy = http://user:pass@ip:portrpm 设置代理sudo rpm -Uvh https://xxxxx.rpm --httpproxy ip --httpport portreference: https://www.lightnetics.com/topic/3698/how-do-i-install-an-rpm-package-using-a-http-proxy..._linux 代理 rpm

Android中的图片处理(包括缓存、大小、优化等)_android 每秒收到30张图片怎么处理-程序员宅基地

文章浏览阅读3.1k次。加载一副位图到你的用户界面是很简单的,然而如果你需要马上加载一组更大的图片的话就会复杂的多.在许多情况下(例如有些组件像ListView,GridView以及ViewPager等),出现在屏幕上的图片总量,其中包括可能马上要滚动显示在屏幕上的那些图片,实际上是无限的. 那些通过回收即将移除屏幕的子视图的组件,内存使用得以保留.如果你不长期保持你对象的引用的话,垃圾收集器也会释放你所加载的位图内_android 每秒收到30张图片怎么处理

摄像头的RTSP视频如何用H5 来播放_h5直接播放rtsp视频-程序员宅基地

文章浏览阅读205次。我们公司开发的liveweb播放器是可支持H.264/H.265视频播放的流媒体播放器,性能稳定、播放流畅,可支持的视频流格式有RTSP、RTMP、HLS、FLV、WebRTC等,具备较高的可用性。支持h264、h265、AAC、G711等常见音视频格式。支持协议:RTSP、RTMP、HLS、HTTP-FLV、WebSocket-FLV、GB28181、HTTP-TS、WebSocket-TS、HTTP-fMP4、WebSocket-fMP4、MP4、WebRTC。对外提供HTTP API二次开发接口;_h5直接播放rtsp视频

推荐文章

热门文章

相关标签