android int转float_记录Android开发中遇到的问题

6b72e8658b93c717b28f4c98e432e05c.png

1. WebView的WebViewClient请求网络图标失败导致404,引起加载空白页

在使用WebView加载网页的时候,在网页加载失败的时候我可能需要做一些处理,比如加载自己指定的错误页面等。 所以我们需要重写 android.webkit.WebViewClient#onReceivedHttpError 但是我发现加载我写的一个简单页面也会出现白屏,会退一下返回栈才能正常显示。这就很奇怪了,页面非常简单不太可能出错, 而且也没有跳转和重定向,最后找了很久才知道定位到问题。

@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
    super.onReceivedHttpError(view, request, errorResponse);
    log.info("onReceivedHttpError " + request.toString() + " " + errorResponse.getStatusCode());
    int statusCode = errorResponse.getStatusCode();
    if (404 == statusCode || 500 == statusCode) {
        //view.loadUrl("about:blank");// 避免出现默认的错误界面
        // view.loadUrl("");
    }
    log.info("errorResponse:" + errorResponse.getData());
}

在加载网页的时候,安卓会加载 favicon.ico 图标,而一些小的网页和网站可能就没有配置,所以这就解释了为什么我写的简单页面不能这正常加载。

我现在不对错误进行处理。 可以参考

2. BottomNavigationView 长按出现Toast影响美观

在使用 com.google.android.material.bottomnavigation.BottomNavigationView 显示底部导航栏时,长按item会出现标题,产品觉得影响美观所以需要去掉

BottomNavigationView bottomNavigationView = getBinding().bottomNavigationView;
    List<Integer> ids = Arrays.asList(...);
    ViewGroup bottomNavigationMenuView = (ViewGroup) bottomNavigationView.getChildAt(0);
    for (int i = 0; i < ids.size(); i++) {
        bottomNavigationMenuView.getChildAt(i).findViewById(ids.get(i)).setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return true;
            }
        });
    }

大家可以通过阅读源码为什么长按事件之后就能不显示Toast

可以从 com.google.android.material.bottomnavigation.BottomNavigationItemView#initialize 

然后一步步 就会找到 android.view.View#showLongClickTooltip 方法


最后揭露迷底

/**
    * Calls this view's OnLongClickListener, if it is defined. Invokes the
    * context menu if the OnLongClickListener did not consume the event,
    * optionally anchoring it to an (x,y) coordinate. 

    调用此视图的OnLongClickListener(如果已定义)。 
    如果OnLongClickListener没有使用事件,则调用上下文菜单,可以选择将其锚定到(x,y)坐标。
    *
    * @param x x coordinate of the anchoring touch event, or {@link Float#NaN}
    *          to disable anchoring
    * @param y y coordinate of the anchoring touch event, or {@link Float#NaN}
    *          to disable anchoring
    * @return {@code true} if one of the above receivers consumed the event,
    *         {@code false} otherwise
    */
private boolean performLongClickInternal(float x, float y) {
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);

    boolean handled = false;
    final ListenerInfo li = mListenerInfo;
    if (li != null && li.mOnLongClickListener != null) {
        // 关键就在于这里,长按事件返回的ture
        handled = li.mOnLongClickListener.onLongClick(View.this);
    }
    if (!handled) {
        final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y);
        handled = isAnchored ? showContextMenu(x, y) : showContextMenu();
    }
    if ((mViewFlags & TOOLTIP) == TOOLTIP) {
        if (!handled) {
            // 显示toast
            handled = showLongClickTooltip((int) x, (int) y);
        }
    }
    if (handled) {
        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    }
    return handled;
}

3. Android O JobIntentService的SecurityException问题解决办法

场景:当日志文件大于设定的文件大小则启动后台服务上传应用日志到后台,或者产生闪退立即上传日志

如何产生错误:在Android 8.0以上的设备,同一时间段启动相同JOB_ID的服务就会出现安全异常(一个服务只能有一个JOB_ID

错误详情如下:(这个错误信息是我拷贝的网上其他的,并不是我机器上的。)

[2020-12-31 13:45:30 041][GlobalExceptionHelper]: android.os.RemoteException: Remote stack trace:
    at com.android.server.job.JobServiceContext.assertCallerLocked(libmapleservices.so:4784420)
    at com.android.server.job.JobServiceContext.doDequeueWork(libmapleservices.so:4677844)
    at com.android.server.job.JobServiceContext$JobCallback.dequeueWork(libmapleservices.so:4680440)
    at android.app.job.IJobCallback$Stub.onTransact(libmapleframework.so:3676756)
    at android.os.Binder.execTransactInternal(libmapleframework.so:5532620)

    at com.android.server.job.JobServiceContext.assertCallerLocked(libmapleservices.so:4784420)
    at com.android.server.job.JobServiceContext.doDequeueWork(libmapleservices.so:4677844)
    at com.android.server.job.JobServiceContext$JobCallback.dequeueWork(libmapleservices.so:4680440)
    at android.app.job.IJobCallback$Stub.onTransact(libmapleframework.so:3676756)
    at android.os.Binder.execTransactInternal(libmapleframework.so:5532620)
 Caused by: java.lang.SecurityException: Caller no longer running, last stopped +525ms because: timed out while starting
    at android.os.Parcel.createException(Parcel.java:2071)
    at android.os.Parcel.readException(Parcel.java:2039)
    at android.os.Parcel.readException(Parcel.java:1987)
    at android.app.job.IJobCallback$Stub$Proxy.dequeueWork(IJobCallback.java:292)
    at android.app.job.JobParameters.dequeueWork(JobParameters.java:248)
    at androidx.core.app.JobIntentService$JobServiceEngineImpl.dequeueWork(JobIntentService.java:315)
    at androidx.core.app.JobIntentService.dequeueWork(JobIntentService.java:640)
    at androidx.core.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:390)
    at androidx.core.app.JobIntentService$CommandProcessor.doInBackground(JobIntentService.java:383)
    at android.os.AsyncTask$3.call(AsyncTask.java:389)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 Caused by: java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$AsyncFutureTask.done(AsyncTask.java:429)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:929)

这个问题在google IssueTracker 上也有追踪 isccies 63622293

因为没有直接的方法可以解决这个问题。并且我们已经知道了问题产生的原因,所以我们可以避免发生这样的情况,或者寻找可以满足当前情景的方案。

我目前想到的方案有如下两种

第一个可行的方案是用IntentService 再做兼容,老方法,我不准备采用

第二个可以的方案是用Jetpack WorkManager, 虽然它不能保证服务立即被执行,但是可以不丢失服务,满足我的需要。新的方法,而且比较灵活,后面有更多去求也可以满足,所以我选择这个方案。我并非喜新厌旧之人。


如果应用没有使用AndroidX,可以通过重写v4下的JobIntentService#dequeueWork

package android.support.v4.app;

import timber.log.Timber;

public abstract class MyJobIntentService extends JobIntentService {   

    @Override

    GenericWorkItem dequeueWork() { 
        try {
            return super.dequeueWork();
        } catch (SecurityException ignored) {
            Timber.e(ignored);
        }    
        return null;
    }
}

PS: 上面方法我并没有在自己应用验证过。

如果应用中使用AndroidX则不适用上述方法,我这里用Jetpack WorkManager

引入WorkManager api 'androidx.work:work-runtime:2.4.0',然后初始化 WorkManager.getInstance(this); 注意Application需要实现 androidx.work.Configuration.Provider#getWorkManagerConfiguration 接口

@Log
public class LogUploadService extends Worker{// 继承 androidx.work.Worker

    public LogUploadService(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    public static void startWork(){
        // 启动一次性任务
        OneTimeWorkRequest.Builder builder = new OneTimeWorkRequest.Builder(LogUploadService.class);
        // 传递参数
        Data data = new Data.Builder().putString("action", intent.getAction())
                .build();
        builder.setInputData(data);
        // 提交任务
        WorkManager.getInstance(context)
                .enqueue(builder.build());
    }

    private void uploadLogFile(Intent intent){
        // 上传日志相关业务
    }

    @NonNull
    @Override
    public Result doWork() {// 重写 androidx.work.Worker#doWork
        try {
            // 因为我在应用通过startWork()启动任务,所以这里不会为空
            String action = getInputData().getString("action");
            uploadLogFile(new Intent(action));
        } catch (Exception e) {
            log.severe(ThrowableUtils.getFullStackTrace(e));
            return Result.failure();
        }
        // 这里的返回值很重要
        // 可以在 androidx.work.ListenableWorker.Result 中看到还有个
        // androidx.work.ListenableWorker.Result#retry 方法 
        // 上面异常处理中也有个 androidx.work.ListenableWorker.Result#failure()

        // 这里拷贝下Result类的注释(我英文水平不太好,没办法准确翻译,为避免误导,请自行理解)

        /**
        * The result of a {@link ListenableWorker}'s computation. Call {@link #success()},
        * {@link #failure()}, or {@link #retry()} or one of their variants to generate an object
        * indicating what happened in your background work.
        */

        return Result.success();
    }
}

Jetpack WorkManager不能保证服务立即被执行,但是可以保证服务一定不丢失。它本身有数据库记录服务

经测试,该替代方案,暂时没问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值