(一百七十五)Android P registerNetworkCallback

2023-12-19 07:32

本文主要是介绍(一百七十五)Android P registerNetworkCallback,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. API

ConnectivityManager的api,用来接收满足NetworkRequest的所有网络通知,除非应用退出或者调用了

    /*** Registers to receive notifications about all networks which satisfy the given* {@link NetworkRequest}.  The callbacks will continue to be called until* either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.** @param request {@link NetworkRequest} describing this request.* @param networkCallback The {@link NetworkCallback} that the system will call as suitable*                        networks change state.*                        The callback is invoked on the default internal Handler.*/@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {registerNetworkCallback(request, networkCallback, getDefaultHandler());}/*** Registers to receive notifications about all networks which satisfy the given* {@link NetworkRequest}.  The callbacks will continue to be called until* either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.** @param request {@link NetworkRequest} describing this request.* @param networkCallback The {@link NetworkCallback} that the system will call as suitable*                        networks change state.* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.*/@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback, Handler handler) {CallbackHandler cbHandler = new CallbackHandler(handler);NetworkCapabilities nc = request.networkCapabilities;sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);}

NetworkCallback就是个回调,应用可以复写用来实现自己的逻辑

    /*** Base class for {@code NetworkRequest} callbacks. Used for notifications about network* changes. Should be extended by applications wanting notifications.** A {@code NetworkCallback} is registered by calling* {@link #requestNetwork(NetworkRequest, NetworkCallback)},* {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},* or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is* unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.* A {@code NetworkCallback} should be registered at most once at any time.* A {@code NetworkCallback} that has been unregistered can be registered again.*/public static class NetworkCallback {

 

2. 梳理流程

    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,int timeoutMs, int action, int legacyType, CallbackHandler handler) {checkCallbackNotNull(callback);Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");final NetworkRequest request;try {synchronized(sCallbacks) {if (callback.networkRequest != null&& callback.networkRequest != ALREADY_UNREGISTERED) {// TODO: throw exception instead and enforce 1:1 mapping of callbacks// and requests (http://b/20701525).Log.e(TAG, "NetworkCallback was already registered");}Messenger messenger = new Messenger(handler);Binder binder = new Binder();if (action == LISTEN) {request = mService.listenForNetwork(need, messenger, binder);} else {request = mService.requestNetwork(need, messenger, timeoutMs, binder, legacyType);}if (request != null) {sCallbacks.put(request, callback);}callback.networkRequest = request;}} catch (RemoteException e) {throw e.rethrowFromSystemServer();} catch (ServiceSpecificException e) {throw convertServiceException(e);}return request;}

继而调用到了ConnectivityService

   @Overridepublic NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,Messenger messenger, IBinder binder) {if (!hasWifiNetworkListenPermission(networkCapabilities)) {enforceAccessPermission();}NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);ensureSufficientPermissionsForRequest(networkCapabilities,Binder.getCallingPid(), Binder.getCallingUid());restrictRequestUidsForCaller(nc);// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get// onLost and onAvailable callbacks when networks move in and out of the background.// There is no need to do this for requests because an app without CHANGE_NETWORK_STATE// can't request networks.restrictBackgroundRequestForCaller(nc);ensureValidNetworkSpecifier(nc);NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),NetworkRequest.Type.LISTEN);NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder);if (VDBG) log("listenForNetwork for " + nri);mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));return networkRequest;}

继而发出一个消息并处理

    private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {mNetworkRequests.put(nri.request, nri);mNetworkRequestInfoLogs.log("REGISTER " + nri);if (nri.request.isListen()) {for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {if (nri.request.networkCapabilities.hasSignalStrength() &&network.satisfiesImmutableCapabilitiesOf(nri.request)) {updateSignalStrengthThresholds(network, "REGISTER", nri.request);}}}rematchAllNetworksAndRequests(null, 0);if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {sendUpdatedScoreToFactories(nri.request, 0);}}

特殊判断的先不看,看下rematchAllNetworksAndRequests

    /*** Attempt to rematch all Networks with NetworkRequests.  This may result in Networks* being disconnected.* @param changed If only one Network's score or capabilities have been modified since the last*         time this function was called, pass this Network in this argument, otherwise pass*         null.* @param oldScore If only one Network has been changed but its NetworkCapabilities have not*         changed, pass in the Network's score (from getCurrentScore()) prior to the change via*         this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if*         {@code changed} is {@code null}. This is because NetworkCapabilities influence a*         network's score.*/private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {// TODO: This may get slow.  The "changed" parameter is provided for future optimization// to avoid the slowness.  It is not simply enough to process just "changed", for// example in the case where "changed"'s score decreases and another network should begin// satifying a NetworkRequest that "changed" currently satisfies.// Optimization: Only reprocess "changed" if its score improved.  This is safe because it// can only add more NetworkRequests satisfied by "changed", and this is exactly what// rematchNetworkAndRequests() handles.final long now = SystemClock.elapsedRealtime();if (changed != null && oldScore < changed.getCurrentScore()) {rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now);} else {final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray(new NetworkAgentInfo[mNetworkAgentInfos.size()]);// Rematch higher scoring networks first to prevent requests first matching a lower// scoring network and then a higher scoring network, which could produce multiple// callbacks and inadvertently unlinger networks.Arrays.sort(nais);for (NetworkAgentInfo nai : nais) {rematchNetworkAndRequests(nai,// Only reap the last time through the loop.  Reaping before all rematching// is complete could incorrectly teardown a network that hasn't yet been// rematched.(nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP: ReapUnvalidatedNetworks.REAP,now);}}}

传来的changed为null,所以走下面的判断,其实都是走一个方法rematchNetworkAndRequests

    // Handles a network appearing or improving its score.//// - Evaluates all current NetworkRequests that can be//   satisfied by newNetwork, and reassigns to newNetwork//   any such requests for which newNetwork is the best.//// - Lingers any validated Networks that as a result are no longer//   needed. A network is needed if it is the best network for//   one or more NetworkRequests, or if it is a VPN.//// - Tears down newNetwork if it just became validated//   but turns out to be unneeded.//// - If reapUnvalidatedNetworks==REAP, tears down unvalidated//   networks that have no chance (i.e. even if validated)//   of becoming the highest scoring network.//// NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy,// it does not remove NetworkRequests that other Networks could better satisfy.// If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}.// This function should be used when possible instead of {@code rematchAllNetworksAndRequests}// as it performs better by a factor of the number of Networks.//// @param newNetwork is the network to be matched against NetworkRequests.// @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be//               performed to tear down unvalidated networks that have no chance (i.e. even if//               validated) of becoming the highest scoring network.private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork,ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) {if (!newNetwork.everConnected) return;boolean keep = newNetwork.isVPN();boolean isNewDefault = false;NetworkAgentInfo oldDefaultNetwork = null;final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork();final int score = newNetwork.getCurrentScore();if (VDBG) log("rematching " + newNetwork.name());// Find and migrate to this Network any NetworkRequests for// which this network is now the best.ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();NetworkCapabilities nc = newNetwork.networkCapabilities;if (VDBG) log(" network has: " + nc);for (NetworkRequestInfo nri : mNetworkRequests.values()) {// Process requests in the first pass and listens in the second pass. This allows us to// change a network's capabilities depending on which requests it has. This is only// correct if the change in capabilities doesn't affect whether the network satisfies// requests or not, and doesn't affect the network's score.if (nri.request.isListen()) continue;final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);final boolean satisfies = newNetwork.satisfies(nri.request);if (newNetwork == currentNetwork && satisfies) {if (VDBG) {log("Network " + newNetwork.name() + " was already satisfying" +" request " + nri.request.requestId + ". No change.");}keep = true;continue;}// check if it satisfies the NetworkCapabilitiesif (VDBG) log("  checking if request is satisfied: " + nri.request);if (satisfies) {// next check if it's better than any current network we're using for// this requestif (VDBG) {log("currentScore = " +(currentNetwork != null ? currentNetwork.getCurrentScore() : 0) +", newScore = " + score);}if (currentNetwork == null || currentNetwork.getCurrentScore() < score) {if (VDBG) log("rematch for " + newNetwork.name());if (currentNetwork != null) {if (VDBG) log("   accepting network in place of " + currentNetwork.name());currentNetwork.removeRequest(nri.request.requestId);currentNetwork.lingerRequest(nri.request, now, mLingerDelayMs);affectedNetworks.add(currentNetwork);} else {if (VDBG) log("   accepting network in place of null");}newNetwork.unlingerRequest(nri.request);setNetworkForRequest(nri.request.requestId, newNetwork);if (!newNetwork.addRequest(nri.request)) {Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);}addedRequests.add(nri);keep = true;// Tell NetworkFactories about the new score, so they can stop// trying to connect if they know they cannot match it.// TODO - this could get expensive if we have alot of requests for this// network.  Think about if there is a way to reduce this.  Push// netid->request mapping to each factory?sendUpdatedScoreToFactories(nri.request, score);if (isDefaultRequest(nri)) {isNewDefault = true;oldDefaultNetwork = currentNetwork;if (currentNetwork != null) {mLingerMonitor.noteLingerDefaultNetwork(currentNetwork, newNetwork);}}}} else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",// mark it as no longer satisfying "nri".  Because networks are processed by// rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will// match "newNetwork" before this loop will encounter a "currentNetwork" with higher// score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".// This means this code doesn't have to handle the case where "currentNetwork" no// longer satisfies "nri" when "currentNetwork" does not equal "newNetwork".if (DBG) {log("Network " + newNetwork.name() + " stopped satisfying" +" request " + nri.request.requestId);}newNetwork.removeRequest(nri.request.requestId);if (currentNetwork == newNetwork) {clearNetworkForRequest(nri.request.requestId);sendUpdatedScoreToFactories(nri.request, 0);} else {Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +newNetwork.name() +" without updating mNetworkForRequestId or factories!");}// TODO: Technically, sending CALLBACK_LOST here is// incorrect if there is a replacement network currently// connected that can satisfy nri, which is a request// (not a listen). However, the only capability that can both// a) be requested and b) change is NET_CAPABILITY_TRUSTED,// so this code is only incorrect for a network that loses// the TRUSTED capability, which is a rare case.callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);}}if (isNewDefault) {// Notify system services that this network is up.makeDefault(newNetwork);// Log 0 -> X and Y -> X default network transitions, where X is the new default.metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, newNetwork, oldDefaultNetwork);// Have a new default network, release the transition wakelock inscheduleReleaseNetworkTransitionWakelock();}if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {Slog.wtf(TAG, String.format("BUG: %s changed requestable capabilities during rematch: %s -> %s",newNetwork.name(), nc, newNetwork.networkCapabilities));}if (newNetwork.getCurrentScore() != score) {Slog.wtf(TAG, String.format("BUG: %s changed score during rematch: %d -> %d",newNetwork.name(), score, newNetwork.getCurrentScore()));}// Second pass: process all listens.if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {// If the network went from background to foreground or vice versa, we need to update// its foreground state. It is safe to do this after rematching the requests because// NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable// capability and does not affect the network's score (see the Slog.wtf call above).updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);} else {processListenRequests(newNetwork, false);}// do this after the default net is switched, but// before LegacyTypeTracker sends legacy broadcastsfor (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);// Linger any networks that are no longer needed. This should be done after sending the// available callback for newNetwork.for (NetworkAgentInfo nai : affectedNetworks) {updateLingerState(nai, now);}// Possibly unlinger newNetwork. Unlingering a network does not send any callbacks so it// does not need to be done in any particular order.updateLingerState(newNetwork, now);if (isNewDefault) {// Maintain the illusion: since the legacy API only// understands one network at a time, we must pretend// that the current default network disconnected before// the new one connected.if (oldDefaultNetwork != null) {mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),oldDefaultNetwork, true);}mDefaultInetConditionPublished = newNetwork.lastValidated ? 100 : 0;mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork);notifyLockdownVpn(newNetwork);}if (keep) {// Notify battery stats service about this network, both the normal// interface and any stacked links.// TODO: Avoid redoing this; this must only be done once when a network comes online.try {final IBatteryStats bs = BatteryStatsService.getService();final int type = newNetwork.networkInfo.getType();final String baseIface = newNetwork.linkProperties.getInterfaceName();bs.noteNetworkInterfaceType(baseIface, type);for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) {final String stackedIface = stacked.getInterfaceName();bs.noteNetworkInterfaceType(stackedIface, type);}} catch (RemoteException ignored) {}// This has to happen after the notifyNetworkCallbacks as that tickles each// ConnectivityManager instance so that legacy requests correctly bind dns// requests to this network.  The legacy users are listening for this bcast// and will generally do a dns request so they can ensureRouteToHost and if// they do that before the callbacks happen they'll use the default network.//// TODO: Is there still a race here? We send the broadcast// after sending the callback, but if the app can receive the// broadcast before the callback, it might still break.//// This *does* introduce a race where if the user uses the new api// (notification callbacks) and then uses the old api (getNetworkInfo(type))// they may get old info.  Reverse this after the old startUsing api is removed.// This is on top of the multiple intent sequencing referenced in the todo above.for (int i = 0; i < newNetwork.numNetworkRequests(); i++) {NetworkRequest nr = newNetwork.requestAt(i);if (nr.legacyType != TYPE_NONE && nr.isRequest()) {// legacy type tracker filters out repeat addsmLegacyTypeTracker.add(nr.legacyType, newNetwork);}}// A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,// because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest// wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the// newNetwork to the tracker explicitly (it's a no-op if it has already been added).if (newNetwork.isVPN()) {mLegacyTypeTracker.add(TYPE_VPN, newNetwork);}}if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) {for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {if (unneeded(nai, UnneededFor.TEARDOWN)) {if (nai.getLingerExpiry() > 0) {// This network has active linger timers and no requests, but is not// lingering. Linger it.//// One way (the only way?) this can happen if this network is unvalidated// and became unneeded due to another network improving its score to the// point where this network will no longer be able to satisfy any requests// even if it validates.updateLingerState(nai, now);} else {if (DBG) log("Reaping " + nai.name());teardownUnneededNetwork(nai);}}}}}

一大摞的代码看到不是很懂,大概意思是

check if it satisfies the NetworkCapabilities,大概就是比较下现有网络和新网络哪个分高,新网络分高的话更新一下

Second pass: process all listens.

其实这是比较想关注的,大概就是网络更新了通知一下

        // Second pass: process all listens.if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {// If the network went from background to foreground or vice versa, we need to update// its foreground state. It is safe to do this after rematching the requests because// NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable// capability and does not affect the network's score (see the Slog.wtf call above).updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);} else {processListenRequests(newNetwork, false);}// do this after the default net is switched, but// before LegacyTypeTracker sends legacy broadcastsfor (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);

看下processListenRequests(这里比较牵强,debug 新网络连接会走这里)

    private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) {// For consistency with previous behaviour, send onLost callbacks before onAvailable.for (NetworkRequestInfo nri : mNetworkRequests.values()) {NetworkRequest nr = nri.request;if (!nr.isListen()) continue;if (nai.isSatisfyingRequest(nr.requestId) && !nai.satisfies(nr)) {nai.removeRequest(nri.request.requestId);callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_LOST, 0);}}if (capabilitiesChanged) {notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);}for (NetworkRequestInfo nri : mNetworkRequests.values()) {NetworkRequest nr = nri.request;if (!nr.isListen()) continue;if (nai.satisfies(nr) && !nai.isSatisfyingRequest(nr.requestId)) {nai.addRequest(nr);notifyNetworkAvailable(nai, nri);}}}

这个和我们的registerNetworkCallback有些相关,都是listen状态,大概就是网络变了调用更新一下监听器

    // Notify only this one new request of the current state. Transfer all the// current state by calling NetworkCapabilities and LinkProperties callbacks// so that callers can be guaranteed to have as close to atomicity in state// transfer as can be supported by this current API.protected void notifyNetworkAvailable(NetworkAgentInfo nai, NetworkRequestInfo nri) {mHandler.removeMessages(EVENT_TIMEOUT_NETWORK_REQUEST, nri);if (nri.mPendingIntent != null) {sendPendingIntentForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE);// Attempt no subsequent state pushes where intents are involved.return;}callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, 0);}private void callCallbackForRequest(NetworkRequestInfo nri,NetworkAgentInfo networkAgent, int notificationType, int arg1) {if (nri.messenger == null) {return;  // Default request has no msgr}Bundle bundle = new Bundle();// TODO: check if defensive copies of data is needed.putParcelable(bundle, new NetworkRequest(nri.request));Message msg = Message.obtain();if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {putParcelable(bundle, networkAgent.network);}switch (notificationType) {case ConnectivityManager.CALLBACK_AVAILABLE: {putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));break;}case ConnectivityManager.CALLBACK_LOSING: {msg.arg1 = arg1;break;}case ConnectivityManager.CALLBACK_CAP_CHANGED: {// networkAgent can't be null as it has been accessed a few lines above.final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(networkAgent.networkCapabilities, nri.mPid, nri.mUid);putParcelable(bundle, nc);break;}case ConnectivityManager.CALLBACK_IP_CHANGED: {putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));break;}}msg.what = notificationType;msg.setData(bundle);try {if (VDBG) {String notification = ConnectivityManager.getCallbackName(notificationType);log("sending notification " + notification + " for " + nri.request);}nri.messenger.send(msg);} catch (RemoteException e) {// may occur naturally in the race of binder death.loge("RemoteException caught trying to send a callback msg for " + nri.request);}}

看下ConnectivityManager对CALLBACK_AVAILABLE的处理,其实就是回调了下callback的onAvailable

                case CALLBACK_AVAILABLE: {NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);LinkProperties lp = getObject(message, LinkProperties.class);callback.onAvailable(network, cap, lp);break;}

 

2.总结

调试发现新网络的建立和断开也会走下面红框框出来的流程,即网络状态发生变化了会走如下流程,结合之前WiFi连接上的经验猜是updateNetworkInfo调用到的,因为WiFi连接上了之后会把networkInfo更新到CS这边,后续debug看下

 

这篇关于(一百七十五)Android P registerNetworkCallback的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511369

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到

android系统源码12 修改默认桌面壁纸--SRO方式

1、aosp12修改默认桌面壁纸 代码路径 :frameworks\base\core\res\res\drawable-nodpi 替换成自己的图片即可,不过需要覆盖所有目录下的图片。 由于是静态修改,则需要make一下,重新编译。 2、方法二Overlay方式 由于上述方法有很大缺点,修改多了之后容易遗忘自己修改哪些文件,为此我们采用另外一种方法,使用Overlay方式。