オープンソース ソフトウェア Motion に接続する Android アプリケーションを実装しようとしています。目標は、アプリケーションのステータスを確認し、最後にキャプチャされた画像を取得できるようにすることです。
私は Java でプログラミングすることはあまりありません。私のバックグラウンドは主に C と Python です。Android の UI 部分を理解する上で実際に問題が発生したことはありませんが、あらゆる種類のバイト バッファを操作するのは非常に苦痛であることがわかりました。Motion ソフトウェアには、非常に単純な HTTP API があります。Java では、URL 接続を開くのは簡単です。デフォルト ページからの応答は次のようになります。
Motion 3.2.12 Running [4] Threads
0
1
2
3
私の目的のために、アプリケーションが最初に実行する必要があるのは、スレッドの数を解析することです。ある時点で、最初の行からバージョン番号を取得することもできますが、現時点ではそれほど重要ではありません。
これが私のコードです
package com.hydrogen18.motionsurveillanceviewer;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
public class MotionHttpApi {
String host;
int port = 80;
boolean secure = false;
int numberOfThreads = -1;
String getBaseUrl()
{
StringBuilder sb = new StringBuilder();
sb.append(secure ? "https://" : "http://");
sb.append(host);
sb.append(':');
sb.append(port);
return sb.toString();
}
public int getNumberOfCameras() throws IOException
{
if(numberOfThreads == -1)
{
retrieveSplash();
}
if(numberOfThreads == 1)
{
return 1;
}
return numberOfThreads - 1;
}
void retrieveSplash () throws IOException
{
URL url = new URL(getBaseUrl());
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
if(conn.getResponseCode()!=HttpURLConnection.HTTP_OK)
{
throw new IOException("Got response code" + conn.getResponseCode());
}
try{
Byte[] buffer = new Byte[512];
byte[] sbuf = new byte[128];
int offset = 0;
InputStream in = new BufferedInputStream(conn.getInputStream());
boolean foundInfoString= false;
while( ! foundInfoString)
{
//Check to make sure we have not run out of space
if(offset == buffer.length)
{
throw new IOException("Response too large");
}
//Read into the smaller buffer since InputStream
//can't write to a Byte[]
final int result = in.read(sbuf,0,sbuf.length);
//Copy the data into the larger buffer
for(int i = 0; i < result;++i)
{
buffer[offset+i] = sbuf[i];
}
//Add to the offset
offset+=result;
//Wrap the array as a list
List<Byte> list = java.util.Arrays.asList(buffer);
//Find newline character
final int index = list.indexOf((byte) '\n');
//If the newline is present, extract the number of threads
if (index != -1)
{
//Find the number of threads
//Thread number is in the first lin like "[X]"
final int start = list.indexOf((byte)'[');
final int end = list.indexOf((byte)']');
//Sanity check the bounds
if(! (end > start))
{
throw new IOException("Couldn't locate number of threads");
}
//Create a string from the Byte[] array subset
StringBuilder sb = new StringBuilder();
for(int i = start+1; i != end; ++i)
{
final char c = (char) buffer[i].byteValue();
sb.append(c);
}
String numThreadsStr = sb.toString();
//Try and parse the string into a number
try
{
this.numberOfThreads = Integer.valueOf(numThreadsStr);
}catch(NumberFormatException e)
{
throw new IOException("Number of threads is NaN",e);
}
//No more values to extract
foundInfoString = true;
}
//If the InputStream got EOF and the into string has not been found
//Then an error has occurred.
if(result == -1 && ! foundInfoString )
{
throw new IOException("Never got info string");
}
}
}finally
{
//Close the connection
conn.disconnect();
}
}
public MotionHttpApi(String host,int port)
{
this.host = host;
this.port = port;
}
}
を呼び出すと、コードは正常に機能しますgetNumberOfCameras()
。しかし、RetrieveSplash メソッドが複雑すぎるため、Java に関して何かを本当に理解している必要はないと思います。C なら 10 行ほど、Python なら 1 行で同じことができます。確かにJavaでバイトを操作するより健全な方法があるに違いありませんか?
整数の解析に失敗するたびに IOException をスローするべきではないなど、いくつかのスタイルの問題があると思います。しかし、それは別の問題です。