今日已更新 163 条资讯 | 累计 40937 条内容
关于我们

标签:#an

找到 3018 篇相关文章

AI 资讯

"Video won't play" turned out to be four different bugs

Our app ships long video lessons. Twenty to forty minutes each, watched mostly on hostel wifi and mobile data with two bars. Streaming video looks like a solved problem when you build the happy path. You wire up ExoPlayer, point it at a stream, it plays. Then real students open it on devices you have never held, and your bug tracker starts filling up with one line: "video not playing." That line turned out to be four unrelated problems. Here's what I actually learned. ## Buffering is the bug you feel before you see an error Nobody waits out a bad connection during a 35-minute lecture. On a 15-second reel a stall is annoying. In a lecture, a stall every two minutes means the student closes the app and studies from a PDF instead. So the real question was never "does it play." It was "what happens when the network stops cooperating for four seconds." Three situations broke us repeatedly: Wifi to mobile data handover mid-lesson Bandwidth that is technically connected but useless Short total drops, three to ten seconds, that should not end playback ExoPlayer gives you everything you need here. Adaptive bitrate, a configurable LoadControl , player listeners. The catch is that the defaults are tuned for general media, not for a 40-minute lecture on a bad link. What moved the numbers for us: Bigger buffers, deliberately. DefaultLoadControl.Builder().setBufferDurationsMs(...) takes a min buffer, a max buffer, the buffer needed to start playback, and the buffer needed to resume after a rebuffer. That last parameter is the interesting one. Raising it costs you a little extra time on resume and buys you far fewer repeat stalls, because the player stops trying to restart on a nearly empty buffer. Telling the user the truth. Our first version showed a spinner and nothing else. A spinner with no context reads as "the app is frozen," so students force-closed and reopened, which threw away the buffer and made everything worse. Saying "reconnecting" instead of spinning silently cut t

2026-09-05 原文 →
AI 资讯

Dealing with sensitive permissions on Android

Right now the developer community seems fascinated (if not outright obsessed) with agentic coding. That wave is real, and it will heavily impact how we build software. But let's not forget there are other topics worth attention. Here, the focus is something less fashionable: sensitive permissions on Android. After shipping TKWeek updates outside Google Play and answering the inevitable Why isn't this on the Play Store? with a blunt Sensitive permissions , it is fair to ask whether that topic still matters in 2026. I can answer that from shipping one app for a long time. I started working on TKWeek back in 2010. Some time later I added a module called My day that shows important information for a particular day, including missed phone calls. READ_CALL_LOG is a dangerous permission since API level 23, so users who do not want to allow the app to read those details have a secure, reliable safety hatch. Still, after a late-2018 announcement, by 2019 Google Play was enforcing READ_CALL_LOG under its high-risk / sensitive rules. Now, what does that store layer mean anyway? Dangerous on the device, sensitive in the store On the platform side, Android already classifies quite a few permissions as dangerous : they guard private user data, and starting with API 23 the user must grant them at runtime. READ_CALL_LOG is in that bucket ( Manifest.permission.READ_CALL_LOG ). Google Play's extra layer sits on top of that. In Play docs the umbrella is high-risk or sensitive permissions; Call Log and SMS are restricted permission groups. Either way, it is store policy, not just OS protection. For Call Log and SMS, only narrow use cases are allowed (typically default Phone, SMS, or Assistant handlers, plus a short list of exceptions), and you must declare them in Play Console or remove them from the manifest. See Google's Permissions and APIs that Access Sensitive Information and Use of SMS or Call Log permission groups . Back in 2021 that policy stopped being theoretical. Showing mis

2026-09-05 原文 →
AI 资讯

The message that mentioned finance and tagged nobody

Somebody types "can we loop in finance on this?" in a product channel. Nobody tags the finance channel. The thread moves on. Three weeks later there is a contract nobody in finance has seen. That is not a tooling problem in any obvious sense. Slack worked exactly as designed. Search would have found the message if anyone had known to look for it. The failure is that the people who needed to know were never told, and nothing in the workspace was watching for the difference between mentioning a team and involving one. Why keyword matching does not solve this The instinct is to grep for the word "finance" and alert on it. That produces a channel nobody reads inside a week, because "finance" appears in sentences that have nothing to do with governance, and the sentences that do matter often do not contain the word at all. What actually carries the signal is structure. A Slack message is not plain text on the wire. When someone references a channel, it arrives looking like this: Can we loop in <#C01ABCDEF|finance> before this goes out? That is a channel reference , distinct from a mention that notifies the channel, and it survives in the event payload whether or not anyone was actually alerted. It means the workspace already knows the difference between "I said the word finance" and "I pointed at the finance channel and did not bring anyone in". Nobody was reading it. So the bot parses references rather than words. It maps channel IDs to what those channels are for, and it looks for the specific shape of a message that points at a governance channel from outside it. Context beats keywords, and in this case the context was already structured and already being thrown away. Two decisions that mattered more than the detection It joins every public channel by itself. The obvious build asks an admin to add the bot wherever it should watch, which means coverage is a function of somebody remembering. Every channel created after launch is a gap, and nobody finds out until somethi

2026-09-05 原文 →
工具

Redefining GIS: Declarative Symbology and Collaborative Workflows in JupyterGIS

JupyterGIS is a GIS-focused extension for Jupyter notebooks. The recent 0.16 release enhances collaborative features, real-time editing, and support for large-scale data processing, including remote sensing. It introduces better visualisation tools and extends compatibility to R users. Community feedback highlights practical concerns and a desire for improved portability. By Olimpiu Pop

2026-09-05 原文 →
AI 资讯

C# Concurrent Collections: A Practical Guide

Choosing a thread-safe collection is not simply a matter of replacing Dictionary<TKey, TValue> with ConcurrentDictionary<TKey, TValue> . The right choice depends on the operations you need to make atomic, the ratio of reads to writes, whether consumers must block, and whether the data can become immutable after construction. This guide explains how ordinary generic collections fail under concurrent access, then compares the main types in System.Collections.Concurrent with immutable and frozen collections. The goal is to give you enough mechanical detail to defend the choice in code review—not just a catalog of APIs. C# Concurrent Collections: Quick Selection Guide Requirement Start with Concurrent FIFO processing ConcurrentQueue<T> Concurrent LIFO processing ConcurrentStack<T> Concurrent key-based reads and updates ConcurrentDictionary<TKey, TValue> Unordered items produced and consumed by the same workers ConcurrentBag<T> Blocking or bounded producer-consumer flow BlockingCollection<T> Snapshot-style updates System.Collections.Immutable Build-once, read-many lookup data System.Collections.Frozen The table is a starting point, not a substitute for checking which compound operations must be atomic. The sections below explain the mechanics and tradeoffs behind each choice. Why C# Needs Thread-Safe Collections C# 1.0 introduced System.Collections , which includes ArrayList , Hashtable , Stack , Queue , and other collection classes. The problem is that these collections are not type-safe. They store elements as object , which can lead to type-mismatch exceptions and to performance costs from boxing and unboxing. C# 2.0 then introduced the System.Collections.Generic namespace and collection classes such as List<T> , Dictionary<TKey, TValue> , Stack<T> , and Queue<T> . These collections are type-safe, but not thread-safe. Type safety means that when you create a generic collection, you specify the type it stores as a generic type parameter. Reading an element then returns

2026-09-05 原文 →
AI 资讯

Architecting Enterprise Angular with Signals: Zoneless Reactivity and 60fps Performance

Architecting Enterprise Angular with Signals: Zoneless Reactivity and 60fps Performance For nearly a decade, Angular relied on Zone.js to intercept asynchronous browser events and trigger top-down dirty checking across the entire component tree. In large enterprise dashboards displaying live telemetry, grid streams, and complex forms, this model leads directly to frame drops and memory leaks. With Angular 19+, fine-grained Signals provide a reactive paradigm where the framework tracks exact DOM dependencies at compile-time and updates only the precise DOM nodes that changed, unlocking 60fps zoneless execution . Architecture & Interview Cheat Sheet Feature Legacy RxJS / Zone.js Angular Signals (Modern) Change Detection Dirty-checks entire component tree Fine-grained single DOM node updates Memory Lifecycle Manual takeUntilDestroyed subscriptions Automatic graph cleanup without memory leaks Derivations Complex combineLatest / switchMap Lazy, memoized computed(() => ...) Zone.js Overhead Monkey-patches all browser async APIs 0 overhead ( provideExperimentalZonelessChangeDetection() ) 1: Clean Reactive State with Signals import { Component , computed , signal , effect , inject } from ' @angular/core ' ; export interface TelemetryPacket { id : string ; latencyMs : number ; status : ' healthy ' | ' degraded ' | ' critical ' ; } @ Component ({ selector : ' app-telemetry-monitor ' , standalone : true , template : ` <div class="card"> <h3>Live Ingestion Monitor</h3> <p>Total Packets: {{ packetCount() }}</p> <p>Average Latency: {{ averageLatency().toFixed(2) }}ms</p> <span [class.badge-warn]="isDegraded()"> {{ isDegraded() ? 'DEGRADED PERFORMANCE' : 'NOMINAL' }} </span> </div> ` }) export class TelemetryMonitorComponent { // Primary Writable Signal readonly packets = signal < TelemetryPacket [] > ([]); // Derived Computed Signals (Memoized, evaluated lazily on read) readonly packetCount = computed (() => this . packets (). length ); readonly averageLatency = computed (() => {

2026-09-05 原文 →
AI 资讯

How AI changed the way I build software, and why I ended up building an open source shell for Angular

Up front: this is my own project, so I'm not exactly neutral here ;-) Where I'm coming from I work completely differently than I did two or three years ago. For most of my career I wanted to write pretty much every line myself, and I was a bit proud of that. That has changed a lot. Instead of programming I now mostly write specifications and review what the AI generates. On the one hand that's great, I can turn new ideas into working software much faster than before. On the other hand there's the risk of stepping into the same traps with AI-generated code again and again. And that's where I noticed something. Every time I started a new project, I found myself explaining the same things to the AI. This goes into a plugin. That stays out of the core. No domain logic in the shell. Please don't invent a third way of doing tabs. The AI would nod, generate something that looked right, and two days later I'd find a slightly different version of the same sidebar with a slightly different bug. There are things I really don't want to explain over and over. A good, preferably deterministic base is getting more important, not less. I don't want to explain proven architectures from scratch every time. I'd rather build on established solutions where I can, ones the AI understands and can just use. So for my new projects I built exactly that, and put it on GitHub as open source. Why Angular? Well, simply because I think it's a great framework and I've had a lot of good experiences with it over the last 10 years. What it is, and what it isn't LoomWeaver is a workbench shell for Angular. Not a component library. Think of the frame VS Code gives you: a rail on the left, sidebars, a top bar, a status bar, and in the middle tabs and panes you can split and drag around. That frame is what most workbench-style products build themselves, every time, slightly differently. LoomWeaver gives you that frame, and your own domain moves in as plugins. The core contains zero domain logic. Even my

2026-09-04 原文 →
AI 资讯

Tableau Aliases: Rename What Readers See Without Touching the Data

By Michael Nocito , data analyst · Published August 9, 2026 By the end of this page you can turn a chart that says E, W, N and S into one that says East, West, North and South, in about thirty seconds, without editing the data or writing a calculation. You'll also know exactly why the Aliases option is missing on some fields, which is the part that sends people looking for a workaround they don't need. It's about ten minutes. Here's the move. Right-click a dimension in the Data pane, choose Aliases, and type the name you want beside each value. The chart updates, the stored data doesn't change, and every view built on that field picks up the new labels. The short version: an alias renames the members of a discrete dimension. Only discrete dimensions have members, which is why measures, dates and continuous dimensions can't have one. An alias sits in a specific place, between what's stored and what's shown, and that placement explains everything else here. So it gets the picture. The original carries a diagram here. In words: Three stacked panels connected left to right. The left panel is labeled stored and holds four small cells reading E, W, N and S. The middle panel is a narrow vertical band labeled alias, holding four arrows. The right panel is labeled shown and holds four cells reading East, West, North and South. A solid arrow runs from the stored panel through the alias band to the shown panel, indicating the direction labels travel. A second arrow attempting to run backwards from the shown panel to the stored panel is crossed through with a heavy X, showing that renaming the label never changes the stored value. The stored cells still read E, W, N and S after the change. This is on the certification. Aliases sit in Section 2, Exploring and Analyzing Data, which is 37% of the Tableau Desktop Foundations exam and the largest section on it. The questions people get wrong are almost always about which field types accept an alias, which is section 2 below. 1. What

2026-09-04 原文 →