Od mojego ostatniego w kodzie źródłowym mojej aplikacji wiele się działo. Dodany został moduł wyszukiwania znajomych i aktywność z profilem użytkownika. Kilka klas doczekało się refactoringu, ale wszystko po kolei…
Klasa SearchFriendActivity
Za pomocą tej klasy użytkownik może przeszukiwać bazę danych z użytkownikami w poszukiwaniu znajomych. Działanie klasy jest proste. Po kliknięciu szukaj zbierany jest tekst zapisany w polu imię i nazwisko. Frazy wysyłane są do Web Service, który zwraca tablicę pasujących do wyszukiwania użytkowników. Wyniki prezentowane są w postaci ListView. Po kliknięciu na poszczególne rekord, użytkownik przekierowywany jest do profilu znajomego. Kod klasy wygląda następująco:
public class SearchFriendActivity extends AppCompatActivity { private String url; private String[][] user; private ListView listView; private ArrayAdapter<String> adapter; private String[][] list; private EditText eName; private EditText eSurname; private ArrayList<String> friends; private WebServiceHelper webServiceHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_search_friend); eName = (EditText)findViewById(R.id.nameText); eSurname = (EditText)findViewById(R.id.surnameText); listView = (ListView) findViewById(R.id.searchFriendsList); listView.setOnItemClickListener(itemClicked); } private AdapterView.OnItemClickListener itemClicked = new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { Intent intent = new Intent(SearchFriendActivity.this, FriendProfileActivity.class); intent.putExtra("friendId", list[position][0]); startActivity(intent); Log.d("ItemClick", list[position][0]); } }; public void searchFriend(View view) { String name = eName.getText().toString(); String surname = eSurname.getText().toString(); url = "http://chinet.cba.pl/meethere.php?search=" + name + "&surname=" + surname; webServiceHelper = new WebServiceHelper(); list = webServiceHelper.getFriends(url); friends = new ArrayList<String>(); for (int i=0; i <list.length; i++) { friends.add(list[i][1] + " " + list[i][2]); } adapter = new ArrayAdapter<String>(this, R.layout.row, friends); adapter.notifyDataSetChanged(); listView.setAdapter(adapter); } }
Plik layout:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_search_friend" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" 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.chinet.meethere.SearchFriendActivity"> <ListView android:id="@+id/searchFriendsList" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/searchButton" android:layout_alignParentStart="true" android:layout_marginTop="53dp" /> <Button android:text="@string/search" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/searchButton" android:layout_marginTop="39dp" android:onClick="searchFriend" android:layout_below="@+id/nameText" android:layout_alignParentEnd="true" android:layout_marginEnd="8dp" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/nameText" android:layout_alignParentTop="true" android:layout_alignEnd="@+id/searchButton" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/surnameText" android:layout_below="@+id/nameText" android:layout_alignEnd="@+id/searchButton" /> <TextView android:text="@string/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/surnameText" android:layout_alignParentStart="true" android:layout_marginStart="40dp" android:layout_marginBottom="7dp" android:id="@+id/nameTextView" /> <TextView android:text="@string/surname" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/surnameTextView" android:layout_alignBottom="@+id/surnameText" android:layout_alignStart="@+id/nameTextView" /> </RelativeLayout>
Profil znajomego
Klasa FriendProfileAcitvity wygląda tak samo jak klasa UserActivity z tą różnicą, że tutaj ID jest pobierane z Bundle, w którym przekazaliśmy ID klikniętego rekordu w SearchFriendActivity. Dodany został też przycisk pozwalający dodać użytkownika do znajomych. Wiele kodu względem UserActivity jest powielane z racji takiej powstała UserHelper, która pozwoliła odchudzić te obie klasy.
public class FriendProfileActivity extends AppCompatActivity { private String url; private UserHelper userHelper; private int userId; private int friendId; private WebServiceHelper webServiceHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_friend_profile); userId = SaveSharedPreference.getId(getApplicationContext()); if (userId == 0) { Intent intent = new Intent(this, LoginActivity.class); startActivity(intent); } else { Bundle bundle = getIntent().getExtras(); friendId = Integer.parseInt(bundle.getString("friendId")); url = "http://chinet.cba.pl/meethere.php?user=" + friendId; userHelper = new UserHelper(); String[] userData = userHelper.getUserFromWS(url); TextView nameText = (TextView) findViewById(R.id.nameText); nameText.setText(userData[0]); TextView ageText = (TextView) findViewById(R.id.ageText); ageText.setText(userData[1]); TextView cityText = (TextView) findViewById(R.id.cityText); cityText.setText(userData[2]); } } public void addFriend(View view) { url = "http://chinet.cba.pl/meethere.php?addFriend=" + userId + "&friend=" + friendId; webServiceHelper = new WebServiceHelper(); webServiceHelper.makeDBOperation(url); Button button = (Button) findViewById(R.id.add_user_button); button.setVisibility(View.INVISIBLE); Toast.makeText(this, "Added new friend", Toast.LENGTH_LONG).show(); } }
Ratunek na duplikację kodu
Klasa UserHelper jest bardzo pomocna, za pomocą jednego wywołania zwraca gotową tablicę z danymi użytkownika. Kod, który się w niej znajduję, jest prawie wierną kopią powtarzającego się kodu w wcześniej wspomnianych klasach, który dodatkowo został opakowany w metody.
public class UserHelper { private String[] user; private String url; public String[] getUserFromWS(String url) { this.url = url; try { user = new UserHelper.GetUser(this).execute().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } String[] userData = getUserData(); return userData; } private String[] getUserData() { String name = user[1] + " " + user[2]; Integer age = calculateYears(user[5]); String city = "City: " + user[4]; String ageString = "Age: " + age; String[] userData = new String[3]; userData[0] = name; userData[1] = ageString; userData[2] = city; return userData; } private Integer calculateYears(String dataFrom) { String[] parts = dataFrom.split(", "); LocalDate df = new LocalDate(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]), Integer.parseInt(parts[2])); LocalDate now = new LocalDate(); Years yearsIns = Years.yearsBetween(df, now); Integer years = yearsIns.getYears(); return years; } private class GetUser extends AsyncTask<String, Void, String[]> { private static final String TAG = "GetUser"; private UserHelper userHelper; private GetUser(UserHelper userHelper) { this.userHelper = userHelper; } @Override protected String[] doInBackground(String... params) { WebServiceHandler webServiceHandler = new WebServiceHandler(); String jsonStr = webServiceHandler.makeServiceCall(url); Log.d(TAG, "Response form url: " + jsonStr); String[] user = new String[8]; if (jsonStr != null) { try { JSONObject jsonObject = new JSONObject(jsonStr); JSONObject u = jsonObject.getJSONObject("user"); user[0] = u.getString("ID"); user[1] = u.getString("name"); user[2] = u.getString("surname"); user[3] = u.getString("email"); user[4] = u.getString("city"); user[5] = u.getString("dayOfBirthday"); user[6] = u.getString("lastLocalization"); user[7] = u.getString("createdAt"); } catch (JSONException e) { Log.e(TAG, "Json parsing error: " + e.getMessage()); } } else { Log.e(TAG, "Couldn't get json from server."); } return user; } @Override protected void onPostExecute(String[] user) { } } }
Klasa WebServiceHelper to kolejna klasa pozwalająca odchodzić inne klasy i rozdzielić funkcjonalności klas i wyciąganie danych z Web Service.
public class WebServiceHelper { private String url; private String operation; private String[][] user; public String makeDBOperation(String url) { this.url = url; try { operation = new dbOperation(this).execute().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return operation; } public String[][] getFriends(String url) { this.url = url; try { user = new GetFriends(this).execute().get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } return user; } private class dbOperation extends AsyncTask<String, Void, String> { private static final String TAG = "dbOperation"; private WebServiceHelper webServiceHelper; private dbOperation(WebServiceHelper webServiceHelper) { this.webServiceHelper = webServiceHelper; } @Override protected String doInBackground(String... strings) { WebServiceHandler webServiceHandler = new WebServiceHandler(); String jsonStr = webServiceHandler.makeServiceCall(url); Log.d(TAG, "Response form url: " + jsonStr); if (jsonStr != null) { try { JSONObject jsonObject = new JSONObject(jsonStr); String response = jsonObject.getString("operation"); String id = jsonObject.getString("id"); if (Objects.equals(response, "success")) { return "success"; } else { return id; } } catch (JSONException e) { e.printStackTrace(); } } return "fail"; } } private class GetFriends extends AsyncTask<String[][], Void, String[][]> { private static final String TAG = "GetFriends"; private WebServiceHelper webServiceHelper; private GetFriends(WebServiceHelper webServiceHelper) { this.webServiceHelper = webServiceHelper; } @Override protected String[][] doInBackground(String[][]... strings) { WebServiceHandler webServiceHandler = new WebServiceHandler(); String jsonStr = webServiceHandler.makeServiceCall(url); String[] list; if (jsonStr != null) { try { JSONObject jsonObject = new JSONObject(jsonStr); JSONArray u = jsonObject.getJSONArray("user"); user = new String[u.length()][3]; Log.d(TAG, u.getJSONObject(0).getString("ID")); for (int i=0; i<u.length(); i++) { user[i][0] = u.getJSONObject(i).getString("ID"); user[i][1] = u.getJSONObject(i).getString("name"); user[i][2] = u.getJSONObject(i).getString("surname"); } } catch (JSONException e) { Log.e(TAG, "Json parsing error: " + e.getMessage()); } } else { Log.e(TAG, "Couldn't get json from server."); } return user; } @Override protected void onPostExecute(String[][] lists) { } } }
Cały kod projektu znajdziesz na moim githubie.
Ten post jest moim dwudziestym postem konkursowym, aż ciężko uwierzyć jak to szybko zleciał, ale to nie koniec pracy nad aplikacją i blogiem. To dopiero początek…