必威-必威-欢迎您

必威,必威官网企业自成立以来,以策略先行,经营致胜,管理为本的商,业推广理念,一步一个脚印发展成为同类企业中经营范围最广,在行业内颇具影响力的企业。

等都可以实现定时任务的执行,所以需要要么跳

2019-10-10 21:24 来源:未知

当APP有推送功能时,需要判断当前app在手机中是否开启了允许消息推送,否则即使添加了推送代码仍然收不到通知,所以需要要么跳转至设置界面设置,要么自定义消息通知。

import java.text.SimpleDateFormat;

BinderInternal中的方法,native的,爱莫能助了,并不知道在哪System.load(“cpp”);

/**

*但是可以看注解啊!

*Return the global "context object" of the system.  This is usually

*an implementation of IServiceManager, which you can use to find

*other services.       《=== 菜鸡英语为您翻译:返回给你一个整个系统全局的上下文,这个东东实现了IServiceManager,用这个东东就可以查询你需要的service

*补充: 根据返回值IBinder,可见系统内部也是用的Binder通讯,罗神讲的详细,什么本地服务,代理服务,什么用户空间,系统空间的。

*/

public static final native IBinder getContextObject();

//Binder内的方法

public static IBinder allowBlocking(IBinder binder) {

          try {

                   if (binder instanceof BinderProxy) {

                                  ((BinderProxy) binder).mWarnOnBlocking = false;        《===  要查询的service本身就是一个代理服务ps

                   } else if (binder != null

                                   && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null)  {   《=== 判定自身不是空,还在本地没有

                                  Log.w(TAG, "Unable to allow blocking on interface " + binder);

}

            } catch (RemoteException ignored) {

             }

             return binder;

}

// 猜想这个描述可能就是罗神分析里ProcessState中的fd,文件描述符

public String getInterfaceDescriptor() {

           return mDescriptor;

}

//赋值方法

public void attachInterface(IInterface owner, String descriptor) {

           mOwner = owner;

          mDescriptor = descriptor; //赋值过程暂留2

}

       initAlarm();

1、日志工具类L.java

```

package com.zhy.utils;   

import android.util.Log;   

/** * Log统一管理类 *   *   *   */  

public class L  {       

private L()      {          

/* cannot be instantiated */          

throw new UnsupportedOperationException("cannot be instantiated");      }       

public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化      

private static final String TAG = "way";    // 下面四个是默认tag的函数      

public static void i(String msg)      {          

if (isDebug)              

Log.i(TAG, msg);      

}       

public static void d(String msg)      {          

if (isDebug)              

Log.d(TAG, msg);      }       

public static void e(String msg)      {          

if (isDebug)              

Log.e(TAG, msg);      }       

public static void v(String msg)      {          

if (isDebug)              

Log.v(TAG, msg);      }   // 下面是传入自定义tag的函数      

public static void i(String tag, String msg)      {          

if (isDebug)              Log.i(tag, msg);      }       

public static void d(String tag, String msg)      {          

if (isDebug)              Log.i(tag, msg);      }       

public static void e(String tag, String msg)      {          

if (isDebug)              Log.i(tag, msg);      }      

 public static void v(String tag, String msg)      {          

if (isDebug)              Log.i(tag, msg);      }  } 

```

-

toast.xml文件:

        return null;

INotificationManager由来

private static INotificationManager sService;

static private INotificationManager getService() {

               if (sService != null) {

                           return sService;

                }

                sService =         INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));   《=== 证明了一切,INotificationManager是注册在ServiceManager的一个服务

补充知识如下:

1.android系统是一个多进程的系统,进程之间相互独立

2.进程间通讯方式方法之一 “Binder”, 这里就是使用的Binder

3.弹toast为什么要跨进程通讯?自我理解:比如我需要在远程服务里弹toast,(有大神给答案那就太好了)一定得跨进程

4.binder机制,去看看罗神的博客吧

                return sService;

}

      public void onTick(long millisUntilFinished) {

10、Http相关辅助类 HttpUtils

```

package com.zhy.utils;  

    import java.io.BufferedReader;  

    import java.io.ByteArrayOutputStream;  

    import java.io.IOException;  

    import java.io.InputStream;  

    import java.io.InputStreamReader;  

    import java.io.PrintWriter;  

    import java.net.HttpURLConnection;  

    import java.net.URL;  

    /**

     * Http请求的工具类

     *  

     * @author zhy

     *  

     */  

    public class HttpUtils  

    {  

        private static final int TIMEOUT_IN_MILLIONS = 5000;  

        public interface CallBack  

        {  

            void onRequestComplete(String result);  

        }  

        /**

         * 异步的Get请求

         *  

         * @param urlStr

         * @param callBack

         */  

        public static void doGetAsyn(final String urlStr, final CallBack callBack)  

        {  

            new Thread()  

            {  

                public void run()  

                {  

                    try  

                    {  

                        String result = doGet(urlStr);  

                        if (callBack != null)  

                        {  

                            callBack.onRequestComplete(result);  

                        }  

                    } catch (Exception e)  

                    {  

                        e.printStackTrace();  

                    }  

                };  

            }.start();  

        }  

        /**

         * 异步的Post请求

         * @param urlStr

         * @param params

         * @param callBack

         * @throws Exception

         */  

        public static void doPostAsyn(final String urlStr, final String params,  

                final CallBack callBack) throws Exception  

        {  

            new Thread()  

            {  

                public void run()  

                {  

                    try  

                    {  

                        String result = doPost(urlStr, params);  

                        if (callBack != null)  

                        {  

                            callBack.onRequestComplete(result);  

                        }  

                    } catch (Exception e)  

                    {  

                        e.printStackTrace();  

                    }  

                };  

            }.start();  

        }  

        /**

         * Get请求,获得返回数据

         *  

         * @param urlStr

         * @return

         * @throws Exception

         */  

        public static String doGet(String urlStr)  

        {  

            URL url = null;  

            HttpURLConnection conn = null;  

            InputStream is = null;  

            ByteArrayOutputStream baos = null;  

            try  

            {  

                url = new URL(urlStr);  

                conn = (HttpURLConnection) url.openConnection();  

                conn.setReadTimeout(TIMEOUT_IN_MILLIONS);  

                conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);  

                conn.setRequestMethod("GET");  

                conn.setRequestProperty("accept", "*/*");  

                conn.setRequestProperty("connection", "Keep-Alive");  

                if (conn.getResponseCode() == 200)  

                {  

                    is = conn.getInputStream();  

                    baos = new ByteArrayOutputStream();  

                    int len = -1;  

                    byte[] buf = new byte[128];  

                    while ((len = is.read(buf)) != -1)  

                    {  

                        baos.write(buf, 0, len);  

                    }  

                    baos.flush();  

                    return baos.toString();  

                } else  

                {  

                    throw new RuntimeException(" responseCode is not 200 ... ");  

                }  

            } catch (Exception e)  

            {  

                e.printStackTrace();  

            } finally  

            {  

                try  

                {  

                    if (is != null)  

                        is.close();  

                } catch (IOException e)  

                {  

                }  

                try  

                {  

                    if (baos != null)  

                        baos.close();  

                } catch (IOException e)  

                {  

                }  

                conn.disconnect();  

            }  

            return null ;  

        }  

        /**  

         * 向指定 URL 发送POST方法的请求  

         *  

         * @param url  

         *            发送请求的 URL  

         * @param param  

         *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。  

         * @return 所代表远程资源的响应结果  

         * @throws Exception  

         */  

        public static String doPost(String url, String param)  

        {  

            PrintWriter out = null;  

            BufferedReader in = null;  

            String result = "";  

            try  

            {  

                URL realUrl = new URL(url);  

                // 打开和URL之间的连接  

                HttpURLConnection conn = (HttpURLConnection) realUrl  

                        .openConnection();  

                // 设置通用的请求属性  

                conn.setRequestProperty("accept", "*/*");  

                conn.setRequestProperty("connection", "Keep-Alive");  

                conn.setRequestMethod("POST");  

                conn.setRequestProperty("Content-Type",  

                        "application/x-www-form-urlencoded");  

                conn.setRequestProperty("charset", "utf-8");  

                conn.setUseCaches(false);  

                // 发送POST请求必须设置如下两行  

                conn.setDoOutput(true);  

                conn.setDoInput(true);  

                conn.setReadTimeout(TIMEOUT_IN_MILLIONS);  

                conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);  

                if (param != null && !param.trim().equals(""))  

                {  

                    // 获取URLConnection对象对应的输出流  

                    out = new PrintWriter(conn.getOutputStream());  

                    // 发送请求参数  

                    out.print(param);  

                    // flush输出流的缓冲  

                    out.flush();  

                }  

                // 定义BufferedReader输入流来读取URL的响应  

                in = new BufferedReader(  

                        new InputStreamReader(conn.getInputStream()));  

                String line;  

                while ((line = in.readLine()) != null)  

                {  

                    result += line;  

                }  

            } catch (Exception e)  

            {  

                e.printStackTrace();  

            }  

            // 使用finally块来关闭输出流、输入流  

            finally  

            {  

                try  

                {  

                    if (out != null)  

                    {  

                        out.close();  

                    }  

                    if (in != null)  

                    {  

                        in.close();  

                    }  

                } catch (IOException ex)  

                {  

                    ex.printStackTrace();  

                }  

            }  

            return result;  

        }  

    }

```

如果有错误欢迎留言,共同改进优化,后续会更新更多的工具类

使用方法:

            Config.interval = interval;

前言:toast再常见不过,但是一个小小的toast居然内有乾坤,呵(w)呵(t)呵(f)

源码如下:

public class Toast {

//toast显示时间    注释控制了下输入内容

@IntDef({LENGTH_SHORT, LENGTH_LONG})

@Retention(RetentionPolicy.SOURCE)

public @interface Duration {}

public static final int LENGTH_SHORT = 0;

public static final int LENGTH_LONG = 1;

public void setDuration(@Duration int duration) { 《=== 注释作用处  不按套路编译报错 Must be one of: Toast.LENGTH_SHORT, Toast.LENGTH_LONG

          mDuration = duration;

          mTN.mDuration = duration;

}

@Duration

public int getDuration() {

         return mDuration;

}

//通常用法中乾坤Toast.makeText(context, "hello world", Toast.LENGTH_SHORT).show()

public static Toast makeText(Context context, CharSequence text, @Duration int duration) {

         return makeText(context, null, text, duration);

}

public static Toast makeText(@NonNull Context context, @Nullable Looper looper,

                              @NonNull CharSequence text, @Duration int duration) {

          Toast result = new Toast(context, looper);   《=== 完全就是一个有参构造的简单类,自身本不是什么view,Window(画外音:显示出来那个玩意一定是wm.add进入的)

          LayoutInflater inflate=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

          View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);    《=== 布局,设置文本什么的

          TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);

           tv.setText(text);

           result.mNextView = v;                     《=== 存为全局为了下面TN使用

           result.mDuration = duration;

           return result;

}

public Toast(Context context) {

           this(context, null);

}

public Toast(@NonNull Context context, @Nullable Looper looper) {

            mContext = context;

            mTN = new TN(context.getPackageName(), looper);     《=== 伏笔(TN重要的东东,后边分析)

            mTN.mY = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.toast_y_offset);

           mTN.mGravity = context.getResources().getInteger( com.android.internal.R.integer.config_toastDefaultGravity);

}


public void show() {

           if (mNextView == null) {

                         throw new RuntimeException("setView must have been called");

           }

           INotificationManager service = getService();    《=== 好戏登场

《==== 经过分析 ok INotificationManager这货终于知道了,就是一个注册的远程服务,我们拿到一个他的代理(可以调用它的实现方法)

           String pkg = mContext.getOpPackageName();

           TN tn = mTN;

           tn.mNextView = mNextView;

            try {

                      service.enqueueToast(pkg, tn, mDuration);              《=== toast任务,加入window,并加入到toast管理队列

             } catch (RemoteException e) {

                       // Empty

             }

  }

}

      

新建Toast.java

    Handler msgHandler = new Handler() {

INotificationManager内部实现

//1.INotificationManager.aidl

void enqueueToast(String pkg, ITransientNotification callback, int duration);

//2.实现NotificationManagerService

@Override

public void enqueueToast(String pkg, ITransientNotification callback, int duration)

{

==========删除日志和安检

final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));

final boolean isPackageSuspended =

isPackageSuspendedForUser(pkg, Binder.getCallingUid());           《=== 猜测最终返回当前应用是否正在运行吧

if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&

(!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())

|| isPackageSuspended)) {                                 《=== 日志不看,这个判断就是如果当前这个toast请求,既不是远程代理,又不是系统,还不是应用交互期间,那你弹个毛

==== 多所一句,远程代理,远程服务弹toast

return;

}

synchronized (mToastQueue) {                                              《=== 集合操作同步锁控制

int callingPid = Binder.getCallingPid();

long callingId = Binder.clearCallingIdentity();

try {

ToastRecord record;

int index = indexOfToastLocked(pkg, callback);

if (index >= 0) {

record = mToastQueue.get(index);

record.update(duration);                                       《=== 队列中已经存在,更新

} else {

if (!isSystemToast) {                                          《=== toast数量限制,除了系统toast,防止内存泄露

int count = 0;

final int N = mToastQueue.size();

for (int i=0; i

final ToastRecord r = mToastQueue.get(i);

if (r.pkg.equals(pkg)) {

count++;

if (count >= MAX_PACKAGE_NOTIFICATIONS) {         《=== 我擦一个应用才能弹50个吐司?

Slog.e(TAG, "Package has already posted " + count

+" toasts. Not showing more. Package=" + pkg);

return;

}}}}

Binder token = new Binder();

mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);    《=== 加入window

record = new ToastRecord(callingPid, pkg, callback, duration, token);

mToastQueue.add(record);                                                      《=== 加入管理队列

index = mToastQueue.size() - 1;

keepProcessAliveIfNeededLocked(callingPid);

}

// If it's at index 0, it's the current toast.  It doesn't matter if it's

// new or just been updated.  Call back and tell it to show itself.

// If the callback fails, this will remove it from the list, so don't

// assume that it's valid after this.

if (index == 0) {

showNextToastLocked();                                                        《=== fuck 终于找到show的逻辑了

}

} finally {

Binder.restoreCallingIdentity(callingId);

}}}

// 检查是不是系统toast

protected boolean isCallerSystemOrPhone() {

return isUidSystemOrPhone(Binder.getCallingUid());     《=== 其实这个地方就证明Binder跨进程,它内部保存了进程id,包名等等信息,用来操作和判断

}

protected boolean isUidSystemOrPhone(int uid) {

final int appid = UserHandle.getAppId(uid);

return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);  《=== 系统uid 1000, phoneid 1001 ,证明0~1000都是系统应用

}

//检测当前包是否正在使用

private boolean isPackageSuspendedForUser(String pkg, int uid) {

int userId = UserHandle.getUserId(uid);

try {

return mPackageManager.isPackageSuspendedForUser(pkg, userId);        《=== 实现过程

} catch (RemoteException re) {

throw new SecurityException("Could not talk to package manager service");

} catch (IllegalArgumentException ex) {

// Package not found.

return false;

}

}

//interface IPackageManager.aidl  《=== 也是binder方式,要不我们放过它实现的过程?按照谷歌的性格应该有个PackageManagerService是实现类,如果查不到就放过他

//好吧一点惊喜都不给我PackageManagerService

@Override

public boolean isPackageSuspendedForUser(String packageName, int userId) {

final int callingUid = Binder.getCallingUid();

enforceCrossUserPermission(callingUid, userId,

true /* requireFullPermission */, false /* checkShell */,

"isPackageSuspendedForUser for user " + userId);

synchronized (mPackages) {

final PackageSetting ps = mSettings.mPackages.get(packageName);

if (ps == null || filterAppAccessLPr(ps, callingUid, userId)) {

throw new IllegalArgumentException("Unknown target package: " + packageName);

}

return ps.getSuspended(userId);

}

}

//。。。找啊找啊找朋友

//PackageSetting extends PackageSettingBase.getSuspended()

boolean getSuspended(int userId) {

return readUserState(userId).suspended;          《==== 所以这个就是包用户状态的一个属性 悬浮,暂停

}

public PackageUserState readUserState(int userId) {

PackageUserState state = userState.get(userId);

if (state == null) {

return DEFAULT_USER_STATE;                   《=== 默认false

}

state.categoryHint = categoryHint;

return state;

}

private final SparseArray userState = new SparseArray();

//.....跑偏的太厉害了,PackageUserState这个玩意源码先暂留3, 直译:包用户状态

//Toast队列,记录Toast

final ArrayList mToastQueue = new ArrayList();

//show的逻辑

@GuardedBy("mToastQueue")

void showNextToastLocked() {

ToastRecord record = mToastQueue.get(0);

while (record != null) {

if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);

try {

record.callback.show(record.token);              《====  show出来,第二场好戏

scheduleTimeoutLocked(record);

return;

} catch (RemoteException e) {

Slog.w(TAG, "Object died trying to show notification " + record.callback

+" in package " + record.pkg);

// remove it from the list and let the process die

int index = mToastQueue.indexOf(record);

if (index >= 0) {

mToastQueue.remove(index);                   《===  异常移除本次toast

}

keepProcessAliveIfNeededLocked(record.pid);

if (mToastQueue.size() > 0) {

record = mToastQueue.get(0);                 《===  上顶一个toast任务

} else {

record = null;                               《===  退出显示

}

}

}

}

/*** 好累啊,终于到了第二场好戏,就是前面暂留的1 TN*/

//其实经过上面分析,TN的快感就少了很多

//extends ITransientNotification.Stub  《===  Binder通讯,一定会有一个ITransientNotification.aidl文件外露接口,实现就在这里

//ITransientNotification.aidl中定义

void show(IBinder windowToken);

void hide();

//实现,发现其实cancel不是复写

private static class TN extends ITransientNotification.Stub {

private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();

private static final int SHOW = 0;

private static final int HIDE = 1;

private static final int CANCEL = 2;

final Handler mHandler;

int mGravity;

int mX, mY;

float mHorizontalMargin;

float mVerticalMargin;

View mView;

View mNextView;

int mDuration;

WindowManager mWM;

String mPackageName;

static final long SHORT_DURATION_TIMEOUT = 4000;

static final long LONG_DURATION_TIMEOUT = 7000;

TN(String packageName, @Nullable Looper looper) {

// XXX This should be changed to use a Dialog, with a Theme.Toast

// defined that sets up the layout params appropriately.

final WindowManager.LayoutParams params = mParams;

params.height = WindowManager.LayoutParams.WRAP_CONTENT;

params.width = WindowManager.LayoutParams.WRAP_CONTENT;

params.format = PixelFormat.TRANSLUCENT;

params.windowAnimations = com.android.internal.R.style.Animation_Toast;

params.type = WindowManager.LayoutParams.TYPE_TOAST;

params.setTitle("Toast");

params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON

| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

mPackageName = packageName;

if (looper == null) {

// Use Looper.myLooper() if looper is not specified.

looper = Looper.myLooper();

if (looper == null) {

throw new RuntimeException(

"Can't toast on a thread that has not called Looper.prepare()");

}

}

mHandler = new Handler(looper, null) {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case SHOW: {

IBinder token = (IBinder) msg.obj;

handleShow(token);

break;

}

case HIDE: {

handleHide();

// Don't do this in handleHide() because it is also invoked by

// handleShow()

mNextView = null;

break;

}

case CANCEL: {

handleHide();

// Don't do this in handleHide() because it is also invoked by

// handleShow()

mNextView = null;

try {

getService().cancelToast(mPackageName, TN.this);

} catch (RemoteException e) {

}

break;

}

}

}

};

}

/**

*schedule handleShow into the right thread

*/

@Override

public void show(IBinder windowToken) {

if (localLOGV) Log.v(TAG, "SHOW: " + this);

mHandler.obtainMessage(SHOW, windowToken).sendToTarget();

}

/**

*schedule handleHide into the right thread

*/

@Override

public void hide() {

if (localLOGV) Log.v(TAG, "HIDE: " + this);

mHandler.obtainMessage(HIDE).sendToTarget();

}

public void cancel() {

if (localLOGV) Log.v(TAG, "CANCEL: " + this);

mHandler.obtainMessage(CANCEL).sendToTarget();

}

public void handleShow(IBinder windowToken) {

if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView

+" mNextView=" + mNextView);

// If a cancel/hide is pending - no need to show - at this point

// the window token is already invalid and no need to do any work.

if (mHandler.hasMessages(CANCEL) || mHandler.hasMessages(HIDE)) {

return;

}

if (mView != mNextView) {

// remove the old view if necessary

handleHide();

mView = mNextView;

Context context = mView.getContext().getApplicationContext();

String packageName = mView.getContext().getOpPackageName();

if (context == null) {

context = mView.getContext();

}

mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

// We can resolve the Gravity here by using the Locale for getting

// the layout direction

final Configuration config = mView.getContext().getResources().getConfiguration();

final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());

mParams.gravity = gravity;

if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {

mParams.horizontalWeight = 1.0f;

}

if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {

mParams.verticalWeight = 1.0f;

}

mParams.x = mX;

mParams.y = mY;

mParams.verticalMargin = mVerticalMargin;

mParams.horizontalMargin = mHorizontalMargin;

mParams.packageName = packageName;

mParams.hideTimeoutMilliseconds = mDuration ==

Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;

mParams.token = windowToken;

if (mView.getParent() != null) {

if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);

mWM.removeView(mView);

}

if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);

// Since the notification manager service cancels the token right

// after it notifies us to cancel the toast there is an inherent

// race and we may attempt to add a window after the token has been

// invalidated. Let us hedge against that.

try {

mWM.addView(mView, mParams);                《===   他强任他强,清风拂山岗  最终还是WindowManager.addView

trySendAccessibilityEvent();

} catch (WindowManager.BadTokenException e) {

/* ignore */

}

}

}

private void trySendAccessibilityEvent() {

AccessibilityManager accessibilityManager =

AccessibilityManager.getInstance(mView.getContext());

if (!accessibilityManager.isEnabled()) {

return;

}

// treat toasts as notifications since they are used to

// announce a transient piece of information to the user

AccessibilityEvent event = AccessibilityEvent.obtain(

AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);

event.setClassName(getClass().getName());

event.setPackageName(mView.getContext().getPackageName());

mView.dispatchPopulateAccessibilityEvent(event);

accessibilityManager.sendAccessibilityEvent(event);

}

public void handleHide() {

if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);

if (mView != null) {

// note: checking parent() just to make sure the view has

// been added...  i have seen cases where we get here when

// the view isn't yet added, so let's try not to crash.

if (mView.getParent() != null) {

if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);

mWM.removeViewImmediate(mView);

}

mView = null;

}

}

}

//剩下的只要自定义过toast都知道,我就不胡说了~

源码贴不上了,删了,迷之缩进怎么解!!!

小结:

1.toast本质是inflate了一个View(有默认,也可以设置),然后通过WindowManager.addView()进行显示

2.由系统中NotificationManagerService管理和维护这一个ToastQueue(toast队列)

3.NotificationManagerService又通过Toast.TN,轮循回调,执行show的操作(即WindowManager.addView())

4.toast是有数量限制的

至此还剩三个遗留:

1.wm.addView流程

2.descriptor描述怎么来的

3.packageUserState分析

下回分解吧

   }

4、单位转换类 DensityUtils

```

 package com.zhy.utils;  

    import android.content.Context;  

    import android.util.TypedValue;  

    /**

     * 常用单位转换的辅助类

     *  

     *  

     *  

     */  

    public class DensityUtils  

    {  

        private DensityUtils()  

        {  

            /** cannot be instantiated **/  

            throw new UnsupportedOperationException("cannot be instantiated");  

        }  

        /**

         * dp转px

         *  

         * @param context

         * @param val

         * @return

         */

         public static int dp2px(Context context, float dpVal)  

            {  

                return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  

                        dpVal, context.getResources().getDisplayMetrics());  

            }  

            /**

             * sp转px

             *  

             * @param context

             * @param val

             * @return

             */  

            public static int sp2px(Context context, float spVal)  

            {  

                return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,  

                        spVal, context.getResources().getDisplayMetrics());  

            }  

            /**

             * px转dp

             *  

             * @param context

             * @param pxVal

             * @return

             */  

            public static float px2dp(Context context, float pxVal)  

            {  

                final float scale = context.getResources().getDisplayMetrics().density;  

                return (pxVal / scale);  

            }

                /**

                 * px转sp

                 *  

                 * @param fontScale

                 * @param pxVal

                 * @return

                 */  

                public static float px2sp(Context context, float pxVal)  

                {  

                    return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);  

                }  

            }

```

方法二:自定义消息通知

        Date now = new Date();

ServiceManager中的方法,c的过来,方便理解

public static IBinder getService(String name) {

           try {

                    IBinder service = sCache.get(name);  《=== sCache是一个hashmap private static HashMap sCache = new HashMap();

                   if (service != null) {

                            return service;

                   } else {

                            return Binder.allowBlocking(getIServiceManager().getService(name));   《=== 内存没有,去本地取 (从下面的分析看完,返回上面流程继续)

                    }

             } catch (RemoteException e) {

                    Log.e(TAG, "error in getService", e);

             }

            return null;

}

private static IServiceManager getIServiceManager() {

             if (sServiceManager != null) {

                       return sServiceManager;

              }

              // Find the service manager

              sServiceManager = ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));   《=== 经过本地一些列查询,反正返回了这个服务

              return sServiceManager;

}

     break;

2、Toast统一管理类 

-

···

package com.zhy.utils;   

import android.content.Context;  

import android.widget.Toast;   /** * Toast统一管理类 *   */  public class T  {       

private T()      {         

 /** cannot be instantiated**/          

throw new UnsupportedOperationException("cannot be instantiated");      }       

public static boolean isShow = true;   /**      * 短时间显示Toast      *       * @param context      * @param message      */      

public static void showShort(Context context, CharSequence message)      {          

if (isShow)              

Toast.makeText(context, message, Toast.LENGTH_SHORT).show();      }       /**      * 短时间显示Toast      *       * @param context      * @param message      */      

public static void showShort(Context context, int message)      {          

if (isShow)              

Toast.makeText(context, message, Toast.LENGTH_SHORT).show();      }      /**      * 长时间显示Toast      *       * @param context      * @param message      */      

public static void showLong(Context context, CharSequence message)      {          

if (isShow)              

Toast.makeText(context, message, Toast.LENGTH_LONG).show();      }       /**      * 长时间显示Toast      *       * @param context      * @param message      */      

public static void showLong(Context context, int message)      {          

if (isShow)              

Toast.makeText(context, message, Toast.LENGTH_LONG).show();      }      /**      * 自定义显示Toast时间      *       * @param context      * @param message      * @param duration      */      

public static void show(Context context, CharSequence message, int duration)      {          

if (isShow)              

Toast.makeText(context, message, duration).show();      }       /**      * 自定义显示Toast时间      *       * @param context      * @param message      * @param duration      */      

public static void show(Context context, int message, int duration)      {          

if (isShow)              

Toast.makeText(context, message, duration).show();      }   }

-

```

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andro android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/toast_bg"> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_vertical" android:background="@color/transparent" android:textSize="18sp" android:padding="7dp" android:textColor="@color/white"> </TextView> </LinearLayout>

                params.x = (int) event.getRawX();

      ca.set(Calendar.SECOND,0);

9、网络相关辅助类 NetUtils

```

 package com.zhy.utils;  

    import android.app.Activity;  

    import android.content.ComponentName;  

    import android.content.Context;  

    import android.content.Intent;  

    import android.net.ConnectivityManager;  

    import android.net.NetworkInfo;  

    /**

     * 跟网络相关的工具类

     *  

     *  

     *  

     */  

    public class NetUtils  

    {  

        private NetUtils()  

        {  

            /** cannot be instantiated **/  

            throw new UnsupportedOperationException("cannot be instantiated");  

        }  

        /**

         * 判断网络是否连接

         *  

         * @param context

         * @return

         */  

        public static boolean isConnected(Context context)  

        {  

            ConnectivityManager connectivity = (ConnectivityManager) context  

                    .getSystemService(Context.CONNECTIVITY_SERVICE);  

            if (null != connectivity)  

            {  

                NetworkInfo info = connectivity.getActiveNetworkInfo();  

                if (null != info && info.isConnected())  

                {  

                    if (info.getState() == NetworkInfo.State.CONNECTED)  

                    {  

                        return true;  

                    }  

                }  

            }  

            return false;  

        }  

        /**

         * 判断是否是wifi连接

         */  

        public static boolean isWifi(Context context)  

        {  

            ConnectivityManager cm = (ConnectivityManager) context  

                    .getSystemService(Context.CONNECTIVITY_SERVICE);  

            if (cm == null)  

                return false;  

            return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI;  

        }  

        /**

         * 打开网络设置界面

         */  

        public static void openSetting(Activity activity)  

        {  

            Intent intent = new Intent("/");  

            ComponentName cm = new ComponentName("com.android.settings",  

                    "com.android.settings.WirelessSettings");  

            intent.setComponent(cm);  

            intent.setAction("android.intent.action.VIEW");  

            activity.startActivityForResult(intent, 0);  

        }  

    }

```

前言

        }

     case R.id.btn_Cancel:

7、App相关辅助类

```

 package com.zhy.utils;  

    import android.content.Context;  

    import android.content.pm.PackageInfo;  

    import android.content.pm.PackageManager;  

    import android.content.pm.PackageManager.NameNotFoundException;  

    /**

     * 跟App相关的辅助类

     *  

     *  

     *  

     */  

    public class AppUtils  

    {  

        private AppUtils()  

        {  

            /**cannot be instantiated **/  

            throw new UnsupportedOperationException("cannot be instantiated");  

        }  

        /**

         * 获取应用程序名称

         */  

        public static String getAppName(Context context)  

        {  

            try  

            {  

                PackageManager packageManager = context.getPackageManager();  

                PackageInfo packageInfo = packageManager.getPackageInfo(  

                        context.getPackageName(), 0);  

                int labelRes = packageInfo.applicationInfo.labelRes;  

                return context.getResources().getString(labelRes);  

            } catch (NameNotFoundException e)  

            {  

                e.printStackTrace();  

            }  

            return null;  

        }  

        /**

         * [获取应用程序版本名称信息]

         *  

         * @param context

         * @return 当前应用的版本名称

         */  

        public static String getVersionName(Context context)  

        {  

            try  

            {  

                PackageManager packageManager = context.getPackageManager();  

                PackageInfo packageInfo = packageManager.getPackageInfo(  

                        context.getPackageName(), 0);  

                return packageInfo.versionName;  

            } catch (NameNotFoundException e)  

            {  

                e.printStackTrace();  

            }  

            return null;  

        }  

    }

```

package com.php.project.notificationsetutildemo.utils; import android.app.AppOpsManager;import android.content.Context;import android.content.Intent;import android.content.pm.ApplicationInfo;import android.net.Uri;import android.os.Build;import android.support.annotation.RequiresApi;import android.support.v4.app.NotificationManagerCompat; import java.lang.reflect.Field;import java.lang.reflect.Method; /** * Created by peihp * Used 判断是否开启消息通知,没有开启的话跳转到手机系统设置界面 */public class NotificationSetUtil { //判断是否需要打开设置界面 @RequiresApi(api = Build.VERSION_CODES.KITKAT) public static void OpenNotificationSetting(Context context, OnNextLitener mOnNextLitener) { if (!isNotificationEnabled { gotoSet; } else { if (mOnNextLitener != null) { mOnNextLitener.onNext(); } } } //判断该app是否打开了通知 /** * 可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限。NotificationManagerCompat 在 android.support.v4.app包中,是API 22.1.0 中加入的。而 areNotificationsEnabled()则是在 API 24.1.0之后加入的。 * areNotificationsEnabled 只对 API 19 及以上版本有效,低于API 19 会一直返回true * */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) public static boolean isNotificationEnabled(Context context) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from; boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled(); return areNotificationsEnabled; } String CHECK_OP_NO_THROW = "checkOpNoThrow"; String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"; AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); ApplicationInfo appInfo = context.getApplicationInfo(); String pkg = context.getApplicationContext().getPackageName(); int uid = appInfo.uid; Class appOpsClass = null; /* Context.APP_OPS_MANAGER */ try { appOpsClass = Class.forName(AppOpsManager.class.getName; Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class); Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION); int value = opPostNotificationValue.get(Integer.class); return checkOpNoThrowMethod.invoke(mAppOps, value, uid, pkg) == AppOpsManager.MODE_ALLOWED); } catch (Exception e) { e.printStackTrace(); } return false; } //打开手机设置页面 /** * 假设没有开启通知权限,点击之后就需要跳转到 APP的通知设置界面,对应的Action是:Settings.ACTION_APP_NOTIFICATION_SETTINGS, 这个Action是 API 26 后增加的 * 如果在部分手机中无法精确的跳转到 APP对应的通知设置界面,那么我们就考虑直接跳转到 APP信息界面,对应的Action是:Settings.ACTION_APPLICATION_DETAILS_SETTINGS*/ private static void gotoSet(Context context) { Intent intent = new Intent(); if (Build.VERSION.SDK_INT >= 26) { // android 8.0引导 intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); intent.putExtra("android.provider.extra.APP_PACKAGE", context.getPackageName; } else if (Build.VERSION.SDK_INT >= 21) { // android 5.0-7.0 intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); intent.putExtra("app_package", context.getPackageName; intent.putExtra("app_uid", context.getApplicationInfo; } else { // 其他 intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); intent.setData(Uri.fromParts("package", context.getPackageName; } intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity; } /*=====================添加Listener回调================================*/ public interface OnNextLitener { /** * 不需要设置通知的下一步 */ void onNext(); } private OnNextLitener mOnNextLitener; public void setOnNextLitener(OnNextLitener mOnNextLitener) { this.mOnNextLitener = mOnNextLitener; }}

        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSSZ");

    //倒计时结束执行定时的任务 

6、屏幕相关辅助类 ScreenUtils

```

 package com.zhy.utils;  

    import android.app.Activity;  

    import android.content.Context;  

    import android.graphics.Bitmap;  

    import android.graphics.Rect;  

    import android.util.DisplayMetrics;  

    import android.view.View;  

    import android.view.WindowManager;  

    /**

     * 获得屏幕相关的辅助类

     *  

     *  

     *  

     */  

    public class ScreenUtils  

    {  

        private ScreenUtils()  

        {  

            /** cannot be instantiated **/  

            throw new UnsupportedOperationException("cannot be instantiated");  

        }  

        /**

         * 获得屏幕高度

         *  

         * @param context

         * @return

         */  

        public static int getScreenWidth(Context context)  

        {  

            WindowManager wm = (WindowManager) context  

                    .getSystemService(Context.WINDOW_SERVICE);  

            DisplayMetrics outMetrics = new DisplayMetrics();  

            wm.getDefaultDisplay().getMetrics(outMetrics);  

            return outMetrics.widthPixels;  

        }  

        /**

         * 获得屏幕宽度

         *  

         * @param context

         * @return

         */  

        public static int getScreenHeight(Context context)  

        {  

            WindowManager wm = (WindowManager) context  

                    .getSystemService(Context.WINDOW_SERVICE);  

            DisplayMetrics outMetrics = new DisplayMetrics();  

            wm.getDefaultDisplay().getMetrics(outMetrics);  

            return outMetrics.heightPixels;  

        }  

        /**

         * 获得状态栏的高度

         *  

         * @param context

         * @return

         */  

        public static int getStatusHeight(Context context)  

        {  

            int statusHeight = -1;  

            try  

            {  

                Class clazz = Class.forName("com.android.internal.R$dimen");  

                Object object = clazz.newInstance();  

                int height = Integer.parseInt(clazz.getField("status_bar_height")  

                        .get(object).toString());  

                statusHeight = context.getResources().getDimensionPixelSize(height);  

            } catch (Exception e)  

            {  

                e.printStackTrace();  

            }  

            return statusHeight;  

        }  

        /**

         * 获取当前屏幕截图,包含状态栏

         *  

         * @param activity

         * @return

         */  

        public static Bitmap snapShotWithStatusBar(Activity activity)  

        {  

            View view = activity.getWindow().getDecorView();  

            view.setDrawingCacheEnabled(true);  

            view.buildDrawingCache();  

            Bitmap bmp = view.getDrawingCache();  

            int width = getScreenWidth(activity);  

            int height = getScreenHeight(activity);  

            Bitmap bp = null;  

            bp = Bitmap.createBitmap(bmp, 0, 0, width, height);  

            view.destroyDrawingCache();  

            return bp;  

        }  

        /**

         * 获取当前屏幕截图,不包含状态栏

         *  

         * @param activity

         * @return

         */  

        public static Bitmap snapShotWithoutStatusBar(Activity activity)  

        {  

            View view = activity.getWindow().getDecorView();  

            view.setDrawingCacheEnabled(true);  

            view.buildDrawingCache();  

            Bitmap bmp = view.getDrawingCache();  

            Rect frame = new Rect();  

            activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  

            int statusBarHeight = frame.top;  

            int width = getScreenWidth(activity);  

            int height = getScreenHeight(activity);  

            Bitmap bp = null;  

            bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height  

                    - statusBarHeight);  

            view.destroyDrawingCache();  

            return bp;  

        }  

    }

```

方法一:跳转到应用程序设置界面

        Intent startIntent = getIntent();

import android.content.Intent;

3、SharedPreferences封装类SPUtils

```

package com.zhy.utils;  

import java.lang.reflect.InvocationTargetException;  

import java.lang.reflect.Method;  

import java.util.Map;  

import android.content.Context;  

import android.content.SharedPreferences;  

public class SPUtils  

{  

    /**

     * 保存在手机里面的文件名

     */  

    public static final String FILE_NAME = "share_data";  

    /**

     * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法

     *  

     * @param context

     * @param key

     * @param object

     */  

    public static void put(Context context, String key, Object object)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        SharedPreferences.Editor editor = sp.edit();  

        if (object instanceof String)  

        {  

            editor.putString(key, (String) object);  

        } else if (object instanceof Integer)  

        {  

            editor.putInt(key, (Integer) object);  

        } else if (object instanceof Boolean)  

        {  

            editor.putBoolean(key, (Boolean) object);  

        } else if (object instanceof Float)  

        {  

            editor.putFloat(key, (Float) object);  

        } else if (object instanceof Long)  

        {  

            editor.putLong(key, (Long) object);  

        } else  

        {  

            editor.putString(key, object.toString());  

        }  

        SharedPreferencesCompat.apply(editor);  

    }  

    /**

     * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值

     *  

     * @param context

     * @param key

     * @param defaultObject

     * @return

     */  

    public static Object get(Context context, String key, Object defaultObject)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        if (defaultObject instanceof String)  

        {  

            return sp.getString(key, (String) defaultObject);  

        } else if (defaultObject instanceof Integer)  

        {  

            return sp.getInt(key, (Integer) defaultObject);  

        } else if (defaultObject instanceof Boolean)  

        {  

            return sp.getBoolean(key, (Boolean) defaultObject);  

        } else if (defaultObject instanceof Float)  

        {  

            return sp.getFloat(key, (Float) defaultObject);  

        } else if (defaultObject instanceof Long)  

        {  

            return sp.getLong(key, (Long) defaultObject);  

        }  

        return null;  

    }  

    /**

     * 移除某个key值已经对应的值

     * @param context

     * @param key

     */  

    public static void remove(Context context, String key)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        SharedPreferences.Editor editor = sp.edit();  

        editor.remove(key);  

        SharedPreferencesCompat.apply(editor);  

    }  

    /**

     * 清除所有数据

     * @param context

     */  

    public static void clear(Context context)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        SharedPreferences.Editor editor = sp.edit();  

        editor.clear();  

        SharedPreferencesCompat.apply(editor);  

    }  

    /**

     * 查询某个key是否已经存在

     * @param context

     * @param key

     * @return

     */  

    public static boolean contains(Context context, String key)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        return sp.contains(key);  

    }  

    /**

     * 返回所有的键值对

     *  

     * @param context

     * @return

     */  

    public static Map getAll(Context context)  

    {  

        SharedPreferences sp = context.getSharedPreferences(FILE_NAME,  

                Context.MODE_PRIVATE);  

        return sp.getAll();  

    }  

    /**

     * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类

     *  

     * @author zhy

     *  

     */  

    private static class SharedPreferencesCompat  

    {  

        private static final Method sApplyMethod = findApplyMethod();  

        /**

         * 反射查找apply的方法

         *  

         * @return

         */  

        @SuppressWarnings({ "unchecked", "rawtypes" })  

        private static Method findApplyMethod()  

        {  

            try  

            {  

                Class clz = SharedPreferences.Editor.class;  

                return clz.getMethod("apply");  

            } catch (NoSuchMethodException e)  

            {  

            }  

            return null;  

        }  

        /**

         * 如果找到则使用apply执行,否则使用commit

         *  

         * @param editor

         */  

        public static void apply(SharedPreferences.Editor editor)  

        {  

            try  

            {  

                if (sApplyMethod != null)  

                {  

                    sApplyMethod.invoke(editor);  

                    return;  

                }  

            } catch (IllegalArgumentException e)  

            {  

            } catch (IllegalAccessException e)  

            {  

            } catch (InvocationTargetException e)  

            {  

            }  

            editor.commit();  

        }  

    }  

}

```

对SharedPreference的使用做了建议的封装,对外公布出put,get,remove,clear等等方法;

注意一点,里面所有的commit操作使用了SharedPreferencesCompat.apply进行了替代,目的是尽可能的使用apply代替commit

首先说下为什么,因为commit方法是同步的,并且我们很多时候的commit操作都是UI线程中,毕竟是IO操作,尽可能异步;

所以我们使用apply进行替代,apply异步的进行写入;

但是apply相当于commit来说是new API呢,为了更好的兼容,我们做了适配;

SharedPreferencesCompat也可以给大家创建兼容类提供了一定的参考~~

1、将NotificationSetUtil.java类复制到项目中

            }

 }

8、软键盘相关辅助类KeyBoardUtils

```

package com.zhy.utils;  

    import android.content.Context;  

    import android.view.inputmethod.InputMethodManager;  

    import android.widget.EditText;  

    /**

     * 打开或关闭软键盘

     *  

     * @author zhy

     *  

     */  

    public class KeyBoardUtils  

    {  

        /**

         * 打卡软键盘

         *  

         * @param mEditText

         *            输入框

         * @param mContext

         *            上下文

         */  

        public static void openKeybord(EditText mEditText, Context mContext)  

        {  

            InputMethodManager imm = (InputMethodManager) mContext  

                    .getSystemService(Context.INPUT_METHOD_SERVICE);  

            imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);  

            imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,  

                    InputMethodManager.HIDE_IMPLICIT_ONLY);  

        }  

        /**

         * 关闭软键盘

         *  

         * @param mEditText

         *            输入框

         * @param mContext

         *            上下文

         */  

        public static void closeKeybord(EditText mEditText, Context mContext)  

        {  

            InputMethodManager imm = (InputMethodManager) mContext  

                    .getSystemService(Context.INPUT_METHOD_SERVICE);  

            imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);  

        }  

    }

```

欢迎大家关注本人公众号,一起学习进步,谢谢!

            public void onClick(View v) {

import android.content.DialogInterface;

5、SD卡相关辅助类 SDCardUtils

```

package com.zhy.utils;  

import java.io.File;  

import android.os.Environment;  

import android.os.StatFs;  

/**

* SD卡相关的辅助类

*  

*  

*  

*/  

public class SDCardUtils  

{  

    private SDCardUtils()  

    {  

        /** cannot be instantiated **/  

        throw new UnsupportedOperationException("cannot be instantiated");  

    }  

    /**

     * 判断SDCard是否可用

     *  

     * @return

     */  

    public static boolean isSDCardEnable()  

    {  

        return Environment.getExternalStorageState().equals(  

                Environment.MEDIA_MOUNTED);  

    }  

    /**

     * 获取SD卡路径

     *  

     * @return

     */  

    public static String getSDCardPath()  

    {  

        return Environment.getExternalStorageDirectory().getAbsolutePath()  

                + File.separator;  

    }  

    /**

     * 获取SD卡的剩余容量 单位byte

     *  

     * @return

     */  

    public static long getSDCardAllSize()  

    {  

        if (isSDCardEnable())  

        {  

            StatFs stat = new StatFs(getSDCardPath());  

            // 获取空闲的数据块的数量  

            long availableBlocks = (long) stat.getAvailableBlocks() - 4;  

            // 获取单个数据块的大小(byte)  

            long freeBlocks = stat.getAvailableBlocks();  

            return freeBlocks * availableBlocks;  

        }  

        return 0;  

    }  

    /**

     * 获取指定路径所在空间的剩余可用容量字节数,单位byte

     *  

     * @param filePath

     * @return 容量字节 SDCard可用空间,内部存储可用空间

     */  

    public static long getFreeBytes(String filePath)  

    {  

        // 如果是sd卡的下的路径,则获取sd卡可用容量  

        if (filePath.startsWith(getSDCardPath()))  

        {  

            filePath = getSDCardPath();  

        } else  

        {// 如果是内部存储的路径,则获取内存存储的可用容量  

            filePath = Environment.getDataDirectory().getAbsolutePath();  

        }  

        StatFs stat = new StatFs(filePath);  

        long availableBlocks = (long) stat.getAvailableBlocks() - 4;  

        return stat.getBlockSize() * availableBlocks;  

    }  

    /**

     * 获取系统存储路径

     *  

     * @return

     */  

    public static String getRootDirectoryPath()  

    {  

        return Environment.getRootDirectory().getAbsolutePath();  

    }  

}

```

图片 1

    LinearLayout toucherLayout;

      String msg=intent.getStringExtra("msg");

package com.php.utils.ui.toast; import android.content.Context;import android.graphics.PixelFormat;import android.os.Handler;import android.os.Message;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.view.WindowManager;import android.widget.TextView;import android.widget.Toast; import java.util.Timer;import java.util.TimerTask; import com.php.notification.R; public class EToast2 { private WindowManager manger; private Long time = 2000L; private View contentView; private WindowManager.LayoutParams params; private static Timer timer; private Toast toast; private static Toast oldToast; private static Context context; public static final int LENGTH_SHORT = 0; public static final int LENGTH_LONG = 1; private static Handler handler; private CharSequence text; private View toastRoot; private EToast2(Context context, CharSequence text, int HIDE_DELAY){ this.text = text; if(HIDE_DELAY == EToast2.LENGTH_SHORT) this.time = 2000L; else if(HIDE_DELAY == EToast2.LENGTH_LONG) this.time = 3500L; if(oldToast != null && EToast2.context != null && EToast2.context != context){ EToast2.context = context; oldToast.cancel(); oldToast = null; } if(oldToast == null){ LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); toastRoot = inflate.inflate(R.layout.toast, null); TextView tv = toastRoot.findViewById(R.id.toast_notice); tv.setText; toast = Toast.makeText(context,"",HIDE_DELAY); toast.setView(toastRoot); toast.setGravity(Gravity.BOTTOM, 0, 200); contentView = toastRoot; params = new WindowManager.LayoutParams(); params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.windowAnimations = context.getResources().getIdentifier("android:style/Animation.Toast", null, null); params.type = WindowManager.LayoutParams.TYPE_TOAST; params.setTitle("EToast2"); params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; params.y = 200; } if(handler == null){ handler = new Handler(){ @Override public void handleMessage(Message msg) { EToast2.this.cancel(); } }; } } public static EToast2 makeText(Context context, String text, int HIDE_DELAY){ EToast2 toast = new EToast2(context, text, HIDE_DELAY); return toast; } public static EToast2 makeText(Context context, int resId, int HIDE_DELAY) { return makeText(context,context.getText.toString(),HIDE_DELAY); } public void show(){ if(oldToast == null){ oldToast = toast; Context context = contentView.getContext().getApplicationContext(); if (context == null) { context = contentView.getContext(); } manger = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); manger.addView(contentView, params); }else{ if(timer != null){ timer.cancel(); } (.getView().findViewById(R.id.toast_notice)).setText; } timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { handler.sendEmptyMessage; } }, time); } public void cancel(){ try { manger.removeView(contentView); } catch (IllegalArgumentException e) { //这边由于上下文被销毁后removeView可能会抛出IllegalArgumentException //暂时这么处理,因为EToast2是轻量级的,不想和Context上下文的生命周期绑定在一块儿 //其实如果真的想这么做,可以参考博文2的第一种实现方式,添加一个空的fragment来做生命周期绑定 } timer.cancel(); oldToast.cancel(); timer = null; toast = null; oldToast = null; contentView = null; handler = null; }}

                params.y = (int) event.getRawY();

        alertDialog.getWindow().setType(type);

package com.php.project.notificationsetutildemo; import android.content.Context;import android.os.Build;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.widget.Toast; import com.php.project.notificationsetutildemo.utils.NotificationSetUtil; public class MainActivity extends AppCompatActivity { private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = this; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { //判断是否需要开启通知栏功能 NotificationSetUtil.OpenNotificationSetting(mContext, new NotificationSetUtil.OnNextLitener() { @Override public void onNext() { Toast.makeText(mContext,"已开启通知权限",Toast.LENGTH_SHORT).show; } }}

import android.content.Intent;

     am.cancel(pi);

效果图

package com.bely.debugassist;

    public void onClick(DialogInterface dialog, intwhich) {

新建EToast2.java文件:

        {

   };

图片 2

    }

      }

package com.php.utils.ui.toast; import android.annotation.SuppressLint;import android.app.Activity;import android.app.AppOpsManager;import android.app.Application;import android.content.Context;import android.content.pm.ApplicationInfo;import android.os.Build;import android.support.annotation.RequiresApi;import android.support.v4.app.NotificationManagerCompat;import android.view.Gravity;import android.view.LayoutInflater;import android.view.View;import android.widget.TextView; import java.lang.reflect.Field;import java.lang.reflect.Method; import com.php.notification.R; public class Toast { private static final String CHECK_OP_NO_THROW = "checkOpNoThrow"; private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION"; private static int checkNotification = 0; private static Object mToast; private static boolean flag = true; private Toast(Context context, String message, int duration) { if(context instanceof Application) checkNotification = 0; else checkNotification = isNotificationEnabled ? 0 : 1; if (checkNotification == 1) { try { mToast = EToast2.makeText(context, message, duration); } catch (Exception e) { e.printStackTrace(); synchronized (CHECK_OP_NO_THROW) { if{ flag = false; View toastRoot = LayoutInflater.from.inflate(R.layout.toast, null); TextView tv = toastRoot.findViewById(R.id.toast_notice); tv.setText; mToast = android.widget.Toast.makeText(context,"",duration); ((android.widget.Toast) mToast).setView(toastRoot); ((android.widget.Toast) mToast).setGravity(Gravity.BOTTOM, 0, 200); } } (((android.widget.Toast) mToast).getView().findViewById(R.id.toast_notice)).setText; } } else {// mToast = android.widget.Toast.makeText(context, message, duration); synchronized (CHECK_OP_NO_THROW) { if{ flag = false; View toastRoot = LayoutInflater.from.inflate(R.layout.toast, null); TextView tv = toastRoot.findViewById(R.id.toast_notice); tv.setText; mToast = android.widget.Toast.makeText(context,"",duration); ((android.widget.Toast) mToast).setView(toastRoot); ((android.widget.Toast) mToast).setGravity(Gravity.BOTTOM, 0, 200); } } (((android.widget.Toast) mToast).getView().findViewById(R.id.toast_notice)).setText; } } private Toast(Context context, int resId, int duration) { if(context instanceof Application) checkNotification = 0; else checkNotification = isNotificationEnabled ? 0 : 1; if (checkNotification == 1 && context instanceof Activity) { mToast = EToast2.makeText(context, resId, duration); } else { mToast = android.widget.Toast.makeText(context, resId, duration); } } public static Toast makeText(Context context, String message, int duration) { return new Toast(context,message,duration); } public static Toast makeText(Context context, int resId, int duration) { return new Toast(context,resId,duration); } public void show() { if(mToast instanceof EToast2){ mToast).show(); }else if(mToast instanceof android.widget.Toast){ ((android.widget.Toast) mToast).show(); } } public void cancel(){ if(mToast instanceof EToast2){ mToast).cancel(); }else if(mToast instanceof android.widget.Toast){ ((android.widget.Toast) mToast).cancel(); } } //判断该app是否打开了通知 /** * 可以通过NotificationManagerCompat 中的 areNotificationsEnabled()来判断是否开启通知权限。NotificationManagerCompat 在 android.support.v4.app包中,是API 22.1.0 中加入的。而 areNotificationsEnabled()则是在 API 24.1.0之后加入的。 * areNotificationsEnabled 只对 API 19 及以上版本有效,低于API 19 会一直返回true * */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) @SuppressLint private static boolean isNotificationEnabled(Context context){ if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT){ NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from; boolean areNotificationsEnabled = notificationManagerCompat.areNotificationsEnabled(); return areNotificationsEnabled; } AppOpsManager mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); ApplicationInfo appInfo = context.getApplicationInfo(); String pkg = context.getApplicationContext().getPackageName(); int uid = appInfo.uid; Class appOpsClass = null; //* Context.APP_OPS_MANAGER *//* try { appOpsClass = Class.forName(AppOpsManager.class.getName; Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class); Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION); int value = opPostNotificationValue.get(Integer.class); return checkOpNoThrowMethod.invoke(mAppOps,value, uid, pkg) == AppOpsManager.MODE_ALLOWED); } catch (Exception e) { e.printStackTrace(); } return false; }}

        }

import android.os.CountDownTimer;

/** * 提示窗 * * @param context * @param mes */public static void promptMes(Context context, String mes) {com.php.utils.ui.toast.Toast.makeText(context, mes,Toast.LENGTH_SHORT).show();}

        }catch(PackageManager.NameNotFoundException e) {

       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

使用方法:

        imageButton1.setOnClickListener(new View.OnClickListener() {

     }

            uid = mPackageManager.getPackageUid("com.debugassist", UserHandle.USER_ALL);

 }else{

        params = new WindowManager.LayoutParams();

        .setMessage("将在30秒后关机")

import android.view.Gravity;

  //android Api的改变不同版本中设 置有所不同

import android.widget.ImageButton;

}

    @Override

          type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

        super.onDestroy();

2)CountDownTimer倒计时

            int interval = startIntent.getIntExtra(Config.KEY_INTERVAL, Config.interval);

}

        windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);

    //这里设置的是当天的15:55分,注意精确到秒,时间可以自由设置

    {

public class MainActivity extends AppCompatActivity

                return false;

       @Override

import android.graphics.PixelFormat;

      Log.i(TAG,"get Receiver msg :"+msg);

    WindowManager windowManager;

      Toast.makeText(context,msg,Toast.LENGTH_LONG).show();

import android.app.AppOpsManager;

     am= (AlarmManager) getSystemService(ALARM_SERVICE);

TAG标签:
版权声明:本文由必威发布于必威-编程,转载请注明出处:等都可以实现定时任务的执行,所以需要要么跳