Android通用自定义toast工具类(可在主线程和子线程中使用)

简单粗暴,先看效果


首先贴上工具类的代码:

/**
 * 通用(主、子线程)的自定义Toast
 */
public class ToastUtil {

    private static final String TAG = "ToastUtil";
    private static Toast toast;


    //如果只想在主线程中弹出自定义toast,则直接调用此方法即可
    public static void showToast(Context context, String titles, String messages) {
        toastProcess(context, titles, messages);
    }

    //如果想在子线程中和子线程中都能使用,则调用此方法即可(前提是在Activity中,因为runOnUiThread属于Activity中的方法)
    public static void showToast1(final Activity context, final String titles, final String messages) {
        if ("main".equals(Thread.currentThread().getName())) {
            toastProcess(context, titles, messages);
        } else {
            context.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    toastProcess(context, titles, messages);
                }
            });
        }
    }

    /**
     * 自定义toast
     *
     * @param context  上下文对象
     * @param titles   toast 标题
     * @param messages toast内容
     */
    private static void toastProcess(Context context, String titles, String messages) {
        LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        assert layoutInflater != null;
        View view = layoutInflater.inflate(R.layout.custom_toast, null);
        ImageView bg = view.findViewById(R.id.toast_bg);
        TextView title = view.findViewById(R.id.toast_title);
        TextView text = view.findViewById(R.id.toast_content);

        bg.setImageResource(R.mipmap.toast_bg);//toast背景
        title.setText(titles); //toast的标题
        text.setText(messages); //toast内容
        if (toast == null) {
            toast = new Toast(context.getApplicationContext());
        }
        toast.setGravity(Gravity.CENTER, 12, 20);//setGravity用来设置Toast显示的位置,相当于xml中的android:gravity或android:layout_gravity
        toast.setDuration(Toast.LENGTH_LONG);//setDuration方法:设置持续时间,以毫秒为单位。该方法是设置补间动画时间长度的主要方法
        toast.setView(view); //添加视图文件
        toast.show();
    }

}

上述代码中封装了2个toast方法,注释上已经很明白了。

关注2个重点:

(1).自定义toast

(2).可在子线程中使用

(1).自定义toast

上述代码展示了自定义toast的代码逻辑(做了封装toastProcess(....)),下面讲toast的自定义布局也贴出来,custom_toast.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toast_root"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/toast_title"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:background="@android:color/darker_gray"
        android:text="这是一个toast"
        android:textSize="12sp" />

    <RelativeLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_below="@+id/toast_title">

        <ImageView
            android:id="@+id/toast_bg"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@mipmap/toast_bg" />

        <TextView
            android:id="@+id/toast_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:text="我就是那个toast"
            android:textColor="@android:color/background_dark"
            android:textSize="12sp" />

    </RelativeLayout>

</RelativeLayout>

(2).可在子线程中使用

这个也没啥好讲的,代码已经体现出来了。首先 通过Thread.currentThread().getName()方法获取当前线程的线程名称,如果等于"main"的话,则说明在主线程,否则在子线程。这里需要注意的是,所谓的子线程通用,其实也是有限制条件的,那就是传入的上下文对象必须是Activity,因为context.runOnUiThread()方法的context只能在其是Activity中才能使用。这里暂时不考虑service中弹出toast的情况,毕竟toast也是属于用户交互的一种,service主要用于不直接与用户交互的后台,使用toast的情况并不常见。。。

除此之外,我想说的是,如果不作为toast通用工具类来讲的话,完全可以只在ToastUtil中实现自定义toast的部分,而在主程序中通过handler来实现线程间通信,最后只要保证在ui线程中调用ToastUtil.showToast(...)方法即可

贴出最初的MainActivity.java代码:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";

    private Button customToast;
    private Button threadCustomToast;
    private static MyHandler myHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        customToast = findViewById(R.id.custom_toast);
        threadCustomToast = findViewById(R.id.thread_custom_toast);
        customToast.setOnClickListener(this);
        threadCustomToast.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.custom_toast:
                ToastUtil.showToast(MainActivity.this, "这是一个toast", "我就是那个toast");
                break;
            case R.id.thread_custom_toast:
                myHandler = new MyHandler(this);
                myHandler.post(myRunnable);
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandler.removeCallbacks(myRunnable);
        myHandler = null;
    }

    //******************************************************

    /**
     * 创建静态内部类
     */
    private static class MyHandler extends Handler {
        //持有弱引用HandlerActivity,GC回收时会被回收掉.
        private final WeakReference<MainActivity> mActivty;

        MyHandler(MainActivity activity) {
            mActivty = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 0x01:
                    MainActivity activity = mActivty.get();
                    if (activity != null) {
                        //执行业务逻辑
                        String text = (String) msg.obj;
                        ToastUtil.showToast(activity, "这是一个toast", text);
                    }
                    break;
                default:
                    break;
            }

        }
    }

    private Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            //线程中无法使用Toast,需要将Toast发送至主线程中才能使用
            Message msg = new Message();
            msg.what = 0x01;
            msg.obj = "这是线程的toast";
            myHandler.sendMessage(msg);
        }
    };

}

上述代码,仅供读者参考吧,毕竟如果存在多个不同的子线程的话,如此操作还是比较繁琐的,不如工具类来的方便啊。

好啦,到此结束,如果有什么疑问,或者意见或建议,请留言探索。


猜你喜欢

转载自blog.csdn.net/zhangqunshuai/article/details/80413129