自定义Toast,解决Android 5.0默认弹窗权限关闭的方案
Switch branches/tags
Nothing to show
Clone or download
Permalink
Failed to load latest commit information.
.idea initial commit Nov 10, 2016
app 调用reset()方法 Nov 10, 2016
gradle/wrapper initial commit Nov 10, 2016
images initial commit Nov 10, 2016
.gitignore initial commit Nov 10, 2016
README.md Update README.md Nov 10, 2016
build.gradle initial commit Nov 10, 2016
gradle.properties initial commit Nov 10, 2016
gradlew initial commit Nov 10, 2016
gradlew.bat initial commit Nov 10, 2016
settings.gradle initial commit Nov 10, 2016

README.md

效果图

图片名称

参考

当关闭通知消息权限后无法显示系统Toast的解决方案

问题分析

Android 5.0以上系统将消息通知默认为关闭,而Toast源码中有如下一段代码:

/**
 * Show the view for the specified duration.
 */
public void show() {
    if (mNextView == null) {
        throw new RuntimeException("setView must have been called");
    }

    INotificationManager service = getService();
    String pkg = mContext.getOpPackageName();
    TN tn = mTN;
    tn.mNextView = mNextView;

    try {
        service.enqueueToast(pkg, tn, mDuration);
    } catch (RemoteException e) {
        // Empty
    }
}

其中调用了INotificationManager类,在默认关闭消息通知的情况下,此类无法调用,因此在Android 5.0以上的系统中,默认是不会显示Toast的,因此使用自定义的Toast实现吐司效果。

主要文件

  • java
    • ToastUtils.java
    • MainActivity.java
    • BaseActivity.java
  • res/layout
    • activity_main.xml
    • toast_layout.xml
  • res/drawable
    • shape_toastutils_bg.xml

核心代码

makeText()方法:

public static ToastUtils makeText(Context context, String message,
                                  int HIDE_DELAY) {
    if (mInstance == null) {
        mInstance = new ToastUtils(context);
    } else {
        // 考虑Activity切换时,Toast依然显示
        if (!mContext.getClass().getName().endsWith(context.getClass().getName())) {
            mInstance = new ToastUtils(context);
        }
    }

    if (HIDE_DELAY == LENGTH_LONG) {
        mInstance.HIDE_DELAY = 2500;
    } else {
        mInstance.HIDE_DELAY = 1500;
    }
    mTextView.setText(message);
    return mInstance;
}
public static ToastUtils makeText(Context context, int resId, int HIDE_DELAY) {
    String mes = "";
    try {
        mes = context.getResources().getString(resId);
    } catch (Resources.NotFoundException e) {
        e.printStackTrace();
    }
    return makeText(context, mes, HIDE_DELAY);
}

show()方法:

public void show() {
    if (isShow) {
        // 若已经显示,则不再次显示
        return;
    }
    isShow = true;
    // 显示动画
    mFadeInAnimation = new AlphaAnimation(0.0f, 1.0f);
    // 消失动画
    mFadeOutAnimation = new AlphaAnimation(1.0f, 0.0f);
    mFadeOutAnimation.setDuration(ANIMATION_DURATION);
    mFadeOutAnimation
            .setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    // 消失动画后更改状态为 未显示
                    isShow = false;
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    // 隐藏布局,不使用remove方法为防止多次创建多个布局
                    mContainer.setVisibility(View.GONE);
                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });
    mContainer.setVisibility(View.VISIBLE);

    mFadeInAnimation.setDuration(ANIMATION_DURATION);

    mContainer.startAnimation(mFadeInAnimation);
    mHandler.postDelayed(mHideRunnable, HIDE_DELAY);
}

调用

ToastUtils调用与系统自带的Toast调用相似,调用如下:

ToastUtils.makeText(context, "消息内容",ToastUtils.LENGTH_SHORT).show();

温馨提示

1.Demo中为了与系统的Toast形成对比,将ToastUtils布局中的marginBottom设置偏大,实际开发中请将marginBottom设置为64dp,布局代码更改如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mbContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    
    android:layout_marginBottom="64dp"
    
    android:gravity="bottom|center"
    android:orientation="vertical"
    android:paddingLeft="50dp"
    android:paddingRight="50dp">

2.为防止Activity切换时ToastUtils单例依然持有上一个Activity的Context,请在BaseActivity的onDestroy()方法中调用reset()方法