• 前言
  • 相关开源项目
    • 使用eclipse和grant开源库权限管理

      • 更新api到23
      • 获得v4包
      • 项目实战开发
    • 默认许可权限无需授权
  • 总结和建议

前言

最近公司的app说装在安卓6.0的系统上程序直接崩溃了,然后呢crash日 志也没有捕获到,感觉好烦人因为公司压根就没有安卓6.0的测试机,最后呢我还是用genymotion来搞,由于用到了so库以前下载的那个jar也不知怎的5.0就运行不通过了,然后今天那到处弄Genymotion-ARM-Translation.zip,最后终于还是可以了。

由于公司是使用eclipse开发的也是醉了,然后呢网上对安卓6.0的权限有了还几个开源框架

相关开源项目

  • PermissionsDispatcher
    使用标注的方式,动态生成类处理运行时权限,目前还不支持嵌套Fragment。
  • RxPermissions
    基于RxJava的运行时权限检测框架
  • Grant
    简化运行时权限的处理,比较灵活
  • android-RuntimePermissions
    Google官方的例子

使用eclipse和grant开源库权限管理

1. 更新api到23

这里我们选择使用grant来进行项目的演示,因为是使用eclipse来开发,所以还是和android studio里面的还是有很多的区别,我们genymotion的6.0打开 ,因为是6.0系统的开发,所以呢我们的api的target 必须是23,如果不是呢那就麻烦你去update下。

2. 获得v4包

不多扯了,去你的sdk目录下拷贝出v4包放在你工程目录的libs下,不要问为什么因为在接下来的 项目里面需要用到。如下图目录图:

当然我们选择23.1.1下面的android-support-v4.jar,放入你项目的libs下面:
哈哈为什么要这样干呢?因为在里面我们会用到
这样做的话,代码会比较复杂,而在support library v4中,已经为我们准备好了更简单的方法,我们只需要采用library包中的方法来替换上面的方法即可:
- ContextCompat.checkSelfPermission()
不管当前运行的Android版本是多少,该方法都可以正确的方法权限的许可情况,允许或者拒绝.
- ActivityCompat.requestPermissions()
当该方法在6.0之前被调用时,onRequestPermissionsResult回调方法会立即被调用,并返回给你正确的PERMISSION_GRANTED 或者
PERMISSION_DENIED结果.

  • ActivityCompat.shouldShowRequestPermissionRationale()

在6.0之前调用该方法,将总会返回false.

切记,你应该总是使用这些方法来取代Activity自身的checkSelfPermission,requestPermissions和shouldShowRequestPermissionsRationale方法.这样,在不同的Android版本中,你的代码将总会完美的运行.

ContextCompat.checkSelfPermission();
ActivityCompat.requestPermissions();

上面的方法是v4包下的方法,然后呢低版本的v4包还不具有这样的方法,所以as的项目放在eclipse也是相当的蛋疼。
接下我们就实战项目了,

3. 项目实战开发

不多扯,来看代码:

package com.richerpay.ryshop.permissions;/*** Enum class to handle the different states* of permissions since the PackageManager only* has a granted and denied state.*/
enum Permissions {GRANTED,DENIED,NOT_FOUND
}

上面呢就 是权限的类型了,简单翻译下注释就是 用枚举对应3种状态:
已授权,授权失败,未发现的权限。
再看下我们的PermissionsManager.java

package com.richerpay.ryshop.permissions;import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment;
import android.util.Log;import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;/*** 权限管理类 */
public class PermissionsManager {private static final String TAG = PermissionsManager.class.getSimpleName();private final Set<String> mPendingRequests = new HashSet<String>(1);private final Set<String> mPermissions = new HashSet<String>(1);private final List<WeakReference<PermissionsResultAction>> mPendingActions = new ArrayList<WeakReference<PermissionsResultAction>>(1);private static PermissionsManager mInstance = null;public static PermissionsManager getInstance() {if (mInstance == null) {mInstance = new PermissionsManager();}return mInstance;}private PermissionsManager() {initializePermissionsMap();}/*** 此方法使用反射来读取清单类中的所有权限。*因为一些权限不存在于旧版本的安卓系统中,*因为他们不存在,他们将被拒绝时,你检查是否有权限*因为一个新的权限,往往是补充,那里没有以前的*所需的许可。我们初始化一组可用的权限,并检查组*检查是否有权限,当我们被拒绝时权限仍然不存在* */private synchronized void initializePermissionsMap() {Field[] fields = Manifest.permission.class.getFields();for (Field field : fields) {String name = null;try {name = (String) field.get("");} catch (IllegalAccessException e) {Log.e(TAG, "Could not access field", e);}mPermissions.add(name);}}/*** 此方法检索在应用程序清单中声明的所有权限。* 它返回一个非空数组,可以声明的权限。** @param  检查我们需要哪些权限* @return 返回在应用程序清单中声明的非空数组*/@NonNullprivate synchronized String[] getManifestPermissions(@NonNull final Activity activity) {PackageInfo packageInfo = null;List<String> list = new ArrayList<String>(1);try {Log.d(TAG, activity.getPackageName());packageInfo = activity.getPackageManager().getPackageInfo(activity.getPackageName(), PackageManager.GET_PERMISSIONS);} catch (PackageManager.NameNotFoundException e) {Log.e(TAG, "A problem occurred when retrieving permissions", e);}if (packageInfo != null) {String[] permissions = packageInfo.requestedPermissions;if (permissions != null) {for (String perm : permissions) {Log.d(TAG, "Manifest contained permission: " + perm);list.add(perm);}}}return list.toArray(new String[list.size()]);}/*** 在permissionsresultaction对象,它将变更通知这些权限* @param 权限所需的操作的权限。* @param 将 动作添加到当前正在执行的动作列表中。*/private synchronized void addPendingAction(@NonNull String[] permissions, @Nullable PermissionsResultAction action) {if (action == null) {return;}action.registerPermissions(permissions);mPendingActions.add(new WeakReference<PermissionsResultAction>(action));}/*** 删除从队列中等待的动作和执行该动作* @param 移除动作*/private synchronized void removePendingAction(@Nullable PermissionsResultAction action) {for (Iterator<WeakReference<PermissionsResultAction>> iterator = mPendingActions.iterator();iterator.hasNext(); ) {WeakReference<PermissionsResultAction> weakRef = iterator.next();if (weakRef.get() == action || weakRef.get() == null) {iterator.remove();}}}/***这个静态方法可以用来检查你是否有一个特定的权限。** @param 检查权限的上下文对象* @param 要检查的权限* @return 返回是否授权了此权限*/public synchronized boolean hasPermission(@Nullable Context context, @NonNull String permission) {return context != null && (ActivityCompat.checkSelfPermission(context, permission)== PackageManager.PERMISSION_GRANTED || !mPermissions.contains(permission));}/*** 这个静态方法可以用来检查你是否有几个特定的权限。* 为每一个权限,并将简单地返回一个布尔值是否你有所有的权限* @param 需要检查 权限的上下文* @param 权限 数组* @return 返回你是否有所有的权限*/public synchronized boolean hasAllPermissions(@Nullable Context context, @NonNull String[] permissions) {if (context == null) {return false;}boolean hasAllPermissions = true;for (String perm : permissions) {hasAllPermissions &= hasPermission(context, perm);}return hasAllPermissions;}/***这种方法的是获取清单里面的所有权限。permissionsresultaction  用于通知允许用户允许或拒绝每一个权限。** @param 需要检查权限的activity* @param permissionsresultaction用于权限接受通知你*/public synchronized void requestAllManifestPermissionsIfNecessary(final @Nullable Activity activity,final @Nullable PermissionsResultAction action) {if (activity == null) {return;}String[] perms = getManifestPermissions(activity);requestPermissionsIfNecessaryForResult(activity, perms, action);}/***该方法将请求的权限,如果*他们需要被要求(即我们没有许可),并会增加* permissionsresultaction到队列被通知的权限被授予或*否认。在预Android棉花糖的情况下,将立即授予权限。*活动变量为空,但如果它是无效的,不能执行的方法。*这是唯一可作为一种礼貌片段,getactivity()可能产量空*如果该片段没有添加到其父活动中* @param 请求权限的活动* @param 权限列表* @param permissionsresultaction通知当权限授予或拒绝。*/public synchronized void requestPermissionsIfNecessaryForResult(@Nullable Activity activity,@NonNull String[] permissions,@Nullable PermissionsResultAction action) {if (activity == null) {return;}addPendingAction(permissions, action);if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {doPermissionWorkBeforeAndroidM(activity, permissions, action);} else {List<String> permList = getPermissionsListToRequest(activity, permissions, action);if (permList.isEmpty()) {//if there is no permission to request, there is no reason to keep the action int the listremovePendingAction(action);} else {String[] permsToRequest = permList.toArray(new String[permList.size()]);mPendingRequests.addAll(permList);ActivityCompat.requestPermissions(activity, permsToRequest, 1);}}}/*** 该方法将请求的权限,如果*他们需要被要求(即我们没有许可),并会增加* permissionsresultaction到队列被通知的权限被授予或*否认。在预Android棉花糖(6.0)的情况下,将立即授予权限。*但如果 getactivity()返回null,这方法*将无法工作作为活动引用,必须检查权限。* @param 需要检查 权限的fragmnet* @param 需要请求的权限列表* @param permissionsresultaction通知当权限授予或拒绝。  */public synchronized void requestPermissionsIfNecessaryForResult(@NonNull Fragment fragment,@NonNull String[] permissions,
@Nullable PermissionsResultAction action) {Activity activity = fragment.getActivity();if (activity == null) {return;}addPendingAction(permissions, action);if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {doPermissionWorkBeforeAndroidM(activity, permissions, action);} else {List<String> permList = getPermissionsListToRequest(activity, permissions, action);if (permList.isEmpty()) {//if there is no permission to request, there is no reason to keep the action int the listremovePendingAction(action);} else {String[] permsToRequest = permList.toArray(new String[permList.size()]);mPendingRequests.addAll(permList);fragment.requestPermissions(permsToRequest, 1);}}}/*** 这个方法通知permissionsmanager,权限已经改变。如果你正在做*使用活动的权限请求,则应调用此方法,将通知所有悬而未决  的,permissionsresultaction当前对象 *在队列中,并将从挂起的请求列表中删除权限请求。* @param  已更改的权限。* @param  每个权限的值*/public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) {int size = permissions.length;if (results.length < size) {size = results.length;}Iterator<WeakReference<PermissionsResultAction>> iterator = mPendingActions.iterator();while (iterator.hasNext()) {PermissionsResultAction action = iterator.next().get();for (int n = 0; n < size; n++) {if (action == null || action.onResult(permissions[n], results[n])) {iterator.remove();break;}}}for (int n = 0; n < size; n++) {mPendingRequests.remove(permissions[n]);}}/*** 在安卓设备前要求权限(安卓6,api23),根据权限状态,直接进行或拒绝工作* @param 检测权限的activity* @param 权限数组* @param 我们执行某项操作后权限检查   */private void doPermissionWorkBeforeAndroidM(@NonNull Activity activity, @NonNull String[] permissions, @Nullable PermissionsResultAction action) {for (String perm : permissions) {if (action != null) {if (!mPermissions.contains(perm)) {action.onResult(perm, Permissions.NOT_FOUND);} else if (ActivityCompat.checkSelfPermission(activity, perm)!= PackageManager.PERMISSION_GRANTED) {action.onResult(perm, Permissions.DENIED);} else {action.onResult(perm, Permissions.GRANTED);}}}}/*** @param 检查权限的activity* @param 所有权限的名字* @param 我们执行某项操作后权限检查* @return 尚未授予的权限名称列表*/@NonNullprivate List<String> getPermissionsListToRequest(@NonNull Activity activity,@NonNull String[] permissions,@Nullable PermissionsResultAction action) {List<String> permList = new ArrayList<String>(permissions.length);for (String perm : permissions) {if (!mPermissions.contains(perm)) {if (action != null) {action.onResult(perm, Permissions.NOT_FOUND);}} else if (ActivityCompat.checkSelfPermission(activity, perm) != PackageManager.PERMISSION_GRANTED) {if (!mPendingRequests.contains(perm)) {permList.add(perm);}} else {if (action != null) {action.onResult(perm,Permissions.GRANTED);}}}return permList;}}

接下来我们来看PermissionsResultAction.java

package com.xxxx.xxxx.permissions;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;
import android.util.Log;import java.util.Collections;
import java.util.HashSet;
import java.util.Set;/***将实例传递给 requestpermissionsifnecessaryforresult方法。结  *果将被送回你无论是ongranted(所有的权限已被授予),或ondenied(所需*的权限被拒绝)。
*你把你的ongranted方法和通知功能,用户什么都在ondenied方法不工作。*/
public abstract class PermissionsResultAction {private static final String TAG = PermissionsResultAction.class.getSimpleName();private final Set<String> mPermissions = new HashSet<String>(1);private Looper mLooper = Looper.getMainLooper();/*** Default Constructor*/public PermissionsResultAction() {}/***如果您是在后台线程中使用权限请求,则希望*回调是在UI线程中,通过looper刷新ui*/public PermissionsResultAction(@NonNull Looper looper) {mLooper = looper;}/***当所有权限已被用户授予,把所有你的权限敏感的代码,可以只需执行所                        需权限*/public abstract void onGranted();/***当一个权限被拒绝的时候调用** @param 被拒绝的权限*/public abstract void onDenied(String permission);/*** 忽视未发现的权限*/@SuppressWarnings({})public synchronized boolean shouldIgnorePermissionNotFound(String permission) {Log.d(TAG, "Permission not found: " + permission);return true;}/**返回授权 结果*/@CallSuperprotected synchronized final boolean onResult(final @NonNull String permission, int result) {if (result == PackageManager.PERMISSION_GRANTED) {return onResult(permission, Permissions.GRANTED);} else {return onResult(permission, Permissions.DENIED);}}/***当一个特定的权限已更改。*此方法将调用所有权限,所以该方法确定*如果授权影响到该状态,是否可以继续进行*/@CallSuperprotected synchronized final boolean onResult(final @NonNull String permission, Permissions result) {//先从权限列表里移除当前权限mPermissions.remove(permission);if (result == Permissions.GRANTED) {if (mPermissions.isEmpty()) {new Handler(mLooper).post(new Runnable() {@Overridepublic void run() {onGranted();}});return true;}} else if (result == Permissions.DENIED) {//权限被拒new Handler(mLooper).post(new Runnable() {@Overridepublic void run() {onDenied(permission);}});return true;} else if (result == Permissions.NOT_FOUND) {if (shouldIgnorePermissionNotFound(permission)) {if (mPermissions.isEmpty()) {//权限为空new Handler(mLooper).post(new Runnable() {@Overridepublic void run() {onGranted();//去授权}});return true;}} else {new Handler(mLooper).post(new Runnable() {@Overridepublic void run() {//拒绝权限onDenied(permission);}});return true;}}return false;}/***注册指定的权限对象的permissionsresultaction*让它知道哪些权限来查找更改。** @param permissions名单*/@CallSuperprotected synchronized final void registerPermissions(@NonNull String[] perms) {//把名单加到权限集合里Collections.addAll(mPermissions, perms);}
}

好了,最后我们就来使用权限管理:

// 先对app获取所有需要的授权(6.0需要去获取权限)
grantPermissions();

/***
* 获取清单文件中的所有权限
*/
private void grantPermissions() {
@Override                       public void onGranted() {                                   Toast.makeText(MainActivity.this,                                         Toast.LENGTH_SHORT).show();
}
@Override                       public void onDenied(String permission) {
String message = String.format(
Locale.getDefault(),"Permission \"%1$s\" has been denied",                                   permission);                          Toast.makeText(MainActivity.this, message,                                   Toast.LENGTH_SHORT).show();
}});
}

上面呢 我们在程序一开始呢就去授权所有的清单里面的权限,你会看到和ios一样的权限dialog提示,这里呢我们直接来图片展示下。
如下图所示:

接下来我们要去通知权限授权的改变

@Overridepublic void onRequestPermissionsResult(intrequestCode,@NonNull String[] permissions, @NonNull int[]   grantResults) {PermissionsManager.getInstance().notifyPermissionsChange(permissions,grantResults);}

这里呢我们以百度定位的例子来使用:

        /*** 定位信息*/private void initLocation() {LocationClientOption option = new LocationClientOption();// 可选,默认高精度,设置定位模式,高精度(LocationMode.Hight_Accuracy),// 低功耗(LocationMode.Battery_Saving),// 仅设备(LocationMode.Device_Sensors)option.setLocationMode(LocationMode.Hight_Accuracy);option.setCoorType("bd09ll");// 可选,默认gcj02,设置返回的定位结果坐标系,// tempcoor="gcj02";//国家测绘局标准"bd09"//百度墨卡托标准"bd09ll"//百度经纬度标准// int span=1000;option.setScanSpan(0);// 可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的option.setIsNeedAddress(true);// 可选,设置是否需要地址信息,默认不需要option.setOpenGps(true);// 可选,默认false,设置是否使用gpsoption.setLocationNotify(true);// 可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果option.setIgnoreKillProcess(false);// 可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死mLocationClient.setLocOption(option);}/**
*页面 停止状态下关闭定位
*/
@Overrideprotected void onStop() {if (mLocationClient != null) {mLocationClient.stop();// 界面消失后取消定位mLocationClient = null;}super.onStop();}

我们先来判断定位权限是否已授权成功:

// 判断是否授权定位权限boolean hasPermission = PermissionsManager.getInstance().hasPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);

接下来我们根据是否授权成功来进行相关的操作:

    if (hasPermission == false) {//没有授权成功grantLoactionPermissons();//去授权}else{//授权成功去定位mLocationClient = ((RYApplication) getApplication()).mLocationClient;initLocation();// 定位mLocationClient.start();// 定位SDK// start之后会默认发起一次定位请求,开发者无须判断isstart并主动调用requestmLocationClient.requestLocation();}

根据定位需要的权限去授权

/*** 授权定位权限*/private void grantLoactionPermissons() {  PermissionsManager.getInstance().requestPermissionsIfNeces         saryForResult(this,new String[] {Manifest.permission.ACCESS_COARSE_LOCATION,                Manifest.permission.ACCESS_FINE_LOCATION,              Manifest.permission.WRITE_EXTERNAL_STORAGE },new PermissionsResultAction() {                      @Override                       public void onGranted() {                        mLocationClient = ((RYApplication)    getApplication()).mLocationClient;                           initLocation();// 定位                                mLocationClient.start();// 定位SDK                          // start之后会默认发起一次定位请求,开发者无须判断isstart并主动调用 requestmLocationClient.requestLocation();}
@Override
public void onDenied(String permission) {}});}

当然还有一些权限你无须去判断:

默认许可权限(无需授权)

还有一些权限是在安装的时候默认许可并且不可撤销的,我们把它们叫做普通权限,这些权限如下:

android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
这些权限和以前一样使用,你无需检查它们是否被撤销了

总结和建议

现在你应该很清楚整个新的权限系统了,同时你也应该知道我们面临的问题了.在Android6.0中动态权限系统已经取代了原有的权限系统,我们别无选择,退无可退,唯一能做的就是去做好适配工作.
好消息是需要进行动态申请的权限是少量的,大部分常用的权限是默认获得许可,并不需要你处理的.总而言之,你只需要修改一小部分代码来完成适配工作.
在这里给出两个建议:
1.优先对重要的部分进行适配,确保不会出现崩溃问题.
2.在完成适配工作前,不要将应用的targetSdkVersion设为23,尤其是在使用AndroidStudio创建新工程的时候,记得手动修改一下工程的targetSdkVersion,因为AndroidStudio会默认使用最新的SDK版本.

说到修改代码,我必须承认工作量很大.如果之前的架构设计不合理的话,你可能需要花费一些时间来重新设计了,就像之前说的,我们别无选择,除了去做好它.

我建议你列出应用的功能所依赖的所有的权限,然后考虑如果权限被拒绝,怎样使你的应用的功能尽可能可用,并考虑好如果部分权限被拒绝的情况下,你应该怎么做.恩,这也很复杂,最好能记录好各种情况.

对于安卓6.0的权限运行问题,你可移步Android 6.0 运行时权限处理

好累啊,一不小心到12点,睡觉,加油吧。第一次使用markDown感觉好辛苦,写个东西都

安卓6.0权限处理在项目中的实践相关推荐

  1. 玩安卓从 0 到 1 之项目总结

    玩安卓从 0 到 1 之项目总结 前言 这篇文章是这个系列的第七篇文章了,也是我准备写的这个系列的最后一篇文章.下面是前六篇文章: 1.玩安卓从 0 到 1 之总体概览 2.玩安卓从 0 到 1 之项 ...

  2. [异常解决] 安卓6.0权限问题导致老蓝牙程序出现异常解决办法:Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission...

    [异常解决] 安卓6.0权限问题导致老蓝牙程序出现异常解决办法:Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission... 参考 ...

  3. Effective Dart 文档注释在Flutter项目中的实践

    前言 什么是注释? 在编程语言中,注释就是对代码的解释和说明,其目的是让人们能够更加轻松地了解代码. 也有一句话是这样说的:程序员都讨厌两件事,1.别人不写注释 2.自己写注释 在开发者社区里,我不止 ...

  4. Protobuf 的 import 功能在 Go 项目中的实践

    业务场景 我们会有这样的需求:在不同的文件夹中定义了不同的 proto 文件,这些不同的文件夹可能是一些不同的 gRPC 服务.因为不想重复定义某一个 message,所以其中一个服务可能会用到其他服 ...

  5. 数加平台在数据挖掘项目中的实践

    目录 背景 数据源 数据处理 模型训练及预测 数据可视化 总结 1. 背景 返回目录 随着越来越多的公司开始重视数据的积累和产品的敏捷开发,数据量的不断增加和开发周期的不断缩短,就形成了一对明显的矛盾 ...

  6. 数加平台在数据挖掘项目中的实践 1

    目录 背景 数据源 数据处理 模型训练及预测 数据可视化 总结 1. 背景 返回目录 随着越来越多的公司开始重视数据的积累和产品的敏捷开发,数据量的不断增加和开发周期的不断缩短,就形成了一对明显的矛盾 ...

  7. 安卓7.0权限及预览版问题

    昨天一觉醒来,发现安卓7.0的首个开发者预览版竟然发布了,惊喜之余立马抓起Nexus5准备升级,结果立马被迎头了一盆冷水,支持的设备只有Nexus6.Nexus 5X.Nexus 6P.Nexus 9 ...

  8. methods vue过滤器 和_数据动态过滤技巧在 Vue 项目中的实践

    这个问题是在下在做一个 Vue 项目中遇到的实际场景,这里记录一下我遇到问题之后的思考和最后怎么解决的(老年程序员记性不好 -.-),过程中会涉及到一些Vue源码的概念比如 $mount. rende ...

  9. 网关 Apache APISIX 在 360 基础运维平台项目中的实践

    女主宣言 今天小编为大家分享一篇关于Apache APISIX的文章,文章从开发者的角度讲述了 Apache APISIX 网关在 360 基础运维平台的落地实践,希望能对大家有所帮助. PS:丰富的 ...

最新文章

  1. Only the original thread that created a view hierarchy can touch its views
  2. 九、数据库群集部署、配置 (二)
  3. Java并发编程(8):多线程环境中安全使用集合API(含代码)
  4. android studio 动画效果图,Android Studio如何动画移动视图?
  5. Spring下载地址
  6. element ui后台html_GitHub上10个开源且优秀的后台管理系统UI面板
  7. Jmeter(三)_配置元件
  8. pythonjson序列化_Python Json序列化与反序列化的示例
  9. 端口映射 - 专业术语 - 发问篇
  10. 没有服务器配置信息是怎么回事,isp服务器未配置怎么回事
  11. %1$s %1$d Android string
  12. iOS 11.2 版本紧急修复黑屏 Bug,却遇 FaceID 识别错误,真实原因在此
  13. python核心理念_《三天搞定Python基础概念之第一天》中文版
  14. 如何保证kafka消息的可靠性传递?
  15. tmdb数据集_数据科学第2部分的数据管道tmdb api数据搜寻器
  16. pdf怎么转换成word格式不变?
  17. 每天做好一件事,坦然微笑地面对生活
  18. 中国气象台API(2017.09)
  19. .NET前后分离解决方案
  20. 浏览器 本地html 图片不显示,浏览网页图片无法显示怎么回事 网页图片显示不出来的解决方法...

热门文章

  1. wbin笔记本商务版博通机型装(原版黑苹果)单MacOS流程记录(备忘)
  2. 微信h5页面图片预览
  3. 酒店小程序线上线下推广引流策略
  4. 计算机休眠移动硬盘不休眠,关闭硬盘盒自动休眠软件
  5. 电脑横屏和竖屏双屏幕设置不一样的壁纸
  6. centos8安装RabbitMQ和erlang
  7. 永洪BI携手华为云FusionInsight,让数据分析提效20倍
  8. CF727E. Games on a CD (Hash)
  9. 计算机机房年度重点工作,信息中心计算机的机房建设要求最新.doc
  10. 点卯.三维视频融合助力国家全面推进实景三维中国建设, 构建数字中国建设基座 ;开放C++源代码 点卯-魔镜系列