热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android新闻App的本地服务器搭建教程

本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。

如今的APP许多都是要联网获取数据的,比如新闻客户端,如果想要尝试下这个流程的话,那么就需要有服务器和数据库了。在服务器上搭建各种环境是十分繁琐的,所以我们可以选择搭建一个本地服务器,然后在手机端获取其数据库内的数据。

这里选用XAMPP
XAMPP 是一个整合型的Apache套件,包含Apache、MySQL、PHP、PERL,可以一键式搭建起开发环境,推荐初学者使用。官方网址——https://www.apachefriends.org/zh_cn/index.html

软件开启后的界面是:

这里写图片描述

这里点击start开启Apache和MySQL就好,点击admin可以进入控制界面。

首先进入phpmyadmin界面,新建一个数据库 news,再建立一张表 new,为其建立六个属性,分别是:

id 主键
title 文章标题
description 摘要
date 文章发表时间
newUrl 文章链接
imageUrl 图片链接

创建new表的SQL语句如下

CREATE TABLE `new` (
`id` int(11) NOT NULL,
`title` text NOT NULL,
`description` text NOT NULL,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`newUrl` text NOT NULL,
`imageUrl` text NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

new表插入数据

这里写图片描述

手机端的工作就是来读取数据并显示出来,不过手机端也无法直接访问数据库内容。所以在数据库端需要利用PHP将数据库内容返回为JSON格式的数据,然后手机端再去解析JSON数组

首先是进行数据库连接
mysql_connect.php


//数据库的用户名为root,密码为空
$con = mysql_connect("localhost", "root", "");
//设置字符集为utf8
mysql_query("SET NAMES 'utf8'");
mysql_query("SET CHARACTER SET utf8");
mysql_query("SET CHARACTER_SET_RESULT=utf8");

if (!$con){
die(mysql_error());
}
//访问数据库news
mysql_select_db("news", $con);
?>

接下来是将读取到的数据库内容返回为JSON数组
getNewsJSON.php


/*
* 获得JSON数据
*/

require 'mysql_connect.php';
$n = 0;
$result = mysql_query("select * from new");
while ($row = mysql_fetch_array($result)){
$arr[$n++] = array("title" => $row['title'],
"description" => $row['description'],
"date" => $row['date'],
"newUrl" => $row['newUrl'],
"imageUrl" => $row['imageUrl']
);
}
//数组转换为JSON字符串
echo json_encode($arr);
?>

将两个php文件放到XAMPP安装目录的htdocs文件夹下,直接存放或者再新建个文件夹存放也可以,例如我的存放路径就是:C:\xampp\htdocs\news

然后打开浏览器,输入http://localhost/news/getNewsJSON.php
如果是呈现如下格式的数据,那就说明数据库数据读取成功了。没有直接呈现中文字符是因为编码问题,无需理会。

这里写图片描述

服务器端开发完毕了,接下来就要进行移动端的设计了。

新建个工程。要做的是一个新闻客户端,新闻列表就采用RecyclerView来呈现,将默认布局改为:


<RelativeLayout 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"
tools:context="com.zy.news.MainActivity">


<android.support.v7.widget.RecyclerView
android:id="@+id/recycleView"
android:layout_width="match_parent"
android:layout_height="match_parent">
android.support.v7.widget.RecyclerView>

RelativeLayout>

列表的子项布局:
new_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fresco="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="#f7f9fa"
android:orientation="horizontal"
android:padding="6dp">


<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/new_image"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_gravity="center" />


<LinearLayout
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="6dp">


<TextView
android:id="@+id/new_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@android:color/black"
android:textSize="20sp"
android:textStyle="bold" />


<TextView
android:id="@+id/new_introduction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="4"
android:textColor="@android:color/black"
android:textSize="16sp" />


<TextView
android:id="@+id/new_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginRight="6dp"
android:textColor="@android:color/black"
android:textSize="13sp" />

LinearLayout>
LinearLayout>

SimpleDraweeView是Fresco推出的一款图片加载控件,导入SimpleDraweeView的方法是在build.gradle文件下加入语句compile 'com.facebook.fresco:fresco:0.10.0',然后点击同步即可

这里写图片描述

前边在建表时时设立了六个属性,除去主键id外,一篇新闻还有五个属性。为新闻建立一个实体NewIntroduction.java,省略相应的get和set属性。

public class NewIntroduction {
//文章标题
private String title;
//文章摘要
private String description;
//文章发表时间
private String date;
//文章链接
private String newUrl;
//图片链接
private String imageUrl;
}

新建一个NewsItemListAdapter.java文件,继承自RecyclerView.Adapter,作为RecyclerView的适配器

/**
* Created by ZY on 2016/6/10.
*/

public class NewsItemListAdapter extends RecyclerView.Adapter {

private List introductionList;

private LayoutInflater inflater;

public NewsItemListAdapter(Context context, List introductionList) {
this.introductiOnList= introductionList;
this.inflater = LayoutInflater.from(context);
}

@Override
public NewsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.new_item, parent, false);
return new NewsHolder(view);
}

@Override
public void onBindViewHolder(NewsHolder holder, int position) {
holder.new_image.setImageURI(Uri.parse(introductionList.get(position).getImageUrl()));
holder.new_title.setText(introductionList.get(position).getTitle());
holder.new_introduction.setText(introductionList.get(position).getDescription());
holder.new_date.setText(introductionList.get(position).getDate());
}

@Override
public int getItemCount() {
if (introductiOnList== null || introductionList.size() == 0) {
return 0;
}
return introductionList.size();
}
}

NewsHolder也是一个自定义类,继承自RecyclerView.ViewHolder

/**
* Created by ZY on 2016/6/10.
*/

public class NewsHolder extends RecyclerView.ViewHolder {

public SimpleDraweeView new_image;

public TextView new_title;

public TextView new_introduction;

public TextView new_date;

public NewsHolder(View itemView) {
super(itemView);
new_image = (SimpleDraweeView) itemView.findViewById(R.id.new_image);
new_title = (TextView) itemView.findViewById(R.id.new_title);
new_introduction = (TextView) itemView.findViewById(R.id.new_introduction);
new_date = (TextView) itemView.findViewById(R.id.new_date);
}

}

修改MainActivity

public class MainActivity extends AppCompatActivity {

private List newIntroductionList;

private NewsItemListAdapter adapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fresco.initialize(this);
setContentView(R.layout.activity_main);

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycleView);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this, LinearLayoutManager.VERTICAL, false));

newIntroductiOnList= new ArrayList<>();
adapter = new NewsItemListAdapter(MainActivity.this, newIntroductionList);
recyclerView.setAdapter(adapter);
}
}

此时newIntroductionList 内还没有填充数据,程序打开后还是一片空白,所以接下来就要来获取本地服务器内的数据

新建一个Util类
getNewsJSon(String strUrl)方法用来访问getNewsJSON.php页面,获取页面数据

public static String getNewsJSon(String strUrl) throws IOException {
URL url;
URLConnection urlConnection;
HttpURLConnection httpURLConnection;
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader reader = null;
StringBuffer resultBuffer = null;
try {
url = new URL(strUrl);
urlCOnnection= url.openConnection();
httpURLCOnnection= (HttpURLConnection) urlConnection;
httpURLConnection.setRequestProperty("Accept-Charset", "utf-8");
inputStream = httpURLConnection.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
reader = new BufferedReader(inputStreamReader);
resultBuffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
resultBuffer.append(line);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
}
if (resultBuffer == null) {
return null;
}
return resultBuffer.toString();
}

getNewIntroductionList(String strUrl)方法用来解析JSON数组

public static List<NewIntroduction> getNewIntroductionList(String strUrl) throws IOException {
String html = getNewsJSon(strUrl);
if (html == null) {
return null;
}
List<NewIntroduction> newIntroductionList = new ArrayList<>();
try {
JSONArray jsonArray = new JSONArray(html);

for (int i = 0; i < jsonArray.length(); i++) {
NewIntroduction newIntroduction = new NewIntroduction();
JSONObject jsonObject = jsonArray.optJSONObject(i);
String title = jsonObject.getString("title");
String description = jsonObject.getString("description");
String date = jsonObject.getString("date");
String newUrl = jsonObject.getString("newUrl");
String imageUrl = jsonObject.getString("imageUrl");

newIntroduction.setTitle(title);
newIntroduction.setDescription(description);
newIntroduction.setDate(date);
newIntroduction.setNewUrl(newUrl);
newIntroduction.setImageUrl(imageUrl);

newIntroductionList.add(newIntroduction);
}

} catch (JSONException e) {
e.printStackTrace();
}

return newIntroductionList;
}

然后在MainActivity文件中建立一个内部类MyAsyncTask继承自

AsyncTask<String, Void, List<NewIntroduction>>

用来进行联网操作。将读取到的JSON数组解析为NewIntroduction对象,传入适配器中

 class MyAsyncTask extends AsyncTask<String, Void, List<NewIntroduction>> {

@Override
protected List doInBackground(String... params) {
List newIntroductiOnList= null;
try {
newIntroductiOnList= Util.getNewIntroductionList(params[0]);
} catch (IOException e) {
e.printStackTrace();
}
return newIntroductionList;
}

@Override
protected void onPostExecute(List introductionList) {
if (introductiOnList== null || introductionList.size() == 0) {
return;
}
MainActivity.this.newIntroductionList.addAll(introductionList);
MainActivity.this.adapter.notifyDataSetChanged();
}
}

然后在onCreate(Bundle savedInstanceState)方法的最后一行new一个MyAsyncTask对象即可。模拟器访问本地服务器的IP地址为10.0.2.2,所以完整的访问地址应为http://10.0.2.2/news/getNewsJSON.php

new MyAsyncTask().execute("http://10.0.2.2/news/getNewsJSON.php");

最后还要加上联网访问权限

<uses-permission android:name="android.permission.INTERNET" />

程序运行结果如下:

这里写图片描述

代码下载地址:一个简单的联网新闻客户端的开发思路


推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
author-avatar
华福-日语人才_601
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有