📜 ⬆️ ⬇️

A simple client server on Android (Internet messenger)

Important. Everything written below does not represent any value for professionals, but can serve as a useful example for novice Android developers! In the code I tried to comment and log all actions.

Go. Many mobile applications (and not only) use the client-server architecture. The general scheme, I think, is clear.


')
Pay attention to each element and note:


No matter how any of these elements are implemented, they are all present in any case. Let's implement a primitive server and an Android client working with it. As an example, we will use any popular mobile Internet instant messenger (Viber, ICQ), and the application will conditionally be called “Internet chat”.

The interaction scheme is as follows:



The client installed on device A sends a message to the client installed on device B. And vice versa. The server plays the role of a link between device A and B ... C, D ... etc. It also plays the role of the “accumulator” of messages, for their recovery, in case of deletion on one of the client devices.

To store messages, we use SQL database both on the server and on client devices (in principle, all the work of Internet messenger clients comes down to constant synchronization of the local and remote databases with messages). Additionally, our online chat will be able to start with the launch of the device and work in the background. The interaction will occur through HTTP requests and JSON responses.
More logically, if synchronization occurs via a port / socket, on the one hand it simplifies the task (no need to cycle HTTP requests to check new messages, it is enough to check the status of the listening socket), but on the other hand, it complicates the creation of the server part of the application.

Making the server


To implement the "server", we need to register on any hosting that allows you to work with SQL and PHP.

Create an empty SQL database, create a table in it.

Chat table
CREATE TABLE `chat` ( `_id` int(11) NOT NULL AUTO_INCREMENT, `author` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `client` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `data` bigint(20) NOT NULL, `text` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, PRIMARY KEY (`_id`) ) 


The structure is as follows:

  1. author - the author of the message;
  2. client - the recipient of the message;
  3. data - time and date of receipt of the message on the server;
  4. text - the message.

In the next two files, you need to change the variables containing the data for accessing the database to your own ones, which you received when registering your "server".

 $mysql_host = "localhost"; // sql ,     .  mysql5.000webhost.com $mysql_user = "l29340eb_chat"; //  $mysql_password = "123456789"; //  $mysql_database = "l29340eb_chat"; //      SQL 

The chat.php file is our api, which implements the structure of requests that are clear to the server.
 <?php //   utf-8 ! // ----------------------------------------------------------         $mysql_host = "localhost"; // sql  $mysql_user = "l29340eb_chat"; //  $mysql_password = "123456789"; //  $mysql_database = "l29340eb_chat"; //    chat // ----------------------------------------------------------       //  ...chat.php?action=select //----------------------------------------------------------- //  action  : // select -    chat  JSON    // insert -      chat,    4  : // / //        ,      // delete -      chat -      // -------------------------------------------   action if (isset($_GET["action"])) { $action = $_GET['action']; } // -------------------------------------------  action=insert    author|client|text if (isset($_GET["author"])) { $author = $_GET['author']; } if (isset($_GET["client"])) { $client = $_GET['client']; } if (isset($_GET["text"])) { $text = $_GET['text']; } // -------------------------------------------  action=select    data -       if (isset($_GET["data"])) { $data = $_GET['data']; } mysql_connect($mysql_host, $mysql_user, $mysql_password); //    SQL mysql_select_db($mysql_database); //      mysql_set_charset('utf8'); //  // ------------------------------------------------------------      if($action == select){ //   SELECT if($data == null){ //    chat         JSON $q=mysql_query("SELECT * FROM chat"); }else{ //    chat          JSON $q=mysql_query("SELECT * FROM chat WHERE data > $data"); } while($e=mysql_fetch_assoc($q)) $output[]=$e; print(json_encode($output)); } if($action == insert && $author != null && $client != null && $text != null){ //   INSERT      //  =      ! $current_time = round(microtime(1) * 1000); //    : // chat.php?action=insert&author=author&client=client&text=text //      mysql_query("INSERT INTO `chat`(`author`,`client`,`data`,`text`) VALUES ('$author','$client','$current_time','$text')"); } if($action == delete){ //   DELETE //     mysql_query("TRUNCATE TABLE `chat`"); } mysql_close(); ?> 


The structure of requests to api:


Examples:


The showBD.php file is an optional script for visualizing the contents of the database in the browser.
 <?php //  utf-8 ! // --------------------------------------------------------------------------   $mysql_host = "localhost"; // sql  $mysql_user = "l29340eb_chat"; //  $mysql_password = "123456789"; //  $mysql_database = "l29340eb_chat"; //    chat // --------------------------------------------------------------------------    if (!mysql_connect($mysql_host, $mysql_user, $mysql_password)){ echo "<h2> !</h2>"; exit; }else{ // --------------------------------------------------------------------------    echo "<h2> !</h2>"; mysql_select_db($mysql_database); mysql_set_charset('utf8'); // --------------------------------------------------------------------------  JSON $q=mysql_query("SELECT * FROM chat"); echo "<h3>Json :</h3>"; //  json while($e=mysql_fetch_assoc($q)) $output[]=$e; print(json_encode($output)); // --------------------------------------------------------------------------   $q=mysql_query("SELECT * FROM chat"); echo "<h3> :</h3>"; echo "<table border=\"1\" width=\"100%\" bgcolor=\"#999999\">"; echo "<tr><td>_id</td><td>author</td>"; echo "<td>client</td><td>data</td><td>text</td></tr>"; for ($c=0; $c<mysql_num_rows($q); $c++){ $f = mysql_fetch_array($q); echo "<tr><td>$f[_id]</td><td>$f[author]</td><td>$f[client]</td><td>$f[data]</td><td>$f[text]</td></tr>"; } echo "</tr></table>"; } mysql_close(); // --------------------------------------------------------------------------     ?> 


Client part


Now the structure of the Android application:



In the background, FoneService.java works, which, in a separate thread, makes a request to the server every 15 seconds. If the server response contains new messages, FoneService.java writes them to the local database and sends a message to ChatActivity.java about the need to update the ListView, with messages. ChatActivity.java (if it is currently open) receives the message and updates the contents of the ListView from the local database.

Sending a new message from ChatActivity.java occurs immediately to the server, bypassing FoneService.java. However, our message is NOT recorded in the local database! There it will appear only after receiving it back as a server response. I used this implementation in connection with the important nuance of the work of any Internet chat - the mandatory grouping of messages by time. If you do not use time grouping, the sequence of messages will be broken. Considering that client applications simply cannot physically be synchronized to the nearest millisecond, and may even work in different time zones, it would be more logical to use server time. So we do.

When creating a new message, we send a request to the server: the name of the author of the message, the name of the message recipient, the text of the message. Receiving this record back, in the form of a server response, we get what we sent + the fourth parameter: the time the server received the message.

In MainActivity.java, for clarity, I added the ability to delete messages from the local database - this is equivalent to a clean installation of the application (in this case, FoneService will send a request to the server to receive all messages of the selected chat). It is also possible to send a request to delete all messages from the database located on the server.

Activity Code:

FoneService.java
 package by.andreidanilevich.temp_chat; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import org.json.JSONArray; import org.json.JSONObject; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.BitmapFactory; import android.os.IBinder; import android.util.Log; public class FoneService extends Service { //   (url   ) //  http://l29340eb.bget.ru String server_name = "http://l29340eb.bget.ru"; SQLiteDatabase chatDBlocal; HttpURLConnection conn; Cursor cursor; Thread thr; ContentValues new_mess; Long last_time; //     ,      //   ,     @Override public IBinder onBind(Intent intent) { return null; } public void onStart(Intent intent, int startId) { Log.i("chat", "+ FoneService -  "); chatDBlocal = openOrCreateDatabase("chatDBlocal.db", Context.MODE_PRIVATE, null); chatDBlocal .execSQL("CREATE TABLE IF NOT EXISTS chat (_id integer primary key autoincrement, author, client, data, text)"); //    notification //     "" //       Intent iN = new Intent(getApplicationContext(), MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pI = PendingIntent.getActivity(getApplicationContext(), 0, iN, PendingIntent.FLAG_CANCEL_CURRENT); Notification.Builder bI = new Notification.Builder( getApplicationContext()); bI.setContentIntent(pI) .setSmallIcon(R.drawable.ic_launcher) .setLargeIcon( BitmapFactory.decodeResource(getApplicationContext() .getResources(), R.drawable.ic_launcher)) .setAutoCancel(true) .setContentTitle(getResources().getString(R.string.app_name)) .setContentText("..."); Notification notification = bI.build(); startForeground(101, notification); startLoop(); } //  ,     //        // . //    -     // ListView  ChatActivity private void startLoop() { thr = new Thread(new Runnable() { // ansver =    // lnk =    String ansver, lnk; public void run() { while (true) { //    //        cursor = chatDBlocal.rawQuery( "SELECT * FROM chat ORDER BY data", null); //  -   -   //       if (cursor.moveToLast()) { last_time = cursor.getLong(cursor .getColumnIndex("data")); lnk = server_name + "/chat.php?action=select&data=" + last_time.toString(); //      -   //     } else { lnk = server_name + "/chat.php?action=select"; } cursor.close(); //   ----------------------------------> try { Log.i("chat", "+ FoneService ---------------  "); conn = (HttpURLConnection) new URL(lnk) .openConnection(); conn.setReadTimeout(10000); conn.setConnectTimeout(15000); conn.setRequestMethod("POST"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); conn.setDoInput(true); conn.connect(); } catch (Exception e) { Log.i("chat", "+ FoneService : " + e.getMessage()); } //   ----------------------------------> try { InputStream is = conn.getInputStream(); BufferedReader br = new BufferedReader( new InputStreamReader(is, "UTF-8")); StringBuilder sb = new StringBuilder(); String bfr_st = null; while ((bfr_st = br.readLine()) != null) { sb.append(bfr_st); } Log.i("chat", "+ FoneService -   :\n" + sb.toString()); //     string //     ,    "]" //  , .. json     //       -   ansver = sb.toString(); ansver = ansver.substring(0, ansver.indexOf("]") + 1); is.close(); //   br.close(); //   } catch (Exception e) { Log.i("chat", "+ FoneService : " + e.getMessage()); } finally { conn.disconnect(); Log.i("chat", "+ FoneService ---------------  "); } //     ----------------------------------> if (ansver != null && !ansver.trim().equals("")) { Log.i("chat", "+ FoneService ----------   JSON:"); try { //    JSON  JSONArray ja = new JSONArray(ansver); JSONObject jo; Integer i = 0; while (i < ja.length()) { //  JSON   jo = ja.getJSONObject(i); Log.i("chat", "=================>>> " + jo.getString("author") + " | " + jo.getString("client") + " | " + jo.getLong("data") + " | " + jo.getString("text")); //    new_mess = new ContentValues(); new_mess.put("author", jo.getString("author")); new_mess.put("client", jo.getString("client")); new_mess.put("data", jo.getLong("data")); new_mess.put("text", jo.getString("text")); //      chatDBlocal.insert("chat", null, new_mess); new_mess.clear(); i++; //    ChatActivity //    -   ListView sendBroadcast(new Intent( "by.andreidanilevich.action.UPDATE_ListView")); } } catch (Exception e) { //       JSON Log.i("chat", "+ FoneService ----------   :\n" + e.getMessage()); } } else { //     Log.i("chat", "+ FoneService ----------    JSON!"); } try { Thread.sleep(15000); } catch (Exception e) { Log.i("chat", "+ FoneService -  : " + e.getMessage()); } } } }); thr.setDaemon(true); thr.start(); } } 


ChatActivity.java
 package by.andreidanilevich.temp_chat; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; public class ChatActivity extends Activity { //   (url   ) //  http://l29340eb.bget.ru String server_name = "http://l29340eb.bget.ru"; ListView lv; //   EditText et; Button bt; SQLiteDatabase chatDBlocal; String author, client; INSERTtoChat insert_to_chat; //       UpdateReceiver upd_res; //         - //  ListView @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.chat); //  2        : // author -      // client -    Intent intent = getIntent(); author = intent.getStringExtra("author"); client = intent.getStringExtra("client"); Log.i("chat", "+ ChatActivity -  author = " + author + " | client = " + client); lv = (ListView) findViewById(R.id.lv); et = (EditText) findViewById(R.id.et); bt = (Button) findViewById(R.id.bt); chatDBlocal = openOrCreateDatabase("chatDBlocal.db", Context.MODE_PRIVATE, null); chatDBlocal .execSQL("CREATE TABLE IF NOT EXISTS chat (_id integer primary key autoincrement, author, client, data, text)"); //      upd_res = new UpdateReceiver(); registerReceiver(upd_res, new IntentFilter( "by.andreidanilevich.action.UPDATE_ListView")); create_lv(); } //  lv =     lv    @SuppressLint("SimpleDateFormat") public void create_lv() { Cursor cursor = chatDBlocal.rawQuery( "SELECT * FROM chat WHERE author = '" + author + "' OR author = '" + client + "' ORDER BY data", null); if (cursor.moveToFirst()) { //       //    //  ,  hashmap     // cursor ArrayList<HashMap<String, Object>> mList = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> hm; do { //   !!! //    =  //    =  if (cursor.getString(cursor.getColumnIndex("author")).equals( author) && cursor.getString(cursor.getColumnIndex("client")) .equals(client)) { hm = new HashMap<>(); hm.put("author", author); hm.put("client", ""); hm.put("list_client", ""); hm.put("list_client_time", ""); hm.put("list_author", cursor.getString(cursor.getColumnIndex("text"))); hm.put("list_author_time", new SimpleDateFormat( "HH:mm - dd.MM.yyyy").format(new Date(cursor .getLong(cursor.getColumnIndex("data"))))); mList.add(hm); } //   !!!!!!! //    =  //     =  if (cursor.getString(cursor.getColumnIndex("author")).equals( client) && cursor.getString(cursor.getColumnIndex("client")) .equals(author)) { hm = new HashMap<>(); hm.put("author", ""); hm.put("client", client); hm.put("list_author", ""); hm.put("list_author_time", ""); hm.put("list_client", cursor.getString(cursor.getColumnIndex("text"))); hm.put("list_client_time", new SimpleDateFormat( "HH:mm - dd.MM.yyyy").format(new Date(cursor .getLong(cursor.getColumnIndex("data"))))); mList.add(hm); } } while (cursor.moveToNext()); //  lv SimpleAdapter adapter = new SimpleAdapter(getApplicationContext(), mList, R.layout.list, new String[] { "list_author", "list_author_time", "list_client", "list_client_time", "author", "client" }, new int[] { R.id.list_author, R.id.list_author_time, R.id.list_client, R.id.list_client_time, R.id.author, R.id.client }); lv.setAdapter(adapter); cursor.close(); } Log.i("chat", "+ ChatActivity ========================   "); } public void send(View v) { //     //     if (!et.getText().toString().trim().equals("")) { //    bt.setEnabled(false); //    - ! insert_to_chat = new INSERTtoChat(); insert_to_chat.execute(); } else { //    -    et.setText(""); } } //     private class INSERTtoChat extends AsyncTask<Void, Void, Integer> { HttpURLConnection conn; Integer res; protected Integer doInBackground(Void... params) { try { //       String post_url = server_name + "/chat.php?action=insert&author=" + URLEncoder.encode(author, "UTF-8") + "&client=" + URLEncoder.encode(client, "UTF-8") + "&text=" + URLEncoder.encode(et.getText().toString().trim(), "UTF-8"); Log.i("chat", "+ ChatActivity -     : " + et.getText().toString().trim()); URL url = new URL(post_url); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); //  10 conn.setRequestMethod("POST"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); conn.connect(); res = conn.getResponseCode(); Log.i("chat", "+ ChatActivity -   (200 -  ): " + res.toString()); } catch (Exception e) { Log.i("chat", "+ ChatActivity -  : " + e.getMessage()); } finally { //   conn.disconnect(); } return res; } protected void onPostExecute(Integer result) { try { if (result == 200) { Log.i("chat", "+ ChatActivity -   ."); //    et.setText(""); } } catch (Exception e) { Log.i("chat", "+ ChatActivity -   :\n" + e.getMessage()); Toast.makeText(getApplicationContext(), "  ", Toast.LENGTH_SHORT).show(); } finally { //   bt.setEnabled(true); } } } //      FoneService //   ,       -  ListView public class UpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i("chat", "+ ChatActivity -    -  ListView"); create_lv(); } } //    public void onBackPressed() { Log.i("chat", "+ ChatActivity - "); unregisterReceiver(upd_res); finish(); } } 


MainActivity.java
 package by.andreidanilevich.temp_chat; import java.net.HttpURLConnection; import java.net.URL; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteDatabase; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.Toast; public class MainActivity extends Activity { //   (url   ) //  http://l29340eb.bget.ru String server_name = "http://l29340eb.bget.ru"; Spinner spinner_author, spinner_client; String author, client; Button open_chat_btn, open_chat_reverce_btn, delete_server_chat; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Log.i("chat", "+ MainActivity -  "); open_chat_btn = (Button) findViewById(R.id.open_chat_btn); open_chat_reverce_btn = (Button) findViewById(R.id.open_chat_reverce_btn); delete_server_chat = (Button) findViewById(R.id.delete_server_chat); //  FoneService this.startService(new Intent(this, FoneService.class)); //  2         // 5   5   //   spinner_author = (Spinner) findViewById(R.id.spinner_author); spinner_client = (Spinner) findViewById(R.id.spinner_client); spinner_author.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, new String[] { "", "", "", "", "", "", "", "", "", "" })); spinner_client.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, new String[] { "", "", "", "", "", "", "", "", "", "" })); spinner_client.setSelection(5); open_chat_btn.setText(" : " + spinner_author.getSelectedItem().toString() + " > " + spinner_client.getSelectedItem().toString()); open_chat_reverce_btn.setText(" : " + spinner_client.getSelectedItem().toString() + " > " + spinner_author.getSelectedItem().toString()); spinner_author .setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View itemSelected, int selectedItemPosition, long selectedId) { author = spinner_author.getSelectedItem().toString(); open_chat_btn.setText(" : " + spinner_author.getSelectedItem().toString() + " > " + spinner_client.getSelectedItem().toString()); open_chat_reverce_btn.setText(" : " + spinner_client.getSelectedItem().toString() + " > " + spinner_author.getSelectedItem().toString()); } public void onNothingSelected(AdapterView<?> parent) { } }); spinner_client .setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView<?> parent, View itemSelected, int selectedItemPosition, long selectedId) { client = spinner_client.getSelectedItem().toString(); open_chat_btn.setText(" : " + spinner_author.getSelectedItem().toString() + " > " + spinner_client.getSelectedItem().toString()); open_chat_reverce_btn.setText(" : " + spinner_client.getSelectedItem().toString() + " > " + spinner_author.getSelectedItem().toString()); } public void onNothingSelected(AdapterView<?> parent) { } }); } //        public void open_chat(View v) { //   if (author.equals(client)) { //      //    Toast.makeText(this, "author = client !", Toast.LENGTH_SHORT) .show(); } else { //    author > client Intent intent = new Intent(MainActivity.this, ChatActivity.class); intent.putExtra("author", author); intent.putExtra("client", client); startActivity(intent); } } //       ,   public void open_chat_reverce(View v) { //   if (author.equals(client)) { //      //    Toast.makeText(this, "author = client !", Toast.LENGTH_SHORT) .show(); } else { //    client > author Intent intent = new Intent(MainActivity.this, ChatActivity.class); intent.putExtra("author", client); intent.putExtra("client", author); startActivity(intent); } } //          public void delete_server_chats(View v) { Log.i("chat", "+ MainActivity -      "); delete_server_chat.setEnabled(false); delete_server_chat.setText(" . ..."); DELETEfromChat delete_from_chat = new DELETEfromChat(); delete_from_chat.execute(); } //     //     public void delete_local_chats(View v) { Log.i("chat", "+ MainActivity -     "); SQLiteDatabase chatDBlocal; chatDBlocal = openOrCreateDatabase("chatDBlocal.db", Context.MODE_PRIVATE, null); chatDBlocal.execSQL("drop table chat"); chatDBlocal .execSQL("CREATE TABLE IF NOT EXISTS chat (_id integer primary key autoincrement, author, client, data, text)"); Toast.makeText(getApplicationContext(), "    !", Toast.LENGTH_SHORT).show(); } //          //    -    //    (     ) // -   private class DELETEfromChat extends AsyncTask<Void, Void, Integer> { Integer res; HttpURLConnection conn; protected Integer doInBackground(Void... params) { try { URL url = new URL(server_name + "/chat.php?action=delete"); conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(10000); //  10 conn.setRequestMethod("POST"); conn.setRequestProperty("User-Agent", "Mozilla/5.0"); conn.connect(); res = conn.getResponseCode(); Log.i("chat", "+ MainActivity -   (200 = ): " + res.toString()); } catch (Exception e) { Log.i("chat", "+ MainActivity -   : " + e.getMessage()); } finally { conn.disconnect(); } return res; } protected void onPostExecute(Integer result) { try { if (result == 200) { Toast.makeText(getApplicationContext(), "   !", Toast.LENGTH_SHORT) .show(); } } catch (Exception e) { Toast.makeText(getApplicationContext(), "  .", Toast.LENGTH_SHORT) .show(); } finally { //    delete_server_chat.setEnabled(true); delete_server_chat.setText("    !"); } } } public void onBackPressed() { Log.i("chat", "+ MainActivity -   "); finish(); } } 


AutoRun.java
 package by.andreidanilevich.temp_chat; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class AutoRun extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { //  boot_completed -  FoneService context.startService(new Intent(context, FoneService.class)); Log.i("chat", "+ AutoRun - "); } } } <b>:</b> 


AndroidManifest
 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="by.andreidanilevich.temp_chat" android:versionCode="1" android:versionName="1.0" > <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="22" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="portrait" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ChatActivity" android:label="@string/app_name" android:screenOrientation="portrait" > </activity> <receiver android:name=".AutoRun" android:enabled="true" android:exported="false" > <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED" /> </intent-filter> </receiver> <service android:name=".FoneService" /> </application> </manifest> 


Markup:

Markup chat.xml
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#999999" > <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="60dp" android:scrollbars="none" android:stackFromBottom="true" android:transcriptMode="alwaysScroll" > </ListView> <LinearLayout android:layout_width="match_parent" android:layout_height="60dp" android:layout_alignParentBottom="true" android:background="#ffffff" > <EditText android:id="@+id/et" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_weight="1" android:ems="10" > </EditText> <Button android:id="@+id/bt" android:layout_width="50dp" android:layout_height="wrap_content" android:layout_gravity="top" android:onClick="send" android:text=">" /> </LinearLayout> </RelativeLayout> 


Main.xml markup
 <LinearLayout 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" android:orientation="vertical" tools:context="${relativePackage}.${activityClass}" > <Spinner android:id="@+id/spinner_author" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Spinner android:id="@+id/spinner_client" android:layout_width="match_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/open_chat_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="open_chat" /> <Button android:id="@+id/open_chat_reverce_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="open_chat_reverce" /> <Button android:id="@+id/delete_server_chat" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:onClick="delete_server_chats" android:text="    !" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="delete_local_chats" android:text="     !" /> </LinearLayout> 


Markup list.xml
 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#999999" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" > <TextView android:id="@+id/author" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:textColor="#c6c6c6" android:textSize="12sp" /> <TextView android:id="@+id/client" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:textColor="#c6c6c6" android:textSize="12sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" > <TextView android:id="@+id/list_author" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:textColor="#0000ff" android:textSize="14sp" android:textStyle="bold" /> <TextView android:id="@+id/list_client" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="left" android:textColor="#ffff00" android:textSize="14sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="5dp" > <TextView android:id="@+id/list_author_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:textColor="#c6c6c6" android:textSize="12sp" /> <TextView android:id="@+id/list_client_time" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="right" android:textColor="#c6c6c6" android:textSize="12sp" /> </LinearLayout> </LinearLayout> 


And all together (+ apk):

github.com/andreidanilevich/temp_chat

PS:

1. If you downloaded apk from the link above, first check the availability of my “server” at l29340eb.bget.ru/showBD.php .
2. The code was written for a long time, of course, not everything is beautiful and according to the canons, perhaps not all exceptions are processed and there are errors. This is a draft. Everything worked for me on real devices and on an emulator.
3. If anyone comes in handy - I will be happy. For criticism - thanks, for constructive messages - thanks twice. I will try to answer the questions.

Source: https://habr.com/ru/post/269135/


All Articles