第一个Android程序
因为公司项目的原因,不得不开始学习Java和Android开发,好在使用Java就能开发Android。
大致的需求是通过Web网页的方式来控制大疆无人机。由于大疆无人机的SDK只有Android和iOS版本,所以就必须使用以下的架构:
Web ----> Android ----> 遥控器 ----> 无人机这就要求在Android上实现一个Web Server来接收我的Post请求了。通过搜索找到了NanoHttpd这个库,一个实现一个简单的Web Server
用iDEA新建一个Android项目,选择Empty Activity,语言选择Java。
修改app目录下的build.gradle,添加nanohttpd依赖:
dependencies {
...
implementation 'org.nanohttpd:nanohttpd:2.3.1'
...
}在activity_main.xml中添加按钮:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/take_off"
android:text="Take off" />
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/landing"
android:text="Landing" />
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/start_httpd"
android:text="Start HTTPD" />
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/stop_httpd"
android:text="Stop HTTDP" />
</LinearLayout>每一个layout目录下的xxx.xml可以理解为Android App里面的布局,类似HTML文件,用来显示组件。而MainActivity.java是活动,可以把它当作MVC模型中的控制器,里面包含的是逻辑活动。MainActivity
package com.example.myapplication;
// NanoHTTPD require library
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.regex.*;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import fi.iki.elonen.NanoHTTPD;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private App myApp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startButton = (Button) findViewById(R.id.start_httpd);
Button stopButton = (Button) findViewById(R.id.stop_httpd);
Button take_off = (Button) findViewById(R.id.take_off);
Button landing = (Button) findViewById(R.id.landing);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try{
myApp = new App(MainActivity.this);
Log.d("onClick", "WebServer started");
}catch (IOException e){
e.printStackTrace();
Log.d("onClick", "WebServer start failed" + e.getMessage());
}
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(myApp != null)
{
myApp.closeAllConnections();
myApp = null;
Log.d("onClick", "Web server close");
}
}
});
}
protected void test()
{
Log.d("OOP","Take off sucessed!");
}
}
class App extends NanoHTTPD{
private MainActivity obj;
public App(MainActivity obj) throws IOException {
super(8080);
this.obj = obj;
start(NanoHTTPD.SOCKET_READ_TIMEOUT,false);
}
private void requestBodyProcess(Map<String, String> map,String requestBody)
{
String requestBodyRegex = "\\w+=\\w+&\\w+=\\w+";
boolean isRequestBodyMatch = Pattern.matches(requestBodyRegex, requestBody);
if(isRequestBodyMatch)
{
Pattern command = Pattern.compile("(?<=\\bcommandName=)\\w+");
Matcher command_matcher = command.matcher(requestBody);
if(command_matcher.find())
{
map.put("commandName", command_matcher.group(0));
}
command = Pattern.compile("(?<=\\boperator=)\\w+");
command_matcher = command.matcher(requestBody);
if(command_matcher.find())
{
map.put("operator", command_matcher.group(0));
}
}
else
{
map = null;
}
}
@Override
public Response serve(IHTTPSession session) {
Map<String, String> files = new HashMap<String, String>();
Map<String, String> map = new HashMap<String, String>();
// HTTP GET
if (session.getMethod() == Method.GET) {
String itemIdRequestParameter = session.getParameters().get("itemId").get(0);
return newFixedLengthResponse("Requested itemId = " + itemIdRequestParameter);
}
// HTTP POST
if (session.getMethod() == Method.POST) {
try {
session.parseBody(files);
String requestBody = session.getQueryParameterString();
requestBodyProcess(map,requestBody);
obj.test();
return newFixedLengthResponse("Command Name = " + map.get("commandName") + "\n" + "Operator = "
+ map.get("operator") );
} catch (IOException | ResponseException e) {
// handle
}
}
return newFixedLengthResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT,
"The requested resource does not exist");
}
}由于刚开始对Java不是很熟悉,这个页面我写了很久,还在V2EX上提问过https://www.v2ex.com/t/834355,后来我把App类当作MainActivity的内部类来实现调用MainActivity类中的方法。
今天回过头来思考了以下,如果App类是一个复杂的类,那么当作内部类来实现,那么MainActivity就非常的大了。所以,还是想改成独立的类,然后通过传参的方式,来建立彼此之间的联系。
通过myApp = new App(MainActivity.this);在实例化App的时候将MainActivity传入其中,再根据不同的Post请求来调用MainActivity中实现的方法。
最后在AndroidManifest.xml中注册应用程序所需要的权限
...
</application>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>然后调试应用程序,向手机所在的IP地址:8080发送Get/Post请求即可。
评论已关闭