现有我们Android使用一个Toast,主要是用来轻量级的提示用户一些小的信息,比如现在弹出5个Toast,但是在Android的历史版本演变中,发现Android7.0系列的版本上,Toast会一个接着一个的弹出,在其他版本上Toast永远只会显示最新的,覆盖掉以前的,基于此,我们为了给用户好一点的体验,希望有一个队列,类似Loop去一直循环消息队列,从而达到自己管理这些Toast,这里分享给各位,水平有限,有不足欢迎评论指出,必定改正!
先分享下我封装的Toast:
功能: 1,支持Toast按照添加顺序一个一个弹出,不会遗漏阻塞某一个Toast
2,支持Toast永远显示最新的内容,不会一次弹出多个给用户体验不好
3,支持自定义Toast布局
4,支持每一个Toast使用自定义布局
5,全局一个Toast,省内存
6,后续再添加新的功能...............
用法:
1,在Application中最简单的初始化方法:
public class MyApplication extends Application {
private static Context mContext;
@Override
public void onCreate() {
super.onCreate();
//初始化操作
FoxToast.init(mContext);
}
}
这是最懒得也是最简单的写法,当然如果你想要让Toast不要一直弹下去,永远显示最新的,初始化的时候你只需要调用:
FoxToast.init(context,0 new DefaultToastInterfaceImpl(context));
如果你感觉这个布局达不到你的要求,那么你完全可以自己写一个布局文件,放到一个View里,再写一个继承自DefaultToastInterface的实现类比如叫:YourInterfaceImpl,具体写法可以参考默认的实现类DefaultToastView,DefaultToastInterfaceImpl,最终:
要是想永远显示最新的Toast这样写:FoxToast.init(context,0 new YourInterfaceImpl(context))
或者:要是想一个一个弹出来这样写:FoxToast.init(context new YourInterfaceImpl(context))
2,添加Toast:
FoxToast.putMessage("这里写上你要提示的内容");
如果你感觉某一个你要弹出来的Toast布局想要变一下,那么你只需要这样做,参考默认的实现类DefaultToastView,DefaultToastInterfaceImpl,比如你写的这个类叫YourInterfaceImpl,你只需要这样写:
FoxToast.putMessage("这里写上你要提示的内容",new YourInterfaceImpl(context));
OK!,就这两步
分享下写的Toast: 1,这个是Toast设置自定义布局和toaast内容的回调接口
public interface ToastViewInterface {
//获取你想要填充的toast的View
View getLayoutView();
//这里将toast返回给你,自己可以去放到TextView上
void setMessage(String msg);
}
2,考虑到有时候比较懒哈哈,所以添加了一个默认的回掉接口实现类,也写了一个默认的布局,当然以一个view来封装的
public class DefaultToastInterfaceImpl implements ToastViewInterface {
DefaultToastView mToastView;
public DefaultToastInterfaceImpl(Context context) {
mToastView = new DefaultToastView(context);
}
@Override
public View getLayoutView() {
return mToastView;
}
@Override
public void setMessage(String msg) {
mToastView.setContent(msg);
}
}
public class DefaultToastView extends LinearLayout {
private View mToastRoot;
public TextView getTextView() {
return mContentTv;
}
private TextView mContentTv;
public DefaultToastView(Context context) {
this(context, null);
}
public DefaultToastView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DefaultToastView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mToastRoot = LayoutInflater.from(context).inflate(R.layout.view_default_toast, this);
mContentTv = (TextView) mToastRoot.findViewById(R.id.tv_toast_message);
}
public View getToastRoot() {
return mToastRoot;
}
public void setContent(String content) {
if (!TextUtils.isEmpty(content)) {
mContentTv.setText(content);
}
}
}
3,Toast消息的载体仿造Handler的Message.
public class ToastMessage {
private String msg;
//一般这里用不到,但是有时候考虑到某一次toast用户想要设置一个不一样的样式
private ToastViewInterface mToastViewInterface;
public ToastMessage(String msg) {
this.msg = msg;
}
public ToastMessage(String msg, ToastViewInterface mToastViewInterface) {
this.msg = msg;
this.mToastViewInterface = mToastViewInterface;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public ToastViewInterface getmToastViewInterface() {
return mToastViewInterface;
}
public void setmToastViewInterface(ToastViewInterface mToastViewInterface) {
this.mToastViewInterface = mToastViewInterface;
}
}
4,最重要就是这个ToastManager类了,调度逻辑都是在这里写的
public class ToastManager {
private static ToastManager mInstance;
private Context mContext;
//消息队列
private List mQueue = new CopyOnWriteArrayList<>();
//回掉接口
private ToastViewInterface mToastViewInterface;
//线程池用来循环读取消息队列
private Executor mExecutor = Executors.newSingleThreadExecutor();
//消息间隔时间,目前亲测不同版本不一样,一般设置为0或者大于2000ms起作用
private static long mIntervalTime = 0;
private volatile Toast mToast;
private long mLastTime;
private final int HANDLE_CODE = 0;
private Handler mMainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case HANDLE_CODE:
handleToasts((ToastMessage) msg.obj);
break;
default:
break;
}
}
};
static ToastManager getInstance() {
if (mInstance == null) {
synchronized (ToastManager.class) {
if (mInstance == null) {
mInstance = new ToastManager();
}
}
}
return mInstance;
}
void init(Context context) {
init(context, new DefaultToastInterfaceImpl(context));
}
void init(Context context, ToastViewInterface in) {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N || Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
init(context, 1000, in);
} else {
init(context, 2050, in);
}
}
void init(Context context, final int intervalTime, ToastViewInterface toastViewInterface) {
this.mContext = context;
this.mIntervalTime = intervalTime;
this.mToastViewInterface = toastViewInterface;
createToast(context);
//循环读取消息
mExecutor.execute(new Runnable() {
@Override
public void run() {
while (true) {
if (!mQueue.isEmpty()) {
if (System.currentTimeMillis() - mLastTime > mIntervalTime) {
Message m = Message.obtain();
m.what = HANDLE_CODE;
m.obj = mQueue.remove(0);
mLastTime = System.currentTimeMillis();
mMainHandler.sendMessageDelayed(m, 0);
}
}
}
}
});
}
private void createToast(Context context) {
if (mToast == null) {
mToast = new Toast(context);
}
if (mToastViewInterface != null) {
mToast.setView(mToastViewInterface.getLayoutView());
}
}
void putMessage(String msg) {
ToastMessage message = new ToastMessage(msg);
mQueue.add(message);
}
void putMessage(String msg, ToastViewInterface toastViewInterface) {
ToastMessage message = new ToastMessage(msg, toastViewInterface);
mQueue.add(message);
}
private void handleToasts(final ToastMessage msg) {
ToastViewInterface customeInterface = msg.getmToastViewInterface();
//自定义的回掉接口存在表示用户想要为这个消息设置不一样的布局
if (customeInterface != null) {
View toastView = customeInterface.getLayoutView();
if (toastView != null) {
mToast.setView(toastView);
}
customeInterface.setMessage(msg.getMsg());
mToast.show();
} else if (mToastViewInterface != null) {
mToast.setView(mToastViewInterface.getLayoutView());
mToastViewInterface.setMessage(msg.getMsg());
mToast.show();
} else {
Toast.makeText(mContext, msg.getMsg(), Toast.LENGTH_SHORT).show();
}
}
void setIntervalTime(long intervalTime) {
this.mIntervalTime = intervalTime;
}
}
5,为了方便调用,我在ToastManager的外面又封装了一层马甲FoxToast,原因是为了以后扩展只需要改ToastManager的具体实现,而作为调用方,只需继续使用FoxToast就行了,改动小一些
public class FoxToast {
public static void init(Context context) {
ToastManager.getInstance().init(context);
}
public static void init(Context context, ToastViewInterface in) {
ToastManager.getInstance().init(context, in);
}
public static void init(Context context, int intervalTime, ToastViewInterface in) {
ToastManager.getInstance().init(context, intervalTime, in);
}
public static void putMessage(String msg) {
ToastManager.getInstance().putMessage(msg);
}
public static void putMessage(String msg, ToastViewInterface toastViewInterface) {
ToastManager.getInstance().putMessage(msg, toastViewInterface);
}
public static void setIntervalTime(long intervalTime) {
ToastManager.getInstance().setIntervalTime(intervalTime);
}
}