热门标签 | 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" />

程序运行结果如下:

这里写图片描述

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


推荐阅读
  • 常用工具(一)
    1.时间戳在线转换工具(1)链接https:tool.lutimestamp(2)说明可以通过此工具:将时间戳转为具体时间点,也可以将具体时间点转为时间戳(3)效果2.JSON在线 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 本文提供了关于数据库设计的建议和注意事项,包括字段类型选择、命名规则、日期的加入、索引的使用、主键的选择、NULL处理、网络带宽消耗的减少、事务粒度的控制等方面的建议。同时还介绍了使用Window Functions进行数据处理的方法。通过遵循这些建议,可以提高数据库的性能和可维护性。 ... [详细]
  • 获取时间的函数js代码,js获取时区代码
    本文目录一览:1、js获取服务器时间(动态)2 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
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社区 版权所有