基于Android的在线电子书阅读器报告基于Android的在线电子书阅读器报告
期末作品报告
课程名称: Android应用程序开发
学 号:
姓 名:
班 别:
1
引言
在这个快节奏的时代,人们的空余时间越来越零碎,而且人们对智能手机的依赖越来越重,所以,一个拥有丰富功能且能随时进行电子书阅读的在线小说阅读器的出现,则是我们刻不容缓的事情。
此软件是在Android平台上进行设计开发,此软件的开发是通过了客户需求分析阶段以及技术可行性分析阶段,然后进行总体设计阶段和详细设计编码等阶段。此软件不仅具有基本的电子书阅读功能,而且还拥有丰富的实用功...
基于Android的在线电子书阅读器
期末作品报告
课程名称: Android应用程序开发
学 号:
姓 名:
班 别:
1
引言
在这个快节奏的时代,人们的空余时间越来越零碎,而且人们对智能手机的依赖越来越重,所以,一个拥有丰富功能且能随时进行电子书阅读的在线小说阅读器的出现,则是我们刻不容缓的事情。
此软件是在Android平台上进行
开发,此软件的开发是通过了客户需求分析阶段以及技术可行性分析阶段,然后进行总体设计阶段和详细设计编码等阶段。此软件不仅具有基本的电子书阅读功能,而且还拥有丰富的实用功能设计。经过不断的测试与完善,电子书阅读器功能稳定,并且在真机上对其进行了测试与验证,基本上达到了用户的需求
。
1、功能分析
1.1项目来源
此次开发的项目是在线小说阅读器,属于自选项目。随着社会的发展,人们的生活节奏也越来越快空闲时间也越来越零碎,人们没有了大段的时间来进行书籍的阅读,所以一款能利用零碎时间进行随时阅读的软件成为了我们的需求。而一款能在人们随身携带的手机上运行的阅读软件成为了大家的选择。以前我们看看杂志,小说都要去图书馆借阅,而且时间有限,很不方便;而在电脑上看杂志,看小说,文档也是很不方便的。以此看来,一个好的手机阅读器软件的开发是相当有必要的。
1.2开发目标
在线小说阅读器的开发目标就是让用户可以把零碎的空余时间有效的利用到书籍的阅读上,而且用户在没有网路的情况下也可以正常的进行书籍的阅读,让用户摆脱书籍的笨重携带不方便等确定,给予阅读者更大的便利性更好的舒适性。此软件是在Android平台上进行设计开发,它的界面丰富简洁但是却不简单,它包含了书架界面、2
文件查看界面、软件设置界面、书籍阅读界面等界面,它的功能全面。其优越性表现在:自动扫描手机里的所有书籍、手动从文件夹中选择添加书籍、自动为书籍生成章节目录、添加查看书签、全文关键词搜索、阅读主题选择、阅读字体大小设置等功能。此外,给用户更清晰方便的界面,也是本软件的出发点之一。
2、功能设计
2.1系统功能设计
根据需要,在线图书阅读器主要实现即时的在线阅读,主要包含以下功能:
(1)在线即时搜索图书:可以按照书名、作者进行搜索所要阅读的书籍。
(2)在线即时阅读图书:在线进行电子图书的全屏阅读。
(3)书签功能:可以定制书签,以方便下次阅读。
(4)预读功能:可以预读下一页的内容,减少用户等待的时间。
(5)选章阅读功能:可以根据用户需要,有选择的进行阅读。
2(2软件的总体架构
在线小说阅读器采用PHP+Android+Sphinx的架构模式(如图1所示)。用PHP做
服务端,提供与阅读相关的一系列接口。Android做客户端,与服务器端通信,
完成用户的相关操作。客户端与服务器端以 SOAP作为基础通讯协议。Sphinx作
为搜索图书的引擎,提供强大的分词、查询等服务。
在线图书阅读器的系统架构:
3
在线小说阅读器软件主要分为8个功能大模块如图3所示,分别是欢迎模块、软件主界面、书籍管理、阅读管理、文件浏览、系统管理、使用帮助、关于。其中书籍模块中还要文件扫描模块,阅读管理中有章节管理、书签管理、搜索管理。系统设置中有密码设置。其各个模块的详细设计如下:
1.软件欢迎模块。该模块主要实现的功能是,通过Handler来实现一个2秒的缓冲界面,然后通过SharedPreferences读取配置文件,判断是否有密码。如果有密码则跳转至密码验证界面;如果没有密码则判断是否为第一次使用此软件,如果是第一次使用则跳转至引导页面。
2.软件主界面模块。该模块是一个通过TabHost标签组件来实现的一个分类管理功能。本界面的标签在屏幕的最下方,分别是:文件管理、我的书架、我的设置。点击不同的标签则显示不同的界面,默认显示标签为“我的书架”,打开选项中会出现对应的视图。实现了将本程序关联成手机默认打开程序中,即从外部打开文本文件时选择查看方式中会出现本软件图标供用户选择以本软件打开。
3.书籍管理。该模块是以书架的模式来展现书籍,并可以对书籍进行一些操作,本模块共有3个书架分别为:“最近阅读”、“历史阅读”、“收藏阅读”,默认显示是“最近阅读”书架。本模块有导航按钮和书籍选择按钮。当弹出导航栏时,则把书籍从每行显示三本书籍调整到每行显示两本书籍。导航栏中与三大项:分类排序、添加书籍、清空书籍。每项里面又有子菜单。当点击导航里的按钮时会显示子功能导航,当再点击其它按钮时,会收起前面的子功能导航,展开当前的子功能。当单击书籍选择按钮时会弹出书籍选择窗口,选择里面的书架则进入相应的书架界面,同时还可以通过左右滑动来切换书架界面。当单击书籍时会打开相应的书籍阅读界面,长按某书籍时会弹出书籍操作窗口。
4.文件浏览。该模块使用ListView组件显示文件目录,不同的文件类型显示不同的图标。最上面标题栏有导航按钮,当点击导航按钮时会从左侧弹出导航栏,导航栏中有标记文件按钮、分类排序按钮和添加到书架按钮,点击标记文件按钮或长按某文件或目录时则切换到多选模式,其中有多选按钮、反选按钮和取
4
消按钮;点击分类排序则弹出子菜单,其中有按名称排序、按大小排序、按时间排序和按类型排序;点击添加到书架时如果为选择文件则自动进入多选模式让用户进行文件选择,如果用户未选择则提示“请选择书籍”,进行选择是用户可选择文件或目录,系统会自动进行扫描,把符合要求的文件添加到“最近书架”中,并弹出提示信息,其中有失败个数、已存在个数和成功个数。在多选模式下点击返回按钮或点击标记文件会取消多选模式。非多选模式下,用户点击文件时本软件会根据文件扩展名来判断打开文件方式,如果是文本文件则直接用本软件打开,并把其添加到“最近书架”中,其它格式则调用对应的软件打开,如果是未识别的类型则提示“没有打开此文件的应用”。
5.阅读管理。该模块通过自定义一个View视图来显示书页,通过自定义类来读取文本内容并通过onDraw()
把文件名、文本内容、电量信息、时间信息和已读百分比进行绘制成图片,并通过View来把绘制的图片显示出来。第一次进入阅读页面是会有显示引导页面来指导用户如何读本页面进行操作。本页面操作包括点击事件和滑动事件,点击左侧屏幕进行向上翻页,点击右侧屏幕进行向下翻页,点击屏幕中间画出菜单选项。此菜单是使用PopupWindow组件实现,菜单分上下两部分,上面的菜单有返回按钮、屏幕亮度调节按钮和添加书签按钮;下面的菜单有主题选择按钮、搜索按钮、书签按钮、目录按钮、字体大小调节按钮、翻页方式按钮、夜间模式切换按钮和退出软件按钮。
6.系统设置。系统设置模块包括阅读设置和系统设置。阅读设置中有连续阅读模式、阅读完成时自动归类、阅读休息提醒和阅读空闲退出。连续阅读模式:下次启动直接进入上次阅读的界面进行继续阅读;阅读完成时自动归类:当书籍阅读到最后一页后对此书籍自动移至“历史阅读”书架中;阅读休息提醒:设置一个时间,当用户在阅读页面停留至这个时间时会弹出个提示框来提醒用户进行休息;阅读空闲退出:设置一个时间,当用户停留在阅读界面并且为对其未进行任何操作至这个时间时,系统会自动关闭本软件。系统设置中有显示隐藏文件、使用软件密码、退出确认、使用帮助和关于。显示隐藏文件:当用户选择此设置后会在下次启动本软件时在文件浏览中显示隐藏文件;使用软件密码:用户可以对此软件进行密码设置;退出时确认:当选择此设置后,退出软件时会显示一个确认框进行退出确认,未选择此设置时则会直接退出本软件;使用帮助:显示本软件的帮助信息;关于:显示关于本软件的信息。本软件的设置信息全部使用SharedPreferences存储。
7.使用帮助。该模块通过读取帮助文件在TextView中显示,并且为TextView添加滚动条。文件中含有本软件的特点、功能介绍、操作说明等。
5
3、功能实现
一、客户端
1、 HomeActivity.java代码:
package activity;
import interfaces.IPushData;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import network.ClientSocket; import adapter.ListAdapter; import android.app.Activity; import android.content.Intent; import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import com.example.wysocket.R;
public class HomeActivity extends Activity implements IPushData{
List
directorys =new ArrayList();
ListView mListView;
ListAdapter adapter;
private Handler mhandler = new Handler()
6
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
adapter.notifyDataSetChanged();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.home_activity);
initView();
requestServer();
}
private void initView()
{
mListView=(ListView) findViewById(R.id.list_home);
adapter =new ListAdapter(directorys, this);
mListView.setAdapter(adapter);
mListView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
String bookName=directorys.get(position);
7
Intent intent =new
Intent(HomeActivity.this,ReaderActivity.class);
intent.putExtra("bookName", bookName);
startActivity(intent);
}
});
}
/**
* 请求服务器获取目录
*/
private void requestServer()
{
ClientSocket client =new ClientSocket("getDiretory",this);
client.start();
}
@Override
public void onError(Object object) {
// TODO Auto-generated method stub
Log.d("HomeActivity", "链接服务器失败");
}
@Override
public void onSuccess(Object object) {
// TODO Auto-generated method stub
String data=(String) object;
List temp =splitString(data);
if(temp!=null)
{
directorys.clear();
for(int i=0;i splitString(String data)
{
return Arrays.asList(data.split(";"));
}
}
2、 ReaderActivity.java代码:
package activity;
import com.example.wysocket.R;
import interfaces.IPushData;
import network.ClientSocket;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
public class ReaderActivity extends Activity implements IPushData{
String bookName;
String custormString ="_wy";//用于服务器对请求参数的判断
String bufString ;//缓存的字符串
private Handler mhandler = new Handler()
{
@Override
public void handleMessage(Message msg) {
9
super.handleMessage(msg);
switch (msg.what) {
case 1:
tvContent.setText(bufString);
break;
default:
break;
}
}
};
private TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.reader_activity);
bookName=getIntent().getStringExtra("bookName");
bookName=bookName+custormString;
initView();
reqeustServer();
}
private void initView() {
// TODO Auto-generated method stub
tvContent=(TextView) findViewById(R.id.tv_content);
}
private void reqeustServer()
{
ClientSocket socket =new ClientSocket(bookName, this);
socket.start();
}
/**
* 这里获取得到bufString为8k,在服务端自定义返回字节的大小,
* 根据自己的分页思路来做吧。
*/
@Override
10
public void onSuccess(Object object) {
// TODO Auto-generated method stub
bufString=(String) object;
mhandler.sendEmptyMessage(1);
}
/**
*
*/
@Override
public void onError(Object object) {
// TODO Auto-generated method stub
}
}
3、IPushData.java代码:
package interfaces;
/**
* 回调接口。
* @author Wy。
*
*/
public interface IPushData {
void onSuccess(Object object);
void onError(Object object);
}
4、 ClientSocket.java代码:
package network;
import interfaces.IPushData;
import java.io.IOException;
import java.net.Socket;
11
import java.net.UnknownHostException;
import android.R.integer;
import util.FileUtils;
/**
* 连接服务器的Socket,只是简单的根据不同的请求参数,获取不同的String。
* @author Wy。
*
*/
public class ClientSocket extends Thread {
Socket socket;
final static String IP="192.168.31.29"; //本机IP地址,使用模拟器就用10.0.2.2。
final static int port =56565; //服务器的端口。
FileUtils fileUtils; //操作Socket流。
String requestParam; //请求参数。
IPushData iPushData; //回调接口。
public ClientSocket(String requestParams,IPushData i) {
this.requestParam=requestParams;
iPushData=i;
fileUtils=new FileUtils();
}
@Override
public void run() {
try {
Socket socket =new Socket(IP,port);
//先添加请求参数。
12
fileUtils.outPut(socket, requestParam);
//获取服务器返回的字符串。
String dataString=fileUtils.Input(socket);
//关闭Socket的流。
fileUtils.closeSocket();
//回调。
iPushData.onSuccess(dataString);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
5、FileUtils.java代码:
package util;
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 封装操纵Socket的输入输出流。
* @author Wy。
*
*/
public class FileUtils {
OutputStream outputStream=null;
13
BufferedOutputStream bufferedOutputStream=null;
InputStream InputStream=null;
BufferedInputStream bufferedInputStream=null;
/**
* 链接的Socket,要发送的内容。
* @param socket
* @param content
*/
public void outPut(Socket socket,String content)
{
try {
outputStream = socket.getOutputStream();
bufferedOutputStream=new
BufferedOutputStream(outputStream);
byte[] temp =content.getBytes("GB2312");
System.out.println(content);
bufferedOutputStream.write(temp);
bufferedOutputStream.flush();//记得刷新,不然写不了内容的。
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
/**
* 当客户端读写完毕的时候,调用关闭流。
*/
public void closeSocket()
{
try {
if(InputStream!=null)
{
InputStream.close();
}
if(bufferedInputStream!=null)
{
14
bufferedInputStream.close();
}
if(outputStream!=null)
{
outputStream.close();
}
if(bufferedOutputStream!=null)
{
bufferedOutputStream.close();
}
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
/**
* 获取该Socket链接对象,发送过来的内容。
* @param socket
* @return
*/
public String Input(Socket socket)
{
try {
InputStream = socket.getInputStream();
bufferedInputStream=new
BufferedInputStream(InputStream);
//8k的缓存
byte[] data =new byte[1024*8];
int len=bufferedInputStream.read(data);
String temp=new String(data,0,len,"GB2312");
return temp;
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
return "读取错误";
}
15
}
}
二、服务器端
1、CutContentThread.java代码:
package servers;
import java.io.File;
import java.io.IOException; import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.util.ArrayList; import java.util.Arrays; import java.util.List;
import util.BufferedRandomAccessFile;
import util.FileUtils;
/**
* 截取文件内容并发送给客户端
* @author Wy
*
*/
public class CutContentThread extends Thread{
Socket socket=null;
String bookPath;
long pos=0;//文件指针
BufferedRandomAccessFile reader;
FileUtils fileUtils ;
public CutContentThread(Socket socket,String bookPath,long pos) {
this.socket=socket;
this.bookPath=bookPath;
this.pos=pos;
16
fileUtils=new FileUtils();
File file =new File(bookPath);
try {
reader =new BufferedRandomAccessFile(file,"r");
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
@Override
public void run() {
String content=sendChapter();
fileUtils.outPut(socket, content);
}
private String sendChapter()
{
long currentIndex =pos;
//文件指针,操纵文件指针来读取文件
try {
reader.seek(currentIndex);
//一次读8k,根据分页思路自定义大小
byte[] buf = new byte[1024*8];
int len = 0;
len = reader.read(buf,0,buf.length) ;
String contentString=new String(buf, 0, len,"gbk");
System.out.println(contentString);
return contentString;
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
return "";
}
17
}
}
2、DirectoryThread.java代码:
package servers;
import java.io.File;
import java.io.IOException; import java.io.UnsupportedEncodingException;
import java.net.Socket; import java.util.ArrayList; import java.util.Arrays; import java.util.List;
import util.FileUtils;
/**
* 发送目录的线程
*
* @author Wy
*
*/
public class DirectoryThread extends Thread {
FileUtils fileUtils = null;
Socket socket = null;
String directory; // 文件目录
public DirectoryThread(Socket socket, String directoryPath) {
this.socket = socket;
fileUtils = new FileUtils();
directory = directoryPath;
}
/**
* 获取文件名
*/
@Override
18
public void run() {
String data=getFileName(".txt");
fileUtils.outPut(socket, data);
}
/**
* 获取文件目录下的文件名
*
* @param filePath
* @return
*/
private List getDiretory(String filePath) {
List files = new ArrayList<>();
File file = new File(filePath);
if (file.isDirectory()) {
files = Arrays.asList(file.list());
}
return files;
}
/**
* 获取不带后缀的文件,只匹配相应的后缀名
* @param houzhui 后缀名,如".txt";
* @return 字符串 "西游记;红楼梦;"
*/
private String getFileName(String houzhui) {
List files = new ArrayList<>();
files = getDiretory(directory);
StringBuffer stringBuffer = new StringBuffer();
for (String s : files) {
String temp = s.substring(s.length() - 4, s.length());
if (temp.equals(houzhui)) {
stringBuffer.append((s.substring(0, s.length() - 4)) + ";");
}
19
}
String temp = stringBuffer.toString();
return temp;
}
}
3、ConnectServer.java代码:
package socketserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException; import java.util.ArrayList;
import servers.CutContentThread; import servers.DirectoryThread; import util.FileUtils;
public class ConnectServer extends Thread{
static final String reader="_wy";
static long pos=0;//文件指针
// public FileUtils fileUtils=null; //
// ServerSocket serverSocket=null; //
public ConnectServer() {
}
public static void main(String[] args) throws IOException {
System.out.println(".....服务器已经启动...正在监听客户端信息");
ServerSocket serverSocket =new ServerSocket(56565);
20
//FileUtils fileUtils=new FileUtils();
while(true)
{
try {
//监听,阻塞主线程
Socket socket=serverSocket.accept();
System.out.println("客户端IP
->"+socket.getInetAddress().getHostAddress());
//判断根据上传的内容,知道Sokect需要做什么
chooseThread(socket);
// chooseThread(socket);
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
}
private static void chooseThread(Socket socket)
{
String bookName="";
String updateString="";
FileUtils fileUtils=new FileUtils();
updateString=fileUtils.Input(socket);
System.out.println("updateString ->"+updateString);
if(updateString.substring(updateString.length()-3,updateString.length
()).equals(reader))
{
21
bookName=updateString.substring(0,updateString.length()-3)+".txt";
updateString="getBookContent";
}
switch (updateString) {
case "getDiretory":
DirectoryThread thread= new DirectoryThread(socket, "E://book");
thread.start();
break;
case "getBookContent":
String bookPath="E://book//"+bookName;
CutContentThread cutContentThread =new CutContentThread(socket,
bookPath, 0);
cutContentThread.start();
break;
default:
fileUtils.outPut(socket, "请求参数不对");
break;
}
}
}
4、Client.java代码:
package util;
import java.io.IOException;
import java.net.Socket;
import java.util.Arrays;
import java.util.List;
/**
* 客户端测试类
* @author Administrator
*
*/
public class Client {
private static List splitString(String data)
{
return Arrays.asList(data.split(";")); 22
}
public static void main(String[] args) {
try {
//测试获取文件目录
Socket socket =new Socket("127.0.0.1", 56565);
FileUtils fileUtils=new FileUtils();
fileUtils.outPut(socket, "getDiretory");
List temp =splitString(fileUtils.Input(socket));
System.out.println(temp.toString());
fileUtils.closeSocket();
//测试获取文件目录下的书
Socket socket2 =new Socket("127.0.0.1", 56565);
fileUtils.outPut(socket2,(temp.get(6)+"_wy"));
System.out.println(fileUtils.Input(socket2));
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
}
}
5、FileUtils.java代码:
package util;
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 封装Socket操纵数据的输入输出流
23
* @author Administrator
*
*/
public class FileUtils {
OutputStream outputStream=null;
BufferedOutputStream bufferedOutputStream=null;
InputStream InputStream=null;
BufferedInputStream bufferedInputStream=null;
/**
* 链接的Socket,要发送的内容
* @param socket
* @param content
*/
public void outPut(Socket socket,String content)
{
try {
outputStream = socket.getOutputStream();
bufferedOutputStream=new BufferedOutputStream(outputStream);
byte[] temp =content.getBytes("GB2312");
System.out.println(content);
bufferedOutputStream.write(temp);
bufferedOutputStream.flush();//记得刷新,不然写不了内容
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
finally
{
}
}
public void closeSocket()
{
try {
if(InputStream!=null)
24
{
InputStream.close();
}
if(bufferedInputStream!=null)
{
bufferedInputStream.close();
}
if(outputStream!=null)
{
outputStream.close();
}
if(bufferedOutputStream!=null)
{
bufferedOutputStream.close();
}
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
/**
* 获取该Socket链接对象,发送过来的内容
* @param socket
* @return
*/
public String Input(Socket socket)
{
try {
InputStream = socket.getInputStream();
bufferedInputStream=new BufferedInputStream(InputStream);
byte[] data =new byte[1024*8];
int len=bufferedInputStream.read(data);
String temp=new String(data,0,len,"GB2312");
return temp;
} catch (IOException e) {
// TODO Auto-generated catch block
25
System.out.println(e.getMessage());
return "读取错误";
}
}
}
26
4、效果分析
1.小说目录
27
2小说内容
28
29
5学习心得
经过一个多月的奋斗终于把在线小说阅读器开发完成,在开发的过程中遇到了各种各样的问题,这些各式的问题通过自己和同学的帮助下一个个的被攻克,可以说这次开发就是对自己学过的知识进行的一次梳理与统一,对以前学过的知识有了更加深刻的理解,认识层面由原来的只是拿来用到了解内部的流程和原理,使我对布局的应用更加得心应手,使我懂得,细节决定成败。同时,在项目开发中,使我逐渐成熟起来,由原来的一出问题就问老师找同学,到现在的尽量自己上网搜索解决,在此过程中发现了比较实用的几个网站,例如CSDN 、AndroidDemo、APKBUS等,并且在网上认识了很多喜欢Android开发的朋友,我们共同探讨共同进步。通过自己解决开发过程中遇到的问题会比老师或同学帮忙解决印象更加深刻,内心也会有很大的成就感。
虽然项目开发后仍然有某些方面的不足,但是我会继续努力,在平时学习中多下功夫,以后也会在此基础上不断的完善,不断的学习。
30
本文档为【基于Android的在线电子书阅读器报告】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。