Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Рефакторинг на архитектуру MVP #6

Merged
merged 7 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@
### Результат
| Главный экран | Детали контакта |
| ------ | ------ |
| ![Детали](https://i.imgur.com/AavdvqJ.jpg) |![Главный экран](https://i.imgur.com/rhFKsrB.jpg)
| ![Список](https://i.imgur.com/uVBhVfT.jpg) |![Главный экран](https://i.imgur.com/rhFKsrB.jpg)

## Задание №3. Сервисы
Необходимо написать привязанный сервис, который будет иметь публичное API предоставляющее список контактов. Список контактов пока захардкодить в константу
Сервис должен предоставлять список контактов на другом потоке программы - т.е. должен создавать поток для загрузки списка контактов
#### Сценарий использования:
### Сценарий использования:
- Главная активность привязывается к сервису с помощью bindService
- Получает публичный интерфейс сервиса
- Предоставляет публичный интерфейс сервиса фрагментам
Expand All @@ -55,11 +55,11 @@

## Задание №5. Content - Использование поставщика контактов

## Задание
### Задание

Необходимо реализовать загрузку контактов пользователя из поставщика контактов В существующем методе загрузки списка контактов - получать список всех контактов пользователя из поставщика контактов В существующем методе загрузки деталей контакта по ID - получать все необходимые данные контакта из поставщика контактов по ID

## Проделанная работа.
### Проделанная работа.

Добавлен класс-репозиторий контактов ContactRepositoryFromSystem, который позволяет получать список всех контактов, список телефонов и адресов эл.почты и подробную информацию о контакте.

Expand All @@ -77,3 +77,17 @@
Пришлось отказаться от разделения на Фамилию Имя и Отчество. Вместо этого использовать объединенное поле `String displayName;`

Помимо этого переделал фейковый репозиторий контактов `ContactRepositoryFakeImp` для работы с новой моделью контакта.

## Задание №6. Рефакторинг проекта по паттерну MVP

### Задание

Необходимо произвести рефакторинг существующего кода приложения с использованием на выбор: 1. MVVM - использовать компоненты от Google: ViewModel + LiveData 2. MVP - в качестве библиотеки использовать Moxy В рамках рефакторинга необходимо будет удалить существующий сервис загрузки контактов, и всю работу по загрузке контактов из сервиса вынести в репозиторий, который будет использоваться в ViewModel/Presenter соответственно выбранного паттерна проектирования.

### Проделанная работа.

Произвел рефакторинг и изменение архитектуры на MVP с использованием библиотеки Moxy.

Удалил существующий сервис загрузки контактов

Всю работу по загрузке контактов перенс в репозиторий
7 changes: 6 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,16 @@ android {

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

implementation "com.arello-mobile:moxy:1.4.5"
annotationProcessor "com.arello-mobile:moxy-compiler:1.4.5"
implementation ('tech.schoolhelper:moxy-x-androidx:1.7.0'){
exclude group: 'tech.schoolhelper', module:'moxy-x'
}
}
5 changes: 0 additions & 5 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">

<service
android:name=".services.DataFetchService"
android:enabled="true"
android:exported="true"/>

<receiver
android:name=".BirthdayReminderReceiver"
android:enabled="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

public class Constants {
public static final int CODE_PERMISSION_READ_CONTACTS = 1;
public static final String KEY_PERSON_ID = "PERSON_ID";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.a65apps.yuhnin.lesson1.callbacks;

import com.a65apps.yuhnin.lesson1.pojo.ContactInfoModel;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelAdvanced;

import java.util.List;

public interface PersonDetailsCallback {
void onFetchPersonDetails(PersonModelAdvanced personModel);
void onFetchPersonContacts(List<ContactInfoModel> contactList);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.a65apps.yuhnin.lesson1.callbacks;

import com.a65apps.yuhnin.lesson1.pojo.PersonModelCompact;

import java.util.List;

public interface PersonListCallback {
void getPersonList(List<PersonModelCompact> personList);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.a65apps.yuhnin.lesson1.presenters;

import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;

import com.a65apps.yuhnin.lesson1.callbacks.PersonDetailsCallback;
import com.a65apps.yuhnin.lesson1.pojo.ContactInfoModel;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelAdvanced;
import com.a65apps.yuhnin.lesson1.repository.ContactRepository;
import com.a65apps.yuhnin.lesson1.views.ContactDetailsView;
import com.arellomobile.mvp.InjectViewState;
import com.arellomobile.mvp.MvpPresenter;

import java.util.List;

@InjectViewState
public class ContactDetailsPresenter extends MvpPresenter<ContactDetailsView> implements PersonDetailsCallback {
goblinr marked this conversation as resolved.
Show resolved Hide resolved
@NonNull
private final ContactRepository contactRepository;
@NonNull
private final Handler handler;

public ContactDetailsPresenter(@NonNull ContactRepository contactRepository) {
this.contactRepository = contactRepository;
this.handler = new Handler(Looper.getMainLooper());
}

public void requestContactsByPerson(String personId) {
contactRepository.getContactByPerson(this, personId);
}

public void requestPersonDetails(String personId) {
contactRepository.getPersonById(this, personId);
}

@Override
public void onFetchPersonDetails(final PersonModelAdvanced personModel) {
handler.post(new Runnable() {
@Override
public void run() {
getViewState().getContactDetails(personModel);
}
});
}

@Override
public void onFetchPersonContacts(final List<ContactInfoModel> contactList) {
handler.post(new Runnable() {
@Override
public void run() {
getViewState().getContactsInfo(contactList);
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.a65apps.yuhnin.lesson1.presenters;

import android.os.Handler;
import android.os.Looper;

import androidx.annotation.NonNull;

import com.a65apps.yuhnin.lesson1.callbacks.PersonListCallback;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelCompact;
import com.a65apps.yuhnin.lesson1.repository.ContactRepository;
import com.a65apps.yuhnin.lesson1.views.ContactListView;
import com.arellomobile.mvp.InjectViewState;
import com.arellomobile.mvp.MvpPresenter;

import java.util.List;

@InjectViewState
public class ContactListPresenter extends MvpPresenter<ContactListView> implements PersonListCallback {
goblinr marked this conversation as resolved.
Show resolved Hide resolved
@NonNull
private final ContactRepository contactRepository;
@NonNull
private final Handler handler;

public ContactListPresenter(@NonNull ContactRepository contactRepository) {
this.contactRepository = contactRepository;
handler = new Handler(Looper.getMainLooper());
}

public void requestContactList() {
contactRepository.getAllPersons(this);
}

@Override
public void getPersonList(final List<PersonModelCompact> personList) {
handler.post(new Runnable() {
@Override
public void run() {
getViewState().getContactList(personList);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.a65apps.yuhnin.lesson1.pojo.ContactInfoModel;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelAdvanced;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelCompact;
import com.a65apps.yuhnin.lesson1.callbacks.PersonDetailsCallback;
import com.a65apps.yuhnin.lesson1.callbacks.PersonListCallback;

import java.util.List;

public interface ContactRepository {
@Nullable
List<PersonModelCompact> getAllPersons();
void getAllPersons(PersonListCallback callback);

@NonNull
List<ContactInfoModel> getContactByPerson(String id);
void getContactByPerson(PersonDetailsCallback callback, String id);

@Nullable
PersonModelAdvanced getPersonById(String id);
void getPersonById(PersonDetailsCallback callback, String id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.util.Log;

import com.a65apps.yuhnin.lesson1.R;
import com.a65apps.yuhnin.lesson1.callbacks.PersonDetailsCallback;
import com.a65apps.yuhnin.lesson1.callbacks.PersonListCallback;
import com.a65apps.yuhnin.lesson1.pojo.ContactInfoModel;
import com.a65apps.yuhnin.lesson1.pojo.ContactType;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelAdvanced;
import com.a65apps.yuhnin.lesson1.pojo.PersonModelCompact;

import java.text.ParseException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -41,16 +42,11 @@ private void setContext(Context context) {


public ContactRepositoryFakeImp() {
try {
createPersons();
createContacts();
}catch (ParseException ex) {
Log.e(LOG_TAG, "Ошибка формата даты рождения при создании списка контактов. " +
ex.getMessage());
}
createPersons();
createContacts();
}

private void createPersons() throws ParseException{
private void createPersons() {
personModelAdvanceds.add(new PersonModelAdvanced(
"1",
"Гагарин Юрий Алексеевич",
Expand Down Expand Up @@ -98,30 +94,57 @@ private void createContacts() {
}

@Override
public List<PersonModelCompact> getAllPersons() {
return personModelCompacts;
public void getAllPersons(PersonListCallback callback) {
final WeakReference<PersonListCallback> weakReference = new WeakReference(callback);
new Thread(new Runnable() {
@Override
public void run() {
PersonListCallback local = weakReference.get();
if (local != null) {
local.getPersonList(personModelCompacts);
}
}
}).start();
}


@Override
public List<ContactInfoModel> getContactByPerson(String id) {
List<ContactInfoModel> foundContacts = new ArrayList<ContactInfoModel>();
for (ContactInfoModel contact : contactInfoModels) {
if (contact.getPersonId().equals(id)) {
foundContacts.add(contact);
public void getContactByPerson(PersonDetailsCallback callback, final String personId) {
final WeakReference<PersonDetailsCallback> weakReference = new WeakReference(callback);
new Thread(new Runnable() {
@Override
public void run() {
List<ContactInfoModel> foundContacts = new ArrayList<ContactInfoModel>();
for (ContactInfoModel contact : contactInfoModels) {
if (contact.getPersonId().equals(personId)) {
foundContacts.add(contact);
}
}
PersonDetailsCallback local = weakReference.get();
if (local != null) {
local.onFetchPersonContacts(contactInfoModels);
}
}
}
return foundContacts;
}).start();
}

@Override
public PersonModelAdvanced getPersonById(String id) {
for (PersonModelAdvanced personModelAdvanced : personModelAdvanceds) {
if (personModelAdvanced.getId().equals(id)) {
return personModelAdvanced;
public void getPersonById(PersonDetailsCallback callback, final String personId) {
final WeakReference<PersonDetailsCallback> weakReference = new WeakReference(callback);
new Thread(new Runnable() {
@Override
public void run() {
for (PersonModelAdvanced personModelAdvanced : personModelAdvanceds) {
if (personModelAdvanced.getId().equals(personId)) {
PersonDetailsCallback local = weakReference.get();
if (local != null) {
local.onFetchPersonDetails(personModelAdvanced);
}
}
}

}
}
return null;
}).start();
}

public Uri resourceToUri(int resID) {
Expand Down
Loading