diff --git a/README.md b/README.md
index 12c65f8..6f1fa31 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@
|指示器加标题模式
水平显示|![效果示例](https://raw.githubusercontent.com/youth5201314/banner/master/image/5.png)
### 联系方式
-![效果示例](https://raw.githubusercontent.com/youth5201314/banner/master/image/Android技术交流群二维码.png)
+![效果示例](http://oceh51kku.bkt.clouddn.com/Android%E6%8A%80%E6%9C%AF%E4%BA%A4%E6%B5%81%E7%BE%A4%E4%BA%8C%E7%BB%B4%E7%A0%81.png)
* 如果遇到问题和建议欢迎在给我发送邮件或者加入qq群,希望让这个工程越来越完善。
## 常量
@@ -64,6 +64,7 @@
|startAutoPlay()|开始轮播|1.4开始,此方法只作用于banner加载完毕-->需要在start()后执行
|stopAutoPlay()|结束轮播|1.4开始,此方法只作用于banner加载完毕-->需要在start()后执行
|start()|开始进行banner渲染|1.4开始
+|setOffscreenPageLimit(int limit)|同viewpager的方法作用一样|1.4.2开始
|setBannerTitle(String[] titles)| 设置轮播要显示的标题和图片对应(如果不传默认不显示标题)|1.3.3结束
|setBannerTitleList(List titles)| 设置轮播要显示的标题和图片对应(如果不传默认不显示标题)|1.3.3结束
|setBannerTitles(List titles)| 设置轮播要显示的标题和图片对应(如果不传默认不显示标题)|1.4开始
@@ -103,9 +104,9 @@
Gradle
```groovy
dependencies{
- compile 'com.youth.banner:banner:1.4.1' //最新版本
+ compile 'com.youth.banner:banner:1.4.2' //最新版本
or
- compile 'com.youth.banner:banner:1.3.3' //旧版本
+ compile 'com.youth.banner:banner:1.3.3' //旧版本,旧版本用法下面有跳转链接
}
```
或者引用本地lib
@@ -135,12 +136,11 @@ compile project(':banner')
#### Step 4.重写图片加载器
```java
-public class GlideImageLoader implements ImageLoader {
+public class GlideImageLoader extends ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
/**
常用的图片加载库:
-
Universal Image Loader:一个强大的图片加载库,包含各种各样的配置,最老牌,使用也最广泛。
Picasso: Square出品,必属精品。和OkHttp搭配起来更配呦!
Volley ImageLoader:Google官方出品,可惜不能加载本地图片~
@@ -148,10 +148,21 @@ public class GlideImageLoader implements ImageLoader {
Glide:Google推荐的图片加载库,专注于流畅的滚动。
*/
+ //Glide 加载图片简单用法
Glide.with(context).load(path).into(imageView);
- or
+
+ //Picasso 加载图片简单用法
Picasso.with(context).load(path).into(imageView)
- ......
+
+ //用fresco加载图片简单用法
+ Uri uri = Uri.parse((String) path);
+ imageView.setImageURI(uri);
+ }
+ //提供createImageView 方法,如果不用可以不重写这个方法,方便fresco自定义ImageView
+ @Override
+ public ImageView createImageView(Context context) {
+ SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context);
+ return simpleDraweeView;
}
}
```
@@ -264,6 +275,15 @@ protected void onCreate(Bundle savedInstanceState) {
## 更新说明
+#### v1.4.2
+ banner优化更新<感谢 694551594,FeverCombo3,MIkeeJY >
+ * !!!注意!!ImageLoader已从接口改变成抽象类,请调整下代码哦!
+ * ImageLoader中增加ImageView控件创建方法createImageView(),可以满足fresco加载图片时扩展ImageView需求
+ * 修改关于banner刷新时需要第二轮才会更新图片问题(同title更新图片不更新问题),具体看demo
+ * 开放viewpager的setOffscreenPageLimit(int limit)方法
+ * 优化banner在开始0s~20s之间会出现的内存泄漏问题
+ * 优化最后一张到第一张之间滑动卡顿现象
+
#### v1.4.1
bug修改<感谢深圳-放飞,台北-Tom>
* 第一次加载一张图片(不能滑动[正常])-->刷新-->第二次加载多张图片(不能滑动[bug])
diff --git a/app/app.iml b/app/app.iml
index c4ebea3..6969eae 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -65,14 +65,6 @@
-
-
-
-
-
-
-
-
@@ -81,6 +73,14 @@
+
+
+
+
+
+
+
+
@@ -90,6 +90,11 @@
+
+
+
+
+
@@ -105,7 +110,13 @@
+
+
+
+
+
+
@@ -113,6 +124,7 @@
+
diff --git a/app/build.gradle b/app/build.gradle
index bf93735..c45b874 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -25,6 +25,7 @@ dependencies {
compile 'com.android.support:appcompat-v7:23+'
compile 'com.android.support:recyclerview-v7:23+'
compile "com.github.bumptech.glide:glide:3.7.0"
+ compile 'com.facebook.fresco:fresco:0.12.0'
compile project(':banner')
// compile 'com.youth.banner:banner:+'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a65a28e..fe5fe43 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,6 +5,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/com/test/banner/App.java b/app/src/main/java/com/test/banner/App.java
new file mode 100644
index 0000000..4c34b65
--- /dev/null
+++ b/app/src/main/java/com/test/banner/App.java
@@ -0,0 +1,16 @@
+package com.test.banner;
+
+import android.app.Application;
+import android.content.Context;
+
+import com.facebook.drawee.backends.pipeline.Fresco;
+
+
+public class App extends Application {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Fresco.initialize(this);
+
+ }
+}
diff --git a/app/src/main/java/com/test/banner/CustomImageLoader.java b/app/src/main/java/com/test/banner/CustomImageLoader.java
new file mode 100644
index 0000000..1402f87
--- /dev/null
+++ b/app/src/main/java/com/test/banner/CustomImageLoader.java
@@ -0,0 +1,29 @@
+package com.test.banner;
+
+import android.content.Context;
+import android.net.Uri;
+import android.widget.ImageView;
+
+import com.bumptech.glide.Glide;
+import com.facebook.drawee.view.SimpleDraweeView;
+import com.youth.banner.loader.ImageLoader;
+
+
+public class CustomImageLoader extends ImageLoader {
+ @Override
+ public void displayImage(Context context, Object path, ImageView imageView) {
+ //具体方法内容自己去选择,次方法是为了减少banner过多的依赖第三方包,所以将这个权限开放给使用者去选择
+// Glide.with(context).load(path).into(imageView);
+
+ //用fresco加载图片
+ Uri uri = Uri.parse((String) path);
+ imageView.setImageURI(uri);
+
+ }
+ //提供createImageView 方法,方便fresco自定义ImageView
+ @Override
+ public ImageView createImageView(Context context) {
+ SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context);
+ return simpleDraweeView;
+ }
+}
diff --git a/app/src/main/java/com/test/banner/GlideImageLoader.java b/app/src/main/java/com/test/banner/GlideImageLoader.java
deleted file mode 100644
index 9904262..0000000
--- a/app/src/main/java/com/test/banner/GlideImageLoader.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.test.banner;
-
-import android.content.Context;
-import android.widget.ImageView;
-
-import com.bumptech.glide.Glide;
-import com.youth.banner.loader.ImageViewImageLoader;
-
-
-public class GlideImageLoader extends ImageViewImageLoader {
- @Override
- public void displayImage(Context context, Object path, ImageView imageView) {
- //具体方法内容自己去选择,次方法是为了减少banner过多的依赖第三方包,所以将这个权限开放给使用者去选择
- Glide.with(context).load(path).into(imageView);
- }
-}
diff --git a/app/src/main/java/com/test/banner/MainActivity.java b/app/src/main/java/com/test/banner/MainActivity.java
index 8047696..7d60155 100644
--- a/app/src/main/java/com/test/banner/MainActivity.java
+++ b/app/src/main/java/com/test/banner/MainActivity.java
@@ -1,5 +1,6 @@
package com.test.banner;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
@@ -14,6 +15,8 @@
import com.test.banner.common.BaseRecyclerAdapter;
import com.youth.banner.Banner;
+import com.youth.banner.BannerConfig;
+import com.youth.banner.Transformer;
import com.youth.banner.listener.OnBannerClickListener;
import java.util.Arrays;
@@ -29,7 +32,7 @@ public class MainActivity extends AppCompatActivity implements SwipeRefreshLayou
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case REFRESH_COMPLETE:
- images = getResources().getStringArray(R.array.url2);
+ images = getResources().getStringArray(R.array.url4);
banner.setImages(Arrays.asList(images)).start();
mSwipeLayout.setRefreshing(false);
break;
@@ -68,22 +71,22 @@ protected void onCreate(Bundle savedInstanceState) {
*/
//简单使用
- banner.setImages(Arrays.asList(images)).setImageLoader(new GlideImageLoader()).start();
-
- /*//设置banner样式
- banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE);
+ banner.setImages(Arrays.asList(images)).setImageLoader(new CustomImageLoader()).start();
+/*
+ //设置banner样式
+ banner.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE);
//设置图片加载器
- banner.setImageLoader(new GlideImageLoader());
+ banner.setImageLoader(new CustomImageLoader());
//设置图片集合
banner.setImages(Arrays.asList(images));
//设置banner动画效果
- banner.setBannerAnimation(Transformer.DepthPage);
+ banner.setBannerAnimation(Transformer.CubeOut);
//设置标题集合(当banner样式有显示title时)
banner.setBannerTitles(Arrays.asList(titles));
//设置自动轮播,默认为true
banner.isAutoPlay(true);
//设置轮播时间
- banner.setDelayTime(1500);
+ banner.setDelayTime(3000);
//设置指示器位置(当banner模式中有指示器时)
banner.setIndicatorGravity(BannerConfig.CENTER);
//banner设置方法全部调用完毕时最后调用
@@ -92,6 +95,7 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void OnBannerClick(int position) {
Toast.makeText(getApplicationContext(), "点击:" + position, Toast.LENGTH_SHORT).show();
+ Log.e("--",position+"");
}
});
}
diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml
new file mode 100644
index 0000000..1e3f385
--- /dev/null
+++ b/app/src/main/res/layout/activity_test.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/layout/header.xml b/app/src/main/res/layout/header.xml
index 157b323..1ceff69 100644
--- a/app/src/main/res/layout/header.xml
+++ b/app/src/main/res/layout/header.xml
@@ -2,5 +2,9 @@
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ app:image_scale_type="center_crop"
+ app:indicator_drawable_selected="@drawable/selected_radius"
+ app:title_background="#555CB85C"/>
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 173d401..79a4ee7 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -9,15 +9,19 @@
- http://img.zcool.cn/community/01fd2756e142716ac72531cbf8bbbf.jpg
- http://img.zcool.cn/community/0192a557a352ef0000012e7ed104e4.jpg
+
+ - http://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpg
+
+ - http://img.zcool.cn/community/01d28457d621800000018c1bb7877e.jpg
+ - http://img.zcool.cn/community/01ae5656e1427f6ac72531cb72bac5.jpg
+
+
- http://img.zcool.cn/community/01b72057a7e0790000018c1bf4fce0.png
- http://img.zcool.cn/community/01fca557a7f5f90000012e7e9feea8.jpg
- http://img.zcool.cn/community/01996b57a7f6020000018c1bedef97.jpg
- http://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpg
-
- - http://img.zcool.cn/community/01700557a7f42f0000018c1bd6eb23.jpg
-
- 51巅峰钜惠
- 十大星级品牌联盟,全场2折起
diff --git a/banner/banner-banner.iml b/banner/banner-banner.iml
index d4e58f6..b8aea74 100644
--- a/banner/banner-banner.iml
+++ b/banner/banner-banner.iml
@@ -66,14 +66,6 @@
-
-
-
-
-
-
-
-
@@ -82,6 +74,14 @@
+
+
+
+
+
+
+
+
diff --git a/banner/build.gradle b/banner/build.gradle
index 2b4f189..ec3bab7 100644
--- a/banner/build.gradle
+++ b/banner/build.gradle
@@ -1,7 +1,7 @@
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
-version = "1.4.1"
+version = "1.4.2"
android {
compileSdkVersion 23
@@ -10,8 +10,8 @@ android {
defaultConfig {
minSdkVersion 11
targetSdkVersion 23
- versionCode 32
- versionName "1.4.1"
+ versionCode 33
+ versionName version
}
buildTypes {
release {
@@ -19,6 +19,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ lintOptions {
+ abortOnError false
+ }
}
dependencies {
@@ -78,7 +81,7 @@ task javadocJar(type: Jar, dependsOn: javadoc) {
}
artifacts {
- archives javadocJar
+// archives javadocJar
archives sourcesJar
}
diff --git a/banner/src/main/java/com/youth/banner/Banner.java b/banner/src/main/java/com/youth/banner/Banner.java
index b1c0e53..7f0ba86 100644
--- a/banner/src/main/java/com/youth/banner/Banner.java
+++ b/banner/src/main/java/com/youth/banner/Banner.java
@@ -21,7 +21,7 @@
import android.widget.TextView;
import com.youth.banner.listener.OnBannerClickListener;
-import com.youth.banner.loader.ImageLoader;
+import com.youth.banner.loader.ImageLoaderInterface;
import com.youth.banner.view.BannerViewPager;
import java.lang.reflect.Field;
@@ -58,12 +58,13 @@ public class Banner extends FrameLayout implements OnPageChangeListener {
private BannerViewPager viewPager;
private TextView bannerTitle, numIndicatorInside, numIndicator;
private LinearLayout indicator, indicatorInside, titleView;
- private ImageLoader imageLoader;
+ private ImageLoaderInterface imageLoader;
private BannerPagerAdapter adapter;
private OnPageChangeListener mOnPageChangeListener;
private BannerScroller mScroller;
private OnBannerClickListener listener;
- private Handler handler = new Handler();
+ private WeakHandler handler = new WeakHandler();
+
public Banner(Context context) {
this(context, null);
}
@@ -131,7 +132,7 @@ public Banner isAutoPlay(boolean isAutoPlay) {
return this;
}
- public Banner setImageLoader(ImageLoader imageLoader) {
+ public Banner setImageLoader(ImageLoaderInterface imageLoader) {
this.imageLoader = imageLoader;
return this;
}
@@ -163,7 +164,30 @@ public Banner setBannerAnimation(Class extends PageTransformer> transformer) {
}
return this;
}
-
+ /**
+ * Set the number of pages that should be retained to either side of the
+ * current page in the view hierarchy in an idle state. Pages beyond this
+ * limit will be recreated from the adapter when needed.
+ *
+ * @param limit How many pages will be kept offscreen in an idle state.
+ * @return Banner
+ */
+ public Banner setOffscreenPageLimit(int limit){
+ if (viewPager!=null){
+ viewPager.setOffscreenPageLimit(limit);
+ }
+ return this;
+ }
+ /**
+ * Set a {@link PageTransformer} that will be called for each attached page whenever
+ * the scroll position is changed. This allows the application to apply custom property
+ * transformations to each page, overriding the default sliding look and feel.
+ *
+ * @param reverseDrawingOrder true if the supplied PageTransformer requires page views
+ * to be drawn from last to first instead of first to last.
+ * @param transformer PageTransformer that will modify each page's animation properties
+ * @return Banner
+ */
public Banner setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
viewPager.setPageTransformer(reverseDrawingOrder, transformer);
return this;
@@ -316,10 +340,8 @@ private void setData() {
currentItem = 1;
if (adapter == null) {
adapter = new BannerPagerAdapter();
- viewPager.setAdapter(adapter);
- } else {
- adapter.notifyDataSetChanged();
}
+ viewPager.setAdapter(adapter);
viewPager.setFocusable(true);
viewPager.setCurrentItem(1);
viewPager.addOnPageChangeListener(this);
@@ -415,13 +437,22 @@ public void onPageScrollStateChanged(int state) {
}
currentItem = viewPager.getCurrentItem();
switch (state) {
- case 0:
+ case 0://No operation
if (currentItem == 0) {
viewPager.setCurrentItem(count, false);
} else if (currentItem == count + 1) {
viewPager.setCurrentItem(1, false);
}
break;
+ case 1://start Sliding
+ if (currentItem == count + 1) {
+ viewPager.setCurrentItem(1, false);
+ }else if(currentItem == 0){
+ viewPager.setCurrentItem(count, false);
+ }
+ break;
+ case 2://end Sliding
+ break;
}
}
@@ -484,13 +515,4 @@ public void setOnBannerClickListener(OnBannerClickListener listener) {
public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener) {
mOnPageChangeListener = onPageChangeListener;
}
-// public void releaseBanner(){
-// stopAutoPlay();
-// new ArrayList(imageUrls).clear();
-// new ArrayList(titles).clear();
-// imageViews.clear();
-// indicatorImages.clear();
-// viewPager.removeAllViews();
-// adapter=null;
-// }
}
diff --git a/banner/src/main/java/com/youth/banner/WeakHandler.java b/banner/src/main/java/com/youth/banner/WeakHandler.java
new file mode 100644
index 0000000..be676f5
--- /dev/null
+++ b/banner/src/main/java/com/youth/banner/WeakHandler.java
@@ -0,0 +1,477 @@
+package com.youth.banner;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+@SuppressWarnings("unused")
+public class WeakHandler {
+ private final Handler.Callback mCallback; // hard reference to Callback. We need to keep callback in memory
+ private final ExecHandler mExec;
+ private Lock mLock = new ReentrantLock();
+ @SuppressWarnings("ConstantConditions")
+ @VisibleForTesting
+ final ChainedRef mRunnables = new ChainedRef(mLock, null);
+
+ /**
+ * Default constructor associates this handler with the {@link Looper} for the
+ * current thread.
+ *
+ * If this thread does not have a looper, this handler won't be able to receive messages
+ * so an exception is thrown.
+ */
+ public WeakHandler() {
+ mCallback = null;
+ mExec = new ExecHandler();
+ }
+
+ /**
+ * Constructor associates this handler with the {@link Looper} for the
+ * current thread and takes a callback interface in which you can handle
+ * messages.
+ *
+ * If this thread does not have a looper, this handler won't be able to receive messages
+ * so an exception is thrown.
+ *
+ * @param callback The callback interface in which to handle messages, or null.
+ */
+ public WeakHandler(@Nullable Handler.Callback callback) {
+ mCallback = callback; // Hard referencing body
+ mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler
+ }
+
+ /**
+ * Use the provided {@link Looper} instead of the default one.
+ *
+ * @param looper The looper, must not be null.
+ */
+ public WeakHandler(@NonNull Looper looper) {
+ mCallback = null;
+ mExec = new ExecHandler(looper);
+ }
+
+ /**
+ * Use the provided {@link Looper} instead of the default one and take a callback
+ * interface in which to handle messages.
+ *
+ * @param looper The looper, must not be null.
+ * @param callback The callback interface in which to handle messages, or null.
+ */
+ public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) {
+ mCallback = callback;
+ mExec = new ExecHandler(looper, new WeakReference<>(callback));
+ }
+
+ /**
+ * Causes the Runnable r to be added to the message queue.
+ * The runnable will be run on the thread to which this handler is
+ * attached.
+ *
+ * @param r The Runnable that will be executed.
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean post(@NonNull Runnable r) {
+ return mExec.post(wrapRunnable(r));
+ }
+
+ /**
+ * Causes the Runnable r to be added to the message queue, to be run
+ * at a specific time given by uptimeMillis.
+ * The time-base is {@link android.os.SystemClock#uptimeMillis}.
+ * The runnable will be run on the thread to which this handler is attached.
+ *
+ * @param r The Runnable that will be executed.
+ * @param uptimeMillis The absolute time at which the callback should run,
+ * using the {@link android.os.SystemClock#uptimeMillis} time-base.
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the Runnable will be processed -- if
+ * the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ */
+ public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
+ return mExec.postAtTime(wrapRunnable(r), uptimeMillis);
+ }
+
+ /**
+ * Causes the Runnable r to be added to the message queue, to be run
+ * at a specific time given by uptimeMillis.
+ * The time-base is {@link android.os.SystemClock#uptimeMillis}.
+ * The runnable will be run on the thread to which this handler is attached.
+ *
+ * @param r The Runnable that will be executed.
+ * @param uptimeMillis The absolute time at which the callback should run,
+ * using the {@link android.os.SystemClock#uptimeMillis} time-base.
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the Runnable will be processed -- if
+ * the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ *
+ * @see android.os.SystemClock#uptimeMillis
+ */
+ public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
+ return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis);
+ }
+
+ /**
+ * Causes the Runnable r to be added to the message queue, to be run
+ * after the specified amount of time elapses.
+ * The runnable will be run on the thread to which this handler
+ * is attached.
+ *
+ * @param r The Runnable that will be executed.
+ * @param delayMillis The delay (in milliseconds) until the Runnable
+ * will be executed.
+ *
+ * @return Returns true if the Runnable was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the Runnable will be processed --
+ * if the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ */
+ public final boolean postDelayed(Runnable r, long delayMillis) {
+ return mExec.postDelayed(wrapRunnable(r), delayMillis);
+ }
+
+ /**
+ * Posts a message to an object that implements Runnable.
+ * Causes the Runnable r to executed on the next iteration through the
+ * message queue. The runnable will be run on the thread to which this
+ * handler is attached.
+ * This method is only for use in very special circumstances -- it
+ * can easily starve the message queue, cause ordering problems, or have
+ * other unexpected side-effects.
+ *
+ * @param r The Runnable that will be executed.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean postAtFrontOfQueue(Runnable r) {
+ return mExec.postAtFrontOfQueue(wrapRunnable(r));
+ }
+
+ /**
+ * Remove any pending posts of Runnable r that are in the message queue.
+ */
+ public final void removeCallbacks(Runnable r) {
+ final WeakRunnable runnable = mRunnables.remove(r);
+ if (runnable != null) {
+ mExec.removeCallbacks(runnable);
+ }
+ }
+
+ /**
+ * Remove any pending posts of Runnable r with Object
+ * token that are in the message queue. If token is null,
+ * all callbacks will be removed.
+ */
+ public final void removeCallbacks(Runnable r, Object token) {
+ final WeakRunnable runnable = mRunnables.remove(r);
+ if (runnable != null) {
+ mExec.removeCallbacks(runnable, token);
+ }
+ }
+
+ /**
+ * Pushes a message onto the end of the message queue after all pending messages
+ * before the current time. It will be received in callback,
+ * in the thread attached to this handler.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean sendMessage(Message msg) {
+ return mExec.sendMessage(msg);
+ }
+
+ /**
+ * Sends a Message containing only the what value.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean sendEmptyMessage(int what) {
+ return mExec.sendEmptyMessage(what);
+ }
+
+ /**
+ * Sends a Message containing only the what value, to be delivered
+ * after the specified amount of time elapses.
+ * @see #sendMessageDelayed(android.os.Message, long)
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
+ return mExec.sendEmptyMessageDelayed(what, delayMillis);
+ }
+
+ /**
+ * Sends a Message containing only the what value, to be delivered
+ * at a specific time.
+ * @see #sendMessageAtTime(android.os.Message, long)
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
+ return mExec.sendEmptyMessageAtTime(what, uptimeMillis);
+ }
+
+ /**
+ * Enqueue a message into the message queue after all pending messages
+ * before (current time + delayMillis). You will receive it in
+ * callback, in the thread attached to this handler.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the message will be processed -- if
+ * the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ */
+ public final boolean sendMessageDelayed(Message msg, long delayMillis) {
+ return mExec.sendMessageDelayed(msg, delayMillis);
+ }
+
+ /**
+ * Enqueue a message into the message queue after all pending messages
+ * before the absolute time (in milliseconds) uptimeMillis.
+ * The time-base is {@link android.os.SystemClock#uptimeMillis}.
+ * You will receive it in callback, in the thread attached
+ * to this handler.
+ *
+ * @param uptimeMillis The absolute time at which the message should be
+ * delivered, using the
+ * {@link android.os.SystemClock#uptimeMillis} time-base.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting. Note that a
+ * result of true does not mean the message will be processed -- if
+ * the looper is quit before the delivery time of the message
+ * occurs then the message will be dropped.
+ */
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ return mExec.sendMessageAtTime(msg, uptimeMillis);
+ }
+
+ /**
+ * Enqueue a message at the front of the message queue, to be processed on
+ * the next iteration of the message loop. You will receive it in
+ * callback, in the thread attached to this handler.
+ * This method is only for use in very special circumstances -- it
+ * can easily starve the message queue, cause ordering problems, or have
+ * other unexpected side-effects.
+ *
+ * @return Returns true if the message was successfully placed in to the
+ * message queue. Returns false on failure, usually because the
+ * looper processing the message queue is exiting.
+ */
+ public final boolean sendMessageAtFrontOfQueue(Message msg) {
+ return mExec.sendMessageAtFrontOfQueue(msg);
+ }
+
+ /**
+ * Remove any pending posts of messages with code 'what' that are in the
+ * message queue.
+ */
+ public final void removeMessages(int what) {
+ mExec.removeMessages(what);
+ }
+
+ /**
+ * Remove any pending posts of messages with code 'what' and whose obj is
+ * 'object' that are in the message queue. If object is null,
+ * all messages will be removed.
+ */
+ public final void removeMessages(int what, Object object) {
+ mExec.removeMessages(what, object);
+ }
+
+ /**
+ * Remove any pending posts of callbacks and sent messages whose
+ * obj is token. If token is null,
+ * all callbacks and messages will be removed.
+ */
+ public final void removeCallbacksAndMessages(Object token) {
+ mExec.removeCallbacksAndMessages(token);
+ }
+
+ /**
+ * Check if there are any pending posts of messages with code 'what' in
+ * the message queue.
+ */
+ public final boolean hasMessages(int what) {
+ return mExec.hasMessages(what);
+ }
+
+ /**
+ * Check if there are any pending posts of messages with code 'what' and
+ * whose obj is 'object' in the message queue.
+ */
+ public final boolean hasMessages(int what, Object object) {
+ return mExec.hasMessages(what, object);
+ }
+
+ public final Looper getLooper() {
+ return mExec.getLooper();
+ }
+
+ private WeakRunnable wrapRunnable(@NonNull Runnable r) {
+ //noinspection ConstantConditions
+ if (r == null) {
+ throw new NullPointerException("Runnable can't be null");
+ }
+ final ChainedRef hardRef = new ChainedRef(mLock, r);
+ mRunnables.insertAfter(hardRef);
+ return hardRef.wrapper;
+ }
+
+ private static class ExecHandler extends Handler {
+ private final WeakReference mCallback;
+
+ ExecHandler() {
+ mCallback = null;
+ }
+
+ ExecHandler(WeakReference callback) {
+ mCallback = callback;
+ }
+
+ ExecHandler(Looper looper) {
+ super(looper);
+ mCallback = null;
+ }
+
+ ExecHandler(Looper looper, WeakReference callback) {
+ super(looper);
+ mCallback = callback;
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ if (mCallback == null) {
+ return;
+ }
+ final Handler.Callback callback = mCallback.get();
+ if (callback == null) { // Already disposed
+ return;
+ }
+ callback.handleMessage(msg);
+ }
+ }
+
+ static class WeakRunnable implements Runnable {
+ private final WeakReference mDelegate;
+ private final WeakReference mReference;
+
+ WeakRunnable(WeakReference delegate, WeakReference reference) {
+ mDelegate = delegate;
+ mReference = reference;
+ }
+
+ @Override
+ public void run() {
+ final Runnable delegate = mDelegate.get();
+ final ChainedRef reference = mReference.get();
+ if (reference != null) {
+ reference.remove();
+ }
+ if (delegate != null) {
+ delegate.run();
+ }
+ }
+ }
+
+ static class ChainedRef {
+ @Nullable
+ ChainedRef next;
+ @Nullable
+ ChainedRef prev;
+ @NonNull
+ final Runnable runnable;
+ @NonNull
+ final WeakRunnable wrapper;
+
+ @NonNull
+ Lock lock;
+
+ public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) {
+ this.runnable = r;
+ this.lock = lock;
+ this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this));
+ }
+
+ public WeakRunnable remove() {
+ lock.lock();
+ try {
+ if (prev != null) {
+ prev.next = next;
+ }
+ if (next != null) {
+ next.prev = prev;
+ }
+ prev = null;
+ next = null;
+ } finally {
+ lock.unlock();
+ }
+ return wrapper;
+ }
+
+ public void insertAfter(@NonNull ChainedRef candidate) {
+ lock.lock();
+ try {
+ if (this.next != null) {
+ this.next.prev = candidate;
+ }
+
+ candidate.next = this.next;
+ this.next = candidate;
+ candidate.prev = this;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Nullable
+ public WeakRunnable remove(Runnable obj) {
+ lock.lock();
+ try {
+ ChainedRef curr = this.next; // Skipping head
+ while (curr != null) {
+ if (curr.runnable == obj) { // We do comparison exactly how Handler does inside
+ return curr.remove();
+ }
+ curr = curr.next;
+ }
+ } finally {
+ lock.unlock();
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/banner/src/main/java/com/youth/banner/loader/ImageLoader.java b/banner/src/main/java/com/youth/banner/loader/ImageLoader.java
index 311af4e..f153dfb 100644
--- a/banner/src/main/java/com/youth/banner/loader/ImageLoader.java
+++ b/banner/src/main/java/com/youth/banner/loader/ImageLoader.java
@@ -1,14 +1,15 @@
package com.youth.banner.loader;
import android.content.Context;
-import android.view.View;
+import android.widget.ImageView;
-import java.io.Serializable;
+public abstract class ImageLoader implements ImageLoaderInterface {
-public interface ImageLoader extends Serializable {
+ @Override
+ public ImageView createImageView(Context context) {
+ ImageView imageView = new ImageView(context);
+ return imageView;
+ }
- void displayImage(Context context, Object path, T imageView);
-
- T createImageView(Context context);
}
diff --git a/banner/src/main/java/com/youth/banner/loader/ImageLoaderInterface.java b/banner/src/main/java/com/youth/banner/loader/ImageLoaderInterface.java
new file mode 100644
index 0000000..0066531
--- /dev/null
+++ b/banner/src/main/java/com/youth/banner/loader/ImageLoaderInterface.java
@@ -0,0 +1,14 @@
+package com.youth.banner.loader;
+
+import android.content.Context;
+import android.view.View;
+
+import java.io.Serializable;
+
+
+public interface ImageLoaderInterface extends Serializable {
+
+ void displayImage(Context context, Object path, T imageView);
+
+ T createImageView(Context context);
+}
diff --git a/banner/src/main/java/com/youth/banner/loader/ImageViewImageLoader.java b/banner/src/main/java/com/youth/banner/loader/ImageViewImageLoader.java
deleted file mode 100644
index 2246b81..0000000
--- a/banner/src/main/java/com/youth/banner/loader/ImageViewImageLoader.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.youth.banner.loader;
-
-import android.content.Context;
-import android.widget.ImageView;
-
-
-public abstract class ImageViewImageLoader implements ImageLoader {
-
- @Override
- public ImageView createImageView(Context context) {
- ImageView imageView = new ImageView(context);
- return imageView;
- }
-
-}
diff --git a/build.gradle b/build.gradle
index 430c4ba..0c758cf 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,9 +5,9 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.0'
- classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.0'
- classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
+ classpath 'com.android.tools.build:gradle:2.2.2'
+ classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.1'
+ classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}