Since I have the extremely good fortune of heading to Stanford in the fall, where app development is a staple of many a hackathon, I decided it would be worthwhile to get started with learning Android App Development.
Since I had never formally learned Java, I've spent the last month and a half reading various java books and, to my chagrin, have found most of them to be quite dry and difficult to absorb...but then, I discovered O'Reilly Media's Head First series of books. As of 7/3/15, I'm proud to say I've actually read 600 informative, strangely entertaining pages from a java textbook (and no, nobody told me to say this). If you're trying to learn java, I'd seriously recommend picking up this book. |
It's a simple Chatbox app, where users can chat with others connected to a server via a local network.
|
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.chris.chatclient" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".Chat" android:label="@string/chatbox" > <intent-filter> <action android:name="com.example.chris.CHAT" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest>
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Chatbox App" android:textSize="40sp" android:textStyle="bold" android:id="@+id/title"/> <ScrollView android:layout_width="match_parent" android:layout_height="200dp" android:background="#99FF99" android:id="@+id/scrl"> <TextView android:id="@+id/incoming" android:layout_width="match_parent" android:layout_height="match_parent" /> </ScrollView> <EditText android:hint="Enter Text" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/outgoing" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Send" android:id="@+id/send_button" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="send_message" /> </LinearLayout>
|
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="20dp" android:paddingTop="20dp" android:orientation="vertical"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Please enter your name" android:id="@+id/nameSetter"/> <EditText android:hint="Enter IPv4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/server_ip" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enter" android:id="@+id/setName_Button"/> </LinearLayout> </RelativeLayout>
|
package com.example.chris.chatclient; import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.View; import android.view.View.*; import android.widget.Button; import android.widget.EditText; public class MainActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.splash_layout); Button name_button = (Button) findViewById(R.id.setName_Button); name_button.setOnClickListener(set_Name); } private OnClickListener set_Name = new OnClickListener() { //when enter button pressed, set name of user @Override public void onClick(View v) { EditText et = (EditText) findViewById(R.id.nameSetter); String myname = et.getText().toString(); EditText et2 = (EditText) findViewById(R.id.server_ip); String myIP = et2.getText().toString(); if (myname != "") { //if text has been entered for both fields if (myIP != "") { Chat.setName(myname); Chat.setIP(myIP); //now that name is set, start the main Chat activity Intent chatIntent = new Intent("com.example.chris.CHAT"); //intent matches intent named in Manifest startActivity(chatIntent); } } } }; }
Basically, threads can be tricky, but they're also very useful (especially when one wants to multitask*).
*There isn't actually real multitasking that goes on between threads, but the Thread Scheduler running on the Java Virtual Machine often executes each thread's stack in such a way that creates the appearance of multitasking from the user's perspective.
|
package com.example.chris.chatclient; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.View.*; import android.widget.Button; import android.widget.EditText; import android.widget.ScrollView; import android.widget.TextView; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.Socket; public class Chat extends Activity { private static final String TAG = "Chat Client"; private static String name = ""; private static String ipAddress; private static boolean entered = false; private EditText out; private TextView incoming; private String inString = ""; private Button send_button; private static PrintWriter writer; private String message = ""; private Socket sock; private BufferedReader reader; private Handler handler; private boolean connected = false; protected static void setName(String n){ name = n; } protected static void setIP(String i) {ipAddress = i;} protected void onCreate(Bundle savedInstanceState) { Log.d(TAG, "onCreate"); super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handler = new Handler(); send_button = (Button) findViewById(R.id.send_button); send_button.setOnClickListener(send_message); out = (EditText) findViewById(R.id.outgoing); Log.d(TAG, "Starting setup thread"); Thread sThread = new Thread(new setupThread()); sThread.start(); } private OnClickListener send_message = new OnClickListener() { @Override public void onClick(View v) { Log.d(TAG, "button clicked"); message = out.getText().toString(); //get entered text and store in message variable out.setText(""); //clear text area Log.d(TAG, "Starting thread"); Thread aThread = new Thread(new sendThread()); //start the client thread aThread.start(); } }; public class setupThread implements Runnable{ public void run() { try { InetAddress serverAddr = InetAddress.getByName(ipAddress); Log.d(TAG, "Connecting"); sock = new Socket(serverAddr, 5000); connected = true; Log.d(TAG, "Connected"); writer = new PrintWriter(sock.getOutputStream(), true); Log.d(TAG, "Made the writer"); InputStreamReader streamReader = new InputStreamReader(sock.getInputStream()); reader = new BufferedReader(streamReader); Log.d(TAG, "Made the reader"); Log.d(TAG, "Starting sending thread"); //start the entry thread once connected Thread eThread = new Thread(new sendThread()); //start the client thread eThread.start(); incoming = (TextView)findViewById(R.id.incoming); Log.d(TAG, "Starting the receiving thread"); Thread rThread = new Thread(new IncomingReader()); rThread.start(); } catch (Exception e) { Log.e(TAG, "Couldn't connect"); connected = false; } } } public class IncomingReader implements Runnable{ public void run() { Log.d(TAG, "in reader thread"); while (true) { try { final String input; if ((input = reader.readLine()) != null) { //while there are text lines to be read handler.post(new Runnable() { @Override public void run() { incoming.append(input + "\n"); ScrollView sv = (ScrollView) findViewById(R.id.scrl); sv.scrollTo(0, sv.getBottom()); } }); }//close while } catch (Exception ex) { ex.printStackTrace(); } }//close run() } }//close inner class public class sendThread implements Runnable{ public void run(){ Log.d(TAG, "in Thread"); try{ Log.d(TAG, "Sending message"); if (!entered){ //to be called when user first enters chatbox writer.println("~~~"+name+" has entered the chatbox~~~"); entered = true; } else { Log.d(TAG, "got the message to send: " + message); writer.println(name + ": " + message); //send entered text to server } Log.d(TAG, "sent"); }catch(Exception e){ Log.e(TAG,"Couldn't send message"); } //sock.close(); //Log.d(TAG, "Closed"); } } }
|
package Chat; //6.25.15 //Chat Server for SimpleChatClient.java import java.io.*; import java.net.*; import java.util.*; public class SimpleChatServer { ArrayList clientOutputStreams; public class ClientHandler implements Runnable{ //inner class as runnable job for thread BufferedReader reader; Socket sock; public ClientHandler(Socket clientSocket){ //custom constructor for the ClientHandler try{ sock = clientSocket; //create InputStreamReader chained to low-level InputStream from sock: InputStreamReader isReader = new InputStreamReader(sock.getInputStream()); reader = new BufferedReader(isReader); }catch(Exception ex){ //if we get any sort of exception, print it in the StackTrace ex.printStackTrace(); } }//close constructor public void run(){ //implement the Runnable interface... String message; try{ while((message = reader.readLine()) != null) { //while there are lines to read System.out.println(message); tellEveryone(message); //display message to all Clients }//close while }catch(Exception ex){ ex.printStackTrace(); } }//close run }//close inner class public static void main(String[] args){ new SimpleChatServer().go(); //create a new SimpleChatServer object and call its go() method } public void go(){ clientOutputStreams = new ArrayList(); //assign the ArrayList reference variable we created earlier to an ArrayList object try{ ServerSocket serverSock = new ServerSocket(5000); //create a new socket object on port 5000 while(true){ //permanent loop -- wait for client requests Socket clientSocket = serverSock.accept(); PrintWriter writer = new PrintWriter(clientSocket.getOutputStream()); clientOutputStreams.add(writer); //add the new writer to the ArrayList of output streams Thread t = new Thread(new ClientHandler(clientSocket)); t.start(); System.out.println("got a connection"); }//end while true }catch(Exception ex){ ex.printStackTrace(); } }//close go() public void tellEveryone(String message){ Iterator it = clientOutputStreams.iterator(); while(it.hasNext()){ try{ PrintWriter writer = (PrintWriter) it.next(); writer.println(message); writer.flush(); }catch(Exception ex){ ex.printStackTrace(); } }//end while }//close tellEveryone }//close class