Skip to content
Open
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
3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ dependencies {
compile libraries.supportRecyclerView
compile libraries.supportCardView

compile libraries.okhttp
compile libraries.gson

compile libraries.butterKnife
apt libraries.butterKnifeCompiler

Expand Down
1 change: 1 addition & 0 deletions app/src/main/assets/singers.json

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions app/src/main/java/ru/yandex/yamblz/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

import ru.yandex.yamblz.developer_settings.DevMetricsProxy;
import ru.yandex.yamblz.developer_settings.DeveloperSettingsModel;
import ru.yandex.yamblz.handler.CriticalSectionsManager;
import ru.yandex.yamblz.loader.CollageLoaderManager;
import timber.log.Timber;

public class App extends Application {
Expand All @@ -33,9 +31,6 @@ public void onCreate() {
DevMetricsProxy devMetricsProxy = applicationComponent.devMetricsProxy();
devMetricsProxy.apply();
}

CollageLoaderManager.init(null); // add implementation
CriticalSectionsManager.init(null); // add implementation
}

@NonNull
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/ru/yandex/yamblz/ApplicationComponent.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
import javax.inject.Singleton;

import dagger.Component;
import okhttp3.OkHttpClient;
import ru.yandex.yamblz.developer_settings.DevMetricsProxy;
import ru.yandex.yamblz.developer_settings.DeveloperSettingsComponent;
import ru.yandex.yamblz.developer_settings.DeveloperSettingsModel;
import ru.yandex.yamblz.developer_settings.DeveloperSettingsModule;
import ru.yandex.yamblz.developer_settings.LeakCanaryProxy;
import ru.yandex.yamblz.handler.CriticalSectionsHandler;
import ru.yandex.yamblz.loader.CollageLoader;
import ru.yandex.yamblz.api.SingersApi;
import ru.yandex.yamblz.ui.activities.MainActivity;
import ru.yandex.yamblz.ui.fragments.ContentFragment;

@Singleton
@Component(modules = {
Expand All @@ -36,4 +41,16 @@ public interface ApplicationComponent {
Handler mainThreadHandler();

void inject(@NonNull MainActivity mainActivity);

void inject(@NonNull ContentFragment fragment);

@NonNull CollageLoader collageLoader();

@NonNull OkHttpClient okHttpClient();

@NonNull
SingersApi singersApi();

@NonNull
CriticalSectionsHandler uiCriticalSectionsHandler();
}
86 changes: 86 additions & 0 deletions app/src/main/java/ru/yandex/yamblz/ApplicationModule.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
package ru.yandex.yamblz;

import android.app.Application;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;

import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.inject.Named;
import javax.inject.Singleton;

import dagger.Module;
import dagger.Provides;
import okhttp3.OkHttpClient;
import ru.yandex.yamblz.api.AssetsSingersApi;
import ru.yandex.yamblz.handler.CriticalSectionsHandler;
import ru.yandex.yamblz.handler.CriticalSectionsHandlerThread;
import ru.yandex.yamblz.images.Cache;
import ru.yandex.yamblz.loader.CollageLoader;
import ru.yandex.yamblz.loader.CollageStrategy;
import ru.yandex.yamblz.images.ImageDownloader;
import ru.yandex.yamblz.images.ImagesLRUCache;
import ru.yandex.yamblz.loader.ParallelCollageLoader;
import ru.yandex.yamblz.api.SingersApi;
import ru.yandex.yamblz.loader.TableCollageStrategy;
import ru.yandex.yamblz.images.UrlImageDownloader;

@Module
public class ApplicationModule {

public static final String MAIN_THREAD_HANDLER = "main_thread_handler";

public static final String POST_EXECUTOR = "POST_EXECUTOR";

public static final String WORKER_EXECUTOR = "WORKER_EXECUTOR";

@NonNull
private final Application application;

Expand All @@ -33,4 +56,67 @@ public Handler provideMainThreadHandler() {
return new Handler(Looper.getMainLooper());
}

@Provides
@Singleton
@Named(POST_EXECUTOR)
Executor providePostExecutor() {
Handler handler = new Handler(Looper.getMainLooper());
Executor executor = handler::post;
return executor;
}

@Provides
@Singleton
@Named(WORKER_EXECUTOR)
Executor provideWorkerExecutor() {
return new ThreadPoolExecutor(4, 10, 120, TimeUnit.SECONDS, new LinkedBlockingDeque<>());
}

@Provides
@Singleton
ImageDownloader provideImageDownloader(OkHttpClient okHttpClient) {
return new UrlImageDownloader(okHttpClient);
}

@Provides
@Singleton
CollageStrategy provideCollageStrategy() {
return new TableCollageStrategy();
}

@Provides
@Singleton
Cache<String, Bitmap> provideImageCache() {
return new ImagesLRUCache(4 * 1024 * 1024);
}

@Provides
@Singleton
CollageLoader provideCollageLoader(@Named(POST_EXECUTOR) Executor postExecutor,
@Named(WORKER_EXECUTOR) Executor workerExecutor,
ImageDownloader imageDownloader,
CollageStrategy defaultStrategy,
Cache<String, Bitmap> cache) {
return new ParallelCollageLoader(postExecutor, workerExecutor, imageDownloader,
defaultStrategy, cache);
}

@Provides
@Singleton
OkHttpClient provideOkHttpClient() {
return new OkHttpClient();
}

@Provides
@Singleton
SingersApi provideSingersApi(Application application) {
return new AssetsSingersApi(application);
}

@Provides
@Singleton
CriticalSectionsHandler provideUiCriticalSectionsHandler(@Named(MAIN_THREAD_HANDLER) Handler handler) {
return new CriticalSectionsHandlerThread(handler);
}

}
34 changes: 34 additions & 0 deletions app/src/main/java/ru/yandex/yamblz/api/AssetsSingersApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ru.yandex.yamblz.api;

import android.content.Context;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;

import ru.yandex.yamblz.models.Singer;

public class AssetsSingersApi implements SingersApi {

private Context mContext;

public AssetsSingersApi(Context context) {
this.mContext = context;
}

@Override
public List<Singer> getSingers() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(mContext.getAssets()
.open("singers.json")));
return new Gson().fromJson(reader, new TypeToken<List<Singer>>() {}.getType());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
17 changes: 17 additions & 0 deletions app/src/main/java/ru/yandex/yamblz/api/SingersApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ru.yandex.yamblz.api;

import android.support.annotation.Nullable;

import java.util.List;

import ru.yandex.yamblz.models.Singer;

public interface SingersApi {

/**
* Returns list of available singers
* @return list of singers or {@code null} if an error occured
*/
@Nullable List<Singer> getSingers();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package ru.yandex.yamblz.handler;

import android.os.Handler;
import android.os.HandlerThread;
import android.support.annotation.MainThread;

import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;

/**
* Implementation of {@link CriticalSectionsHandler} which uses {@link HandlerThread} for delayed tasks
* internally
*/
public class CriticalSectionsHandlerThread implements CriticalSectionsHandler {

//UI thread handler, or any other thread actually
private Handler mPostHandler;

//Set of sections
private Set<Integer> mSections = new HashSet<>();
//Queue of tasks
private Queue<Task> mTasks = new ArrayDeque<>();

//Worker handler for delayed tasks
private Handler mWorkerHandler;

@MainThread
public CriticalSectionsHandlerThread(Handler postHandler) {
mPostHandler = postHandler;
initWorkerHandler();
}

private void initWorkerHandler() {
HandlerThread handlerThread = new HandlerThread("worker");
handlerThread.start();
mWorkerHandler = new Handler(handlerThread.getLooper());
}

@Override
@MainThread
public void startSection(int id) {
mSections.add(id);
}

@Override
@MainThread
public void stopSection(int id) {
mSections.remove(id);
startTasksIfCan();
}

/**
* Starts tasks if no critical section
*/
@MainThread
private void startTasksIfCan() {
if (!isInCriticalSection()) {
startTasks();
}
}

/**
* Starts tasks
*/
@MainThread
private void startTasks() {
while (!mTasks.isEmpty()) {
//Why post? So not to load main thread
mPostHandler.post(mTasks.poll()::run);
}
}

/**
* Checks whether there are any critical sections
* @return
*/
@MainThread
private boolean isInCriticalSection() {
return mSections.size() != 0;
}

@Override
@MainThread
public void stopSections() {
mSections.clear();
startTasks();
}

@Override
@MainThread
public void postLowPriorityTask(Task task) {
mTasks.add(task);
startTasksIfCan();
}

@Override
@MainThread
public void postLowPriorityTaskDelayed(Task task, int delay) {
//first post to worker thread with delay, then post to main thread to queue
mWorkerHandler.postDelayed(() -> mPostHandler.post(() -> postLowPriorityTask(task)), delay);
}

@Override
@MainThread
public void removeLowPriorityTask(Task task) {
mTasks.remove(task);
}

@Override
@MainThread
public void removeLowPriorityTasks() {
mTasks.clear();
}
}

This file was deleted.

Loading