Wyszukiwanie znajomych w aplikacji

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…

pexels-photo-316681

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…

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj /  Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj /  Zmień )

Zdjęcie na Facebooku

Komentujesz korzystając z konta Facebook. Wyloguj /  Zmień )

Połączenie z %s