首页 文章 精选 留言 我的

精选列表

搜索[记忆机制],共10000篇文章
优秀的个人博客,低调大师

一个Demo带你理解Android接口回调机制

前言 开发中,接口回调是我们经常用到的。 接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行。 举个例子: A有一个问题不会,他去问B,B暂时解决不出来,B说,等我(B)解决了再告诉你(A)此时A可以继续先做别的事情。 那么就只有当B解决完问题后告诉A问题解决了,A才可以能解决这个问题。 代码中比如最常用的: 一个Activity中给按钮一个接口回调方法,只有用户点击了这个按钮,告诉按钮被点击了,才会执行按钮接口回调的方法 Button btn = new Button(this); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); 那么下面通过一个Demo理解接口回调: 主线程开启一个异步任务,当异步任务接收到数据,则把数据用TextView显示出来 1、首先 我们需要定义一个接口,定义一个方法,参数为一个字符串: package com.xqx.InterfaceDemo; public interface ChangeTitle { void onChangeTitle(String title); } 2、写一个异步任务,把接口作为构造方法参数,在doInBackground()方法中判断如果有数据,则接口回调 package com.xqx.InterfaceDemo; import android.content.Context; import android.os.AsyncTask; public class MyTask extends AsyncTask<String,Void,String>{ private ChangeTitle changeTitle; public MyTask(ChangeTitle changeTitle) { this.changeTitle = changeTitle; } @Override protected String doInBackground(String... strings) { if (strings[0]!=null){ changeTitle.onChangeTitle(strings[0]); } return null; } } 3、主Activity,给异步任务参数传this,即 接口回调方法在此类中执行,那么就需要实现ChangeTitle接口,重写接口中 onChangeTitle 方法 package com.xqx.InterfaceDemo; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity implements ChangeTitle { private TextView textView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); textView = (TextView) findViewById(R.id.textView); new MyTask(this).execute("我是标题"); } // 重写接口方法,执行相应操作 @Override public void onChangeTitle(String title) { textView.setText(title); } } 附录 Android高级技术大纲,以及系统进阶视频; Android高级技术大纲 Android进阶系统资料视频 获取方式; 加Android进阶群;701740775。即可前往免费领取。免费备注一下csdn

优秀的个人博客,低调大师

如何设计投放系统系列----灵活的字段映射补全机制

引言 我们知道搭建系统跟投放系统是两个紧密关联的系统,搭建产出的是页面的结构,投放产出的是页面的数据。搭建产出的页面包含各式各样的模块,这些模块包含的字段也没有太多规律可言,那么投放系统怎么为这些模块补全数据呢? 在回答这个问题之前,我们先尝试解决一些简单的业务 case。 几个案例 案例一 有一个商品模块,字段包括:商品的标题、商品图片、购买链接、商品价格、商品描述,想要投放某个选品集的商品,请问投放系统应该怎么设计以补全这些字段信息? 拿到这个需求,最直观的解决方案就是,直接去商品库取选品集对应的商品列表,把商品库里的字段塞到对应的模块字段上。 // 商品选品集 var goodSet = [1,2,3,4,5]; // 从商品库获取对应的商品实体信息 var entityMap = goodService.fetch(goodSet);

优秀的个人博客,低调大师

学习Java基础知识,打通面试关~十三锁机制

静态创建线程池 我们平常使用的大部分还是依靠java中自带的静态工厂产生的线程池。先了解下自带的线程池。 newFixedThreadPool(int numThreads) 该线程池会在初始化的指定线程数量。具有以下的特点1.在任何时刻都是最多有numThreads的线程数量活动。如果超过限制会在LinkedBlockingQueue中等待。 2.当达到核心线程数的时候,线程数不在继续增加。3.有工作线程退出,新的工作线程被创建来达到设置的线程数。 Executors.newFixedThreadPool(1); //源码实现 public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } newCachedThreadPool 该线程池是一个可以用来缓存的线程池。1.尝试缓存使用过的线程。2.没有缓存的线程池时,就会使用工厂方法创建线程池,最大的容量理论上是Integer.MAX_VALUE。这个跟服务器的配置有关。所以如果过来大量的线程任务,那么该线程池会在瞬间创建多个线程来执行工作。3.时间上多余的线程超过60秒会被终止移除缓存中。4.内部使用的SynchronousQueue实现的队列,该队列在实现的时候没有容量。适合来做交换的工作。 Executors.newCachedThreadPool(); //源码实现 public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } newSingleThreadExecutor 该线程池是用来设置单个的线程池,使用的队列是无界队列。因为提交的任务只要一个是能活动的,剩下的是放到无界队列中。队列是先进先出的。那么执行顺序是有序的。 Executors.newSingleThreadExecutor(); //源码 public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } newWorkStealingPool 工作线程,该线程是在jdk1.8以后新增加的.使用的是ForkJoinPool创建线程池。该任务执行没有顺序。需要考虑到硬件的cpu核心数。 Executors.newWorkStealingPool(); public static ExecutorService newWorkStealingPool() { return new ForkJoinPool (Runtime.getRuntime().availableProcessors(), //默认使用的是硬件的cpu数目 ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); } Executors.newWorkStealingPool(10); public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, // 使用的是自定义的核心数 ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); } newSingleThreadScheduledExecutor()与newScheduledThreadPool(int poolSize) 周期性的调度执行任务的线程池。 单个执行。 Executors.newSingleThreadScheduledExecutor(); public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService (new ScheduledThreadPoolExecutor(1)); } //核心周期执行的线程数 Executors.newScheduledThreadPool(10); public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } 了解其java内部的静态线程池,并且在程序中使用其策略。当然在这种我们没有看到的是线程池的拒绝策略。无界队列和有界队列,核心数的与最大的核心数的设置,这些不同。那么我们的执行拒绝策略也是不同的。在接下里的文章我们会具体了解拒绝策略。 原文发布时间为:2018-07-09本文作者:mengrui本文来自云栖社区合作伙伴“LuckQI”,了解相关信息可以关注“LuckQI”。

优秀的个人博客,低调大师

[译] JavaScript 是如何工作的:Web 推送通知的机制

原文地址:How JavaScript works: the mechanics of Web Push Notifications 原文作者:Alexander Zlatkov 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m… 译者:Starrier 校对者:allen、老教授 这是专门研究 JavaScript 及其构建组件系列文章的第 9 章。在识别和描述核心元素的过程中,我们还分享了我们在构建一个轻量级 JavaScript 应用程序 SessionStack 时使用的一些经验规则,该应用程序需要健壮、高性能,可以帮助用户实时查看和重现它们的 Web 应用程序缺陷。 如果你错过了前几章,你可以在这里找到它们: [译] JavaScript 是如何工作的:对引擎、运行时、调用堆栈的概述 [译] JavaScript 是如何工作的:在 V8 引擎里 5 个优化代码的技巧 [译] JavaScript 是如何工作的:内存管理 + 处理常见的4种内存泄漏 [译] JavaScript 是如何工作的: 事件循环和异步编程的崛起 + 5个如何更好的使用 async/await 编码的技巧 [译] JavaScript 是如何工作的:深入剖析 WebSockets 和拥有 SSE 技术 的 HTTP/2,以及如何在二者中做出正确的选择 [译] JavaScript 是如何工作的:与 WebAssembly 一较高下 + 为何 WebAssembly 在某些情况下比 JavaScript 更为适用 [译] JavaScript 是如何工作的:Web Worker 的内部构造以及 5 种你应当使用它的场景 [译] JavaScript 是如何工作的:Web Worker 生命周期及用例 今天,我们来关注 Web 推送通知:我们将了解它们的构建组件,探索发送/接收通知的流程,最后分享 SessionStack 是如何利用这些来构建新产品的特性。 推送通知在手机领域被广泛使用。由于某种原因,它们很晚才进入 Web 领域,尽管开发人员呼唤了很久。 概述 Web 推送通知允许用户在 Web 应用程序中选择接收更新信息,这些旨在重新吸引用户群注意的更新信息通常是对用户来说有趣、重要、实时的内容。 推送基于我们在上一篇文章中详细讨论过的 Service Worker。 在这种情况下,使用 Service Worker 的原因是它们在后台工作。这对推送通知非常有用,因为这意味着只有当用户与通知本身进行交互时才会执行它们的代码。 推送和通知 推送和通知是两种不同的 API。 推送 —— 它在服务器端将消息推送给 Service Worker 时被调用 通知 —— 这是 Service Worker 或 web 应用程序中向用户显示信息脚本的操作。 推送 实现推送有三个步骤: UI —— 添加必要的客户端逻辑来让用户订阅推送,这是你的 Web 应用程序 UI 需要的 JavaScript 逻辑,这样用户就能给自己注册从而可以收到消息推送。 发送推送消息 —— 在服务器上实现 API 调用,该调用将触发对用户设备的推送消息。 接受推送消息 —— 一旦推送消息到达浏览器,就进行处理。 现在我们将更详细地描述整个过程。 浏览器支持检测 首先,我们需要检查当前浏览器是否支持推送消息。我们可以通过两个简单的方法检查是否支持推送消息: 检查 navigator 对象上的 serviceWorker 检查 window 对象上的 PushManager 两种检查看起来都是这样的: if (!('serviceWorker' in navigator)) { // Service Worker isn't supported on this browser, disable or hide UI. return; } if (!('PushManager' in window)) { // Push isn't supported on this browser, disable or hide UI. return; } 注册一个 Service Worker 此时,我们知道该功能是受支持的。下一步是注册我们的 Service Worker。 如何注册 Service Worker,你从我们以前的一篇文章中应该已经熟悉了。 请求许可 在注册了 Service Worker 之后,我们可以开始订阅用户。要做到这一点,我们需要得到他的许可才能给他发送推送信息。 获取许可的 API 相对简单,但缺点是 API 已经从接受回调变为返回 Promise,这带来了一个问题:我们无法判断当前浏览器实现了哪个 API 版本,因此你必须实现和处理这两个版本。 看起来是这样的: function requestPermission() { return new Promise(function(resolve, reject) { const permissionResult = Notification.requestPermission(function(result) { // Handling deprecated version with callback. resolve(result); }); if (permissionResult) { permissionResult.then(resolve, reject); } }) .then(function(permissionResult) { if (permissionResult !== 'granted') { throw new Error('Permission not granted.'); } }); } Notification.requestPermission() 调用将向用户显示以下提示: 一旦被授权、关闭或阻止,我们将得到字符串格式的结果:‘granted’、‘default’ 或 ‘denied’。 记住,如果用户单击 Block 按钮,你的 Web 应用程序将无法再次请求用户的许可,直到他们通过更改权限状态手动 “unblock” 你的应用程序的限制。此选项隐藏在设置界面中。 用户订阅使用 PushManager 一旦我们注册了 Service Worker 并获得许可权限,当你在注册你的 Service Worker 时,我们就可以通过调用 registration.pushManager.subscribe() 来订阅用户。 整个片段可能如下所示(包括 Service Workder 注册): function subscribeUserToPush() { return navigator.serviceWorker.register('service-worker.js') .then(function(registration) { var subscribeOptions = { userVisibleOnly: true, applicationServerKey: btoa( 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U' ) }; return registration.pushManager.subscribe(subscribeOptions); }) .then(function(pushSubscription) { console.log('PushSubscription: ', JSON.stringify(pushSubscription)); return pushSubscription; }); } registration.pushManager.subscribe(options) 接受一个 options 对象,它包含必要参数和可选参数: userVisibleOnly:布尔值指示返回的推送订阅将仅用于对用户可见的消息。它必须设置为 true,否则你会得到一个错误(这有历史原因)。 applicationServerKey:Base64-encoded DOMString 或者 ArrayBuffer 包含推送服务器用来验证应用服务器的公钥。 你的服务器需要生成一对应用程序服务器密钥 —— 也称为 VAPID 密钥,对于你的服务器来说,它们是唯一的。它们是一对公钥和私钥。私钥被秘密存储在你的终端,而公钥则与客户端交换。这些密钥允许推送服务知道哪个应用服务器订阅了用户,并确保它是触发向该特定用户推送消息的相同服务器。 你只需要为应用程序创建一次私钥/公钥对。做到这一点的方法是去完成这个 —— web-push-codelab.glitch.me/。 浏览器在订阅用户时将 applicationServerKey(公钥)传递给推送服务,这意味着推送服务可以将应用程序的公钥绑定到用户的 PushSubscription 中。 情况是这样的: 你的 web app 被加载时,你可以调用 subscribe() 来传入你的 server 密钥。 浏览器向生成端点的推送服务发出请求,将此端点与该键关联并将端点返回给浏览器。 浏览器将此端点添加到 PushSubscription 对象中,该对象通过 subscribe() 的 promise 返回。 之后,无论你想何时发送推送消息,你都需要创建一个包含使用应用程序服务器的专用密钥签名信息的 Authorization header。当推送服务收到发送推送消息的请求时,它将通过查找已经连接到该特定端点的公钥来验证头(第二步)。 推送对象 PushSubscription 包含用户设备发送推送消息所需的所有信息。就像这样: { "endpoint": "https://domain.pushservice.com/some-id", "keys": { "p256dh": "BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=", "auth":"FPssMOQPmLmXWmdSTdbKVw==" } } endpoint 是推送服务的 URL。要触发推送消息,请对此 URL 发送 POST 请求。 这里的 keys 对象的值是用来加密推送消息带过来的消息数据。 一旦用户被订阅并且你有 PushSubscription,你需要将它发送到你的服务器。在那里(在服务器上),你将这个订阅存到数据库中,从今以后如果你要向该用户推送消息就使用它。 发送推送消息 当你想向用户发送推送消息时,你首先需要一个推送服务。你要(通过 API 调用)告诉推送服务要发送哪些数据,谁来接收数据以及其他关于怎么发送数据的标准。通常,此 API 调用是在你服务器上完成的。 推送服务 推送服务是接收请求,验证请求并将推送消息传递给对应的浏览器。 注意推送服务不是由你管理的 —— 它是第三方服务。你的服务器通过 API 与 推送服务进行通讯。推送服务的一个例子是 Google 的 FCM。 推送服务处理所有繁重的任务,比如,如果浏览器处于脱机状态,推送服务会在发送相应消息之前对消息进行排队,等待浏览器的再次联机。 每个浏览器都使用它们想要的任何推送服务,这是开发者无法控制的。 然而所有的推送服务都具有相同的 API,因此在实现过程中不会有很大难度。 为了获得 URL 来进行消息推送请求,你需要检查 PushSubscription 对象中存储的 endpoint 值。 推送服务 API 推送服务 API 提供了一种将消息发送给用户的方式。API 基于Web 推送协议,它是一种定义了如何对推送服务进行 API 调用的 IETF 标准。 你使用推送消息发送的数据必须被加密。这样可以防止推送服务查看发送的数据。这很重要,因为浏览器是可以决定使用哪种推送服务的(它可能使用了一些不受信任且不够安全的服务器)。 对于每个推送消息,你还可以提供下列说明: TTL —— 定义消息会在队列中等多久,超过这个时间消息就会被删除不做推送。。 优先级 —— 定义消息的优先级,因为推送服务只发送高优先级的消息,以此来保护用户设备的电池寿命。 Topic —— 给推送消息一个主题,新消息会替换等待中的带相同主题的消息,这样一旦设备处于活动状态,用户将不会收到过时的消息。 浏览器中的推送事件 如上所述,将消息发送到推送服务后,消息将处于挂机状态,直到发生下列情况之一: 设备上线。 消息由于 TTL 而在队列上过期。 当推送服务传递消息时,浏览器会接收它,解密并在 Service Worker 中分发一个 push 事件。 这里最好的是,即使是你的网页没有打开,浏览器也可以执行你的 Service Worker。将会发生下面的事情: 推送消息到达解密它的浏览器 浏览器唤醒 Service Worker push 事件被分发给 Service Worker 设置推送事件监听器的代码应该与用 JavaScript 编写的任何其他事件监听器类似: self.addEventListener('push', function(event) { if (event.data) { console.log('This push event has data: ', event.data.text()); } else { console.log('This push event has no data.'); } }); 需要了解 Service Worker 的一点是,你没有 Service Worker 代码运行时长的控制权。浏览器决定何时将其唤醒以及何时终止它。 在 Service Workers 中,event.waitUntil(promise) 通知浏览器工作正在进行,直到 promise 确定为止,如果它想要完成该工作,它不应该终止 sercice worker。 这里是处理 push 事件的例子: self.addEventListener('push', function(event) { var promise = self.registration.showNotification('Push notification!'); event.waitUntil(promise); }); 调用 self.registration.showNotification() 会向用户发送一个通知,并返回一个 promise,只要消息展示了该 promise 就会触发 resolve。 showNotification(title, options) 方法可以在视觉上进行调整以适应你的需求。title 参数是一个 string,而 options 是一个看起来像这样的对象: { "//": "Visual Options", "body": "<String>", "icon": "<URL String>", "image": "<URL String>", "badge": "<URL String>", "vibrate": "<Array of Integers>", "sound": "<URL String>", "dir": "<String of 'auto' | 'ltr' | 'rtl'>", "//": "Behavioural Options", "tag": "<String>", "data": "<Anything>", "requireInteraction": "<boolean>", "renotify": "<Boolean>", "silent": "<Boolean>", "//": "Both Visual & Behavioural Options", "actions": "<Array of Strings>", "//": "Information Option. No visual affect.", "timestamp": "<Long>" } 你可以在这里阅读到每个选项内容的更多细节 — developer.mozilla.org/en-US/docs/…。 推送通知是一种可以在有紧急、重要和时间敏感的信息需要与用户进行分享的情况下,吸引用户注意的绝好方式。 例如,我们在 SessionStack 计划利用推送通知来提醒用户,让他们知道自己的产品中何时发生崩溃、问题或异常。这会让用户立即知道出现了问题。然后他们可以利用我们的库所收集的数据(如 DOM 修改、用户交互、网络请求、未处理异常和调试信息),以视频的形式重现问题并查看最终发生在用户身上的一切事情。 原文发布时间为:2018年05月19日原文作者:LeviDing 本文来源:掘金如需转载请联系原作者

优秀的个人博客,低调大师

深入java虚拟机学习 -- 类的加载机制(四)

类加载的命名空间 每个类加载器都有自己的命名空间,命名空间由所有以此加载器为初始类加载器的类组成,不同命名空间的两个类是不可见的,但只要得到类所对应的Class对象的refrence(反射),还是可以访问另一个命名空间的类信息的。 同一个命名空间内的类是相互可见的,子加载器的命名空间包含所有父加载器的命名空间,也就是说由子加载器加载的类能看到父加载器加载的类。例如:系统类加载器加载的类能看到根类加载器加载的类(用户自定的类可以访问java.lang.*包下的信息),由父加载器加载的类不能看到子加载器加载的类。 如果两个加载器之间没有直接或者间接的父子关系,那么它们个字加载的类相互不可见。 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,该方法根据参数指定的类的名字,返回对应的Class对象的引用。 protected Class<?> findClass(String name) throws ClassNotFoundException { throw new ClassNotFoundException(name); } 我们可以按到ClassLoader里面的findClass方法的默认实现会抛出ClassNotFoundException异常,我们只需要在自定义的加载器里面重写,即可。 public class MyClassLoader extends ClassLoader { private String name;//类加载器的名字 private String path="";//加载类的默认路径 private String fileType=".class"; //class文件的扩展名 public MyClassLoader(String name){ super();//让系统类加载器成为该类加载器的父加载器 this.name=name; } public MyClassLoader(ClassLoader parent,String name){ super(parent);//显示指定该类加载器的父加载器 this.name=name; } @Override public String toString() { return this.name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } /** * 抽象类ClassLoader的findClass函数默认是抛出异常的。而前面我们知道, * loadClass在父加载器无法加载类的时候,就会调用我们自定义的类加载器中的findeClass函数, * 因此我们必须要在loadClass这个函数里面实现将一个指定类名称转换为Class对象. * @param name * @return */ @Override protected Class<?> findClass(String name) { byte [] data=this.loadClassData(name); return this.defineClass(name,data,0,data.length); } private byte[] loadClassData(String name) { InputStream is=null; byte [] data=null; ByteArrayOutputStream baos=null; try { this.name=this.name.replace(".","\\"); is=new FileInputStream(new File(path+name+fileType)); baos=new ByteArrayOutputStream(); int ch=0; while(-1!=(ch=is.read())){ baos.write(ch); } data= baos.toByteArray(); } catch(Exception e){ e.printStackTrace(); } finally { try { is.close(); baos.close(); } catch(IOException e) { e.printStackTrace(); } } return data; } public static void main(String[] args) throws Exception { MyClassLoader loader1 = new MyClassLoader("loader1");//没有指定loader的父加载器,则默认的父加载器为系统类加载器 loader1.setPath("G:\\myapp\\loader1\\"); MyClassLoader loader2 = new MyClassLoader(loader1,"loader2");//指定loader2的父加载器为loader1,这里的loader1和loader2都为MyClassLoader的实例 loader2.setPath("G:\\myapp\\loader2\\"); MyClassLoader loader3 = new MyClassLoader(null,"loader3");//bootstrap类加载器 loader3.setPath("G:\\myapp\\loader3\\"); //test(loader1); test(loader2); test(loader3); } public static void test(ClassLoader loader) throws Exception { Class clazz=loader.loadClass("Sample"); Object object=clazz.newInstance(); } 开开心心编码,快快乐乐生活。

优秀的个人博客,低调大师

Blackphone手机制造商欲推“高端”平板电脑

随着平板电脑市场变得越来越饱和,平板销售量可能也已达到峰值,平板制造商怎样才能脱颖而出呢?或许通过制造一款能把用户隐藏起来的平板电脑,将可实现这一目标。 图:Blackphone团队的隐私保护平板电脑标志 这正是Silent Circle在今年6月份推出的Blackphone智能手机背后的思想。该公司主要专注于用户隐私,这是其首要特征,因此Blackphone手机几乎为所有功能都进行了加密:短信、电子邮件、通话记录、网页浏览等。基于Blackphone手机的控制中心实用程序,Slient Circle强调用户有能力限制其信息的发送和接收量。这一切都因Silent Circle与Geeksphone合作构建的PrivatOS平台成为可能,该平台有点像专注于隐私的Android系统,但并未经Android认证。 正如许多其他Android设备制造商一样,Silent Circle决定从智能手机领域跃入平板电脑市场。该公司的联合创始人乔恩·卡拉斯(Jon Callas)向美国广播电视(BBC)表示,该公司“很快”将推出一款平板电脑,目前该设备已处于准备阶段。很遗憾,卡拉斯并未提供更多详细信息,不过他曾向美国全国广播公司财经频道(CNBC)表示,它将是一款“高端”平板设备。Blackphone智能手机的零售价为629美元,其中还包括一年期的Silent Circle移动计划。 毋庸置疑,该公司的这(些)款设备为智能手机市场上那些受隐私困扰的买家填补了空白,由于前段时间的明星照片曝光及类似事件,越来越多的人成为该隐私保护设备的买家。然而,即使是PrivatOS系统也并非刀枪不入——尽管Blackphone的小规模社区可保护其免受针对最大组织的黑客的窃听,但该设备在今年的Def Con黑客大会上还是被root了。 “Blackphone”式平板电脑面临的一个主要障碍是,它缺乏Android系统的认证,这意味着它将无法访问谷歌官方电子市场(Google Play Store)。然而Silent Circle详细说明了用户需如何访问亚马逊的应用商店,尽管其追踪用途与PrivatOS系统的目标有些相悖。虽然对智能手机用户而言,应用的缺乏可能没什么大碍,但对很多人来说,应用是他们选择使用平板电脑的主要因素。期待在Silent Circle最终发布其平板电脑时,我们可以看到该公司是如何处理这个问题的。 原文出处:科技行者 转载请与作者联系,同时请务必标明文章原始出处和原文链接及本声明。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册