Połączenie Androida z zewnetrznym serwerem (Java Servlet + XML)

Połączenie aplikacji mobilnej z zewnętrznym serwerem jest często czynnością niezbędną dla wielu usług, dlatego w niniejszym instruktażu zostanie przedstawione jak takie połączenie uzyskać przy wykorzystaniu podstawowych funkcji androida, servletów Javy oraz XML.

 

Poniżej został stworzony program który umożliwia wysłanie obiektu 'książki’ przez internet i otrzymaniu z powrotem jej zmodyfikowanej wersji. Zacznijmy więc od części serwerowej. Tworzymy prostą klasę odwzorowującą książkę:
 

public class Book {

	private String title;
	private String author;
	private int pages;
	private String ISBN;
	private int rating;
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public int getPages() {
		return pages;
	}
	public void setPages(int pages) {
		this.pages = pages;
	}
	public String getISBN() {
		return ISBN;
	}
	public void setISBN(String ISBN) {
		this.ISBN = ISBN;
	}
	public int getRating() {
		return rating;
	}
	public void setRating(int rating) {
		this.rating = rating;
	}
}

Oraz servlet który będzie obsługiwał zapytania przychodzące z androida:
 


@WebServlet(name = "androidServlet", urlPatterns = { "/index", "", "/androidServlet" })
public class androidServlet extends HttpServlet{
	
	public androidServlet() {
		super();
	}
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
	}
	
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		getDataFromAndroid(request,response);

	}
	
	
	public synchronized void getDataFromAndroid(HttpServletRequest request, HttpServletResponse response) {
		try {
	
			byte[] input = getInputData(request);
			String recievedString = new String(input);

			Book book = deserializeData(recievedString, Book.class);
			
			Random rand = new Random();
			book.setRating(rand.nextInt(10));
			StringWriter bookWithRating = serializeData(book);
			
			response.setStatus(HttpServletResponse.SC_OK);
			OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream());
			writer.write(bookWithRating.toString());
			writer.flush();
			writer.close();

		} catch (IOException e) {
			try {
				response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
				response.getWriter().print(e.getMessage());
				response.getWriter().close();
			} catch (IOException ioe) {
			}
		}

	}
	
	public synchronized byte[] getInputData(HttpServletRequest request) throws IOException {

		int length = request.getContentLength();
		byte[] input = new byte[length];
		ServletInputStream sin = request.getInputStream();
		int c, count = 0;
		while ((c = sin.read(input, count, input.length - count)) != -1) {
			count += c;
		}
		sin.close();

		return input;

	}
	
	public synchronized <T> T deserializeData(String recievedString, Class<T> myclass) {
		Serializer serializer = new Persister();
		T readObjects = null;
		try {
			readObjects = serializer.read(myclass, recievedString);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return readObjects;
	}
	
	public synchronized <T> StringWriter serializeData(T writeObjects){
		Serializer serializer = new Persister();
		StringWriter send = new StringWriter();
		try {
			serializer.write(writeObjects, send);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return send;
	}
}

Na samym początku metoda getInputData(request) pobiera wszystkie dane wejściowe wysłane przez androida w postaci bajowej. Następnie z tablicy bajtów tworzymy Stringa. Program w androidzie jest tak stworzony iż przesyłamy jedynie interesujący nasz xml dlatego możemy od razu otrzymane dane deserializować na obiekt książka. Metody serializacji i deserializacji zostały tak stworzone by w razie rozbudowy projektu możliwe było łatwe i szybkie serializowanie i deserializownie innych projektów. Następnie losujemy liczbę w zakresie od 0-10 i przypisujemy to jako ocene dopiero co otrzymanej książce. Na koniec ponownie serializujemy obiekt i przesyłamy go do androida.
 
Do serializacji i deserializacji obiektów na XML wykorzystuje bibliotekę simple dlatego jeśli chcemy uzyskać ten sam efekt nie zapomnijmy jej dodać w Mavenie
 

<dependency>
	<groupId>org.simpleframework</groupId>
	<artifactId>simple-xml</artifactId>
	<version>2.7.1</version>
</dependency>

oraz gradle

compile 'org.simpleframework:2.7.1'

Niemniej nic nie stoi nam na przeszkodzie by korzystać np z JSONa.
 
Przejdźmy do części związanej z androidem. Tutaj również tworzymy identyczną klasę Book:
 

public class Book {

	private String title;
	private String author;
	private int pages;
	private String ISBN;
	private int rating;
	
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	public int getPages() {
		return pages;
	}
	public void setPages(int pages) {
		this.pages = pages;
	}
	public String getISBN() {
		return ISBN;
	}
	public void setISBN(String ISBN) {
		this.ISBN = ISBN;
	}
	public int getRating() {
		return rating;
	}
	public void setRating(int rating) {
		this.rating = rating;
	}
	
}

Główną aktywność w której podajemy informacje o książce i w której otrzymamy informacje zwrotne:
 


public class MainActivity extends Activity {

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

		final EditText title = (EditText) findViewById(R.id.Title);
		final EditText author = (EditText) findViewById(R.id.Author);
		final EditText pages = (EditText) findViewById(R.id.Pages);
		final EditText ISBN = (EditText) findViewById(R.id.ISBN);
		final TextView rating = (TextView) findViewById(R.id.Rating);

		Button send = (Button) findViewById(R.id.Send);
		send.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {

				Book someBook = new Book();
				someBook.setAuthor(author.getText().toString());
				someBook.setTitle(title.getText().toString());
				someBook.setPages(Integer.valueOf(pages.getText().toString()));
				someBook.setAuthor(ISBN.getText().toString());

				new sendUrlToServlet(MainActivity.this, someBook, rating).execute();
			}
		});
	}
}

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.android_connector.MainActivity" >

    <EditText
        android:id="@+id/Title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Title" />

    <EditText
        android:id="@+id/Author"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Author" />

    <EditText
        android:id="@+id/Pages"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Pages" />

    <EditText
        android:id="@+id/ISBN"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ISBN" />

    <Button
        android:id="@+id/Send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send" />

    <TextView
        android:id="@+id/Rating"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp" />

</LinearLayout>

Oraz AsyncTask który wykonuję większość pracy:
 

class sendUrlToServlet extends AsyncTask<Integer, Void, Integer> {

	private Context con;
	private Book book;
	private Book newBook;
	private TextView resultTextView;


	sendUrlToServlet(Context con,Book book, TextView resultTextView) {
		this.con = con;
		this.book = book;
		this.resultTextView = resultTextView;
	}

	protected void onPreExecute() {

        super.onPreExecute();

	}

	protected void onPostExecute(Integer result) {
		resultTextView.setText("Book " + newBook.getTitle() + " acquired Rating of " + newBook.getRating());
	}

	@Override
	protected Integer doInBackground(Integer... params) {
		HttpURLConnection connection = null;
		try {
				URL url = new URL("https://android-baseconnection.rhcloud.com");
				connection = (HttpURLConnection) url.openConnection();

				connection.setRequestMethod("POST");
				connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
				
				sendData(connection);
				reciveData(connection);
			
				} catch (Exception e) {

				} finally {
					try {
						System.out.println(connection.getResponseCode());
					} catch (IOException e) {
						e.printStackTrace();
					}
					connection.disconnect();
				}
		return null;
			}

	void sendData(HttpURLConnection connection) throws Exception{
		
		Serializer serializer = new Persister();
		StringWriter send = new StringWriter();
		serializer.write(book, send);
		
		BufferedOutputStream out = new BufferedOutputStream(connection.getOutputStream());
		out.write(send.toString().getBytes());
		out.flush();
		out.close();
	}
	
	void reciveData(HttpURLConnection connection) throws Exception {
		BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

		String returnString = "";
		StringBuilder allData = new StringBuilder("");

		while ((returnString = in.readLine()) != null) {
			allData.append(returnString);
		}
		in.close();

		System.out.println(allData.toString());
		
		Serializer serializer = new Persister();
		newBook = serializer.read(Book.class,allData.toString());
	}
			

}

 
W głównej klasie nie ma wielu niezwykłych funkcji pobieramy tam podstawowe informacje o książce przy kliknięciu zaś buttona uruchamiamy zadanie asynchroniczne odpowiedzialne za komunikacje z servletem. Tworzymy obiekt url który określa adres z jakim chcemy się połączyć oraz parametry połączenia. W przypadku wysyłania informacji serializujemy obiekt książka i przesyłamy go w postaci bajtowej przez strumień wyjściowy. Analogicznie postępujemy w przypadku otrzymywania danych z serwera.
 
Przykładowy wynik programu możemy obejrzeć poniżej dane o książce został wysłane na serwer a tam korzystając z losowej liczby książka ta została oceniona i z powrotem przesłana do naszej aplikacji:
 
android communication

Dodaj komentarz

WordPress Video Lightbox Plugin