美文网首页
StudentAgency项目开发遇到的问题

StudentAgency项目开发遇到的问题

作者: LongSh1z | 来源:发表于2020-02-27 20:26 被阅读0次

    本文收集了项目开发中遇到的大大小小的问题,主要目的也是方便以后的开发能够别踩那么多的坑、提高开发效率。

    一、Glide裁剪成圆形图片

    使用Glide自带的功能即可

    RequestOptions requestOptions = RequestOptions.circleCropTransform();
    Glide.with(getActivity())
             .load(resId)
             .placeholder(R.drawable.placeholder_pic)
             .apply(requestOptions)//重点是这一句
             .into(iv_avatar);
    

    二、Resources中的getColor(int)已过时

    替换成ContextCompat.getColor(Context,R.color.colorAccent);

    //例如
    iv_avatar_bg.setBackgroundColor(ContextCompat.getColor(getActivity(),R.color.themeColor));
    

    三、动态申请权限时,onRequestPermissionsResult未被回调

    动态申请权限时,我们要注意动态申请权限的地方在哪里。这里的地方指的是Activity或者是Fragment
    如果是Activity:申请的方法应该用ActivityCompat.requestPermissions
    如果是Fragment:申请的方法应该用requestPermissions

    四、拍照或者从相册中选择的图片被旋转

    整体思路就是获取图片被旋转的角度之后,再旋转相应的角度即可

    4.1 拍照:ContentUri转文件路径(通过反射)

    //获取content开头的Uri文件在文件系统中的路径
        public static String getFPUriToPath(Context context, Uri uri) {
            try {
                List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
                if (packs != null) {
                    String fileProviderClassName = FileProvider.class.getName();
                    for (PackageInfo pack : packs) {
                        ProviderInfo[] providers = pack.providers;
                        if (providers != null) {
                            for (ProviderInfo provider : providers) {
                                if (uri.getAuthority().equals(provider.authority)) {
                                    if (provider.name.equalsIgnoreCase(fileProviderClassName)) {
                                        Class<FileProvider> fileProviderClass = FileProvider.class;
                                        try {
                                            Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class, String.class);
                                            getPathStrategy.setAccessible(true);
                                            Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
                                            if (invoke != null) {
                                                String PathStrategyStringClass = FileProvider.class.getName() + "$PathStrategy";
                                                Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
                                                Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                                                getFileForUri.setAccessible(true);
                                                Object invoke1 = getFileForUri.invoke(invoke, uri);
                                                if (invoke1 instanceof File) {
                                                    String filePath = ((File) invoke1).getAbsolutePath();
                                                    return filePath;
                                                }
                                            }
                                        } catch (NoSuchMethodException e) {
                                            e.printStackTrace();
                                        } catch (InvocationTargetException e) {
                                            e.printStackTrace();
                                        } catch (IllegalAccessException e) {
                                            e.printStackTrace();
                                        } catch (ClassNotFoundException e) {
                                            e.printStackTrace();
                                        }
                                        break;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    

    4.2 从相册中选择:ContentUri转文件路径

    public static String getRealPathFromURI(Context context, Uri uri) {
    
            int sdkVersion = Build.VERSION.SDK_INT;
            if (sdkVersion >= 19) { // api >= 19
                return getRealPathFromUriAboveApi19(context, uri);
            } else { // api < 19
                return getRealPathFromUriBelowAPI19(context, uri);
            }
        }
    
        private static String getRealPathFromUriBelowAPI19(Context context, Uri uri) {
            String[] proj = {MediaStore.Audio.Media.DATA};
            Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
            cursor.moveToFirst();
            int columnIndex = cursor.getColumnIndex(proj[0]);
            String picturePath = cursor.getString(columnIndex);
            cursor.close();
            return picturePath;
        }
    
        /**
         * 适配api19及以上,根据uri获取图片的绝对路径
         *
         * @param uri     图片的Uri
         * @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
         */
        @SuppressLint("NewApi")
        private static String getRealPathFromUriAboveApi19(Context context, Uri uri) {
            String filePath = null;
            if ("content".equalsIgnoreCase(uri.getScheme())){
                // 如果是 content 类型的 Uri
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equals(uri.getScheme())) {
                // 如果是 file 类型的 Uri,直接获取图片对应的路径
                filePath = uri.getPath();
            }
            Log.e(TAG,"real path = "+filePath) ;
            return filePath;
        }
    
        /**
         * 获取数据库表中的 _data 列,即返回Uri对应的文件路径
         * @return
         */
        private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
            String path = null;
    
            String[] projection = new String[]{MediaStore.Images.Media.DATA};
            Cursor cursor = null;
            try {
                cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
                if (cursor != null && cursor.moveToFirst()) {
                    int columnIndex = cursor.getColumnIndexOrThrow(projection[0]);
                    path = cursor.getString(columnIndex);
                }
            } catch (Exception e) {
                if (cursor != null) {
                    cursor.close();
                }
            }
            return path;
        }
    

    4.3 获取被旋转的角度以及旋转图片

    //读取图片旋转角度
        public static int readPictureDegree(String path) {
            int degree = 0;
            try {
                ExifInterface exifInterface = new ExifInterface(path);
                int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                Log.i(TAG,"readPictureDegree : orientation = " + orientation);
                if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
                    degree = 90;
                } else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
                    degree = 180;
                } else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
                    degree = 270;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return degree;
        }
    
        //旋转图片
        public static Bitmap rotateBitmap(int angle, Bitmap bitmap) {
            Matrix matrix = new Matrix();
            matrix.postRotate(angle);
            Bitmap rotation = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
                    matrix, true);
            return rotation;
        }
    

    五、没有使用音频却出现AudioTrack错误

    在logcat中的报错信息如下,项目中没有使用任何音频,却出现了AudioTrack错误:

    图片.png

    此时如果定位不到任何地方的代码时,可以尝试在Run项中查看有没有其他报错信息。该次的错误其实是textView.setText时里面的参数放进了int类型的数据,所以才导致了错误。

    图片.png

    六、recyclerview.setLayoutManager空指针错误

    androidx.recyclerview.widget.RecyclerView.setLayoutManager on a null object reference
    

    在排除了recyclerview包名相同,语法正确之后,依然出现空指针错误。这时可以改一下xml中recyclerview的id,然后再重新运行即可。

    七、toast自带包名

    //toast日常使用方式改为:
    Toast toast = Toast.makeText(context, "", Toast.LENGTH_SHORT);
    toast.setText("请填写相关信息!");
    toast.show();
    

    八、启动页白屏

    白屏产生的原因我就不讲了,无非是application在初始化时耗时较久之类的,这里我采用的是修改style方式

    //1.首先在styles文件中添加启动时的默认图片
    <style name="SloganTheme" parent="AppTheme">
            <item name="android:windowTranslucentStatus">true</item>
            <item name="android:windowBackground">@drawable/slogan_style</item>
            <item name="android:windowNoTitle">true</item>
            <item name="android:windowTranslucentNavigation">true</item>
    </style>
    
    //2.然后在AndroidManifest文件中设置theme
    <activity android:name=".ui.activity.SloganActivity"
                android:theme="@style/SloganTheme">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
    
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
    </activity>
    //最后,如果你的启动页的背景和style中的几乎一样的话,还可以在启动页的activity中取消setContentView
    

    九、Retrofit同时发送两次请求以及后台正常返回数据,客户端却回调失败onError closed信息

    9.1 Retrofit同时发送两次请求

    原因:
    一般我们使用retrofit的时候,都会去使用拦截器。这时,如果多个拦截器里面都会调用chain.proceed()方法,则会同时发起多次网络请求,每调用一次chain.proceed()方法,都会发起一次请求。
    解决方案:
    可以将拦截器合成一个,保证只调用一次chain.proceed()方法。

    9.2 后台正常返回数据,客户端却回调失败onError closed信息

    原因:
    如题目所示,虽然后台能够正常返回数据,但是客户端回调的却是onError,并且错误信息为closed。原因是在拦截器里面已经调用过response.body().string()方法,向上返回的response的responseBody已经被close掉了,所以错误信息显示的是closed。
    解决方法:
    在return的时候重新构建一个response。

    @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request()
                        .newBuilder()
                        .addHeader("X-APP-TYPE","android")
                        .build();
                Response response = chain.proceed(request);
    
                //打印请求的具体信息
                String url = request.url().toString();
                String params = requestBodyToString(request.body());
                String responseString = response.body().string();//JsonHandleUtils.jsonHandle(response)
                String time = DateUtils.getCurrentDateByFormat("yyyy-MM-dd HH:mm:ss");
                String log =
                        "\n\n******请求时间*****:\n" + time +
                                "\n*****路径*****:\n" + url +
                                "\n*******参数******:\n" + params +
                                "\n*****报文******:\n" + responseString+"\n \n";
                Log.d(TAG, log);
    
                return response.newBuilder().body(ResponseBody.create(response.body().contentType(), responseString)).build();
            }
    

    参考链接:
    Retrofit2的一些坑

    十、Retrofit上传图片时Multipart注解和FormUrlEncoded注解冲突

    问题:
    当我们需要上传图片时,需要Multipart注解;当我们还有其他参数需要用POST方法传递时,需要FormUrlEncoded注解。当我们在同一个请求方法上同时加上这两个注解时,就会报冲突异常。
    解决方案:
    将需要传递的其他参数的Field换成Part即可

    //错误写法
    @FormUrlEncoded
    @Multipart
    @POST("api-user/user/uploadAvatar")
    Observable<ResponseBean> uploadAvatar(
                                          @Part MultipartBody.Part avatar, 
                                          @Field("userId") int userId);
    
    //正确写法
    @Multipart
    @POST("api-user/user/uploadAvatar")
    Observable<ResponseBean> uploadAvatar(
                                          @Part MultipartBody.Part avatar, 
                                          @Part("userId") int userId);
    

    相关文章

      网友评论

          本文标题:StudentAgency项目开发遇到的问题

          本文链接:https://www.haomeiwen.com/subject/fpshxhtx.html