En el código abierto Android 10 cliente chino con experiencia en la adaptación de la tecnología de Código

navegación de páginas blog personal (haga clic a la derecha de enlace para abrir un blog personal): Daniel lo lleve en la pila de tecnología 

adaptación nuestra aplicación de  targetSdkVersion = 26 actualización-versión cruz a 29 , y por lo tanto se encontrará con un gran número de pozos, la versión final de la configuración es como sigue:

Ahora encajar en el orificio de llenado guía contiene el código real que la experiencia, no copiar cualquier traducción de documentos

1.Region.Op相关异常 : java.lang.IllegalArgumentException: no válida Region.Op - sólo se cruzan y se les permite DIFERENCIA

Cuando  targetSdkVersion> = Build.VERSION_CODES.P  llamada cuando canvas.clipPath (path,  Region.Op.XXX ); causada por anormal, la fuente de referencia como sigue:

@Deprecated
public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
     checkValidClipOp(op);
     return nClipPath(mNativeCanvasWrapper, path.readOnlyNI(), op.nativeInt);
}

private static void checkValidClipOp(@NonNull Region.Op op) {
     if (sCompatiblityVersion >= Build.VERSION_CODES.P
         && op != Region.Op.INTERSECT && op != Region.Op.DIFFERENCE) {
         throw new IllegalArgumentException(
                    "Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed");
     }
}

Podemos ver que cuando una versión de destino desde Android P empezar, (Canvas.clipPath @NonNull  ruta Path,  @NonNull  Region.Op OP); ha sido abandonada y abandonada API se incluye un riesgo anormal, y sólo Region.Op.INTERSECT Región .Op.DIFFERENCE conseguir compatibles, google está claro cómo el propósito del movimiento, tan simple como lanzar una excepción incitó a los desarrolladores para adaptarse a casi todas las soluciones de blogs son simples y crudo de la siguiente manera:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    canvas.clipPath(path);
} else {
    canvas.clipPath(path, Region.Op.XOR);// REPLACE、UNION 等
}

Pero ciertamente necesitamos un poco de efecto avanzada operación lógica de cómo hacerlo? Resultados de la simulación de páginas como la lectura de novelas, la solución es la siguiente, con Path.op en su lugar, la primera ruta de operación, dan canvas.clipPath:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
    Path mPathXOR = new Path();
    mPathXOR.moveTo(0,0);
    mPathXOR.lineTo(getWidth(),0);
    mPathXOR.lineTo(getWidth(),getHeight());
    mPathXOR.lineTo(0,getHeight());
    mPathXOR.close();
    //以上根据实际的Canvas或View的大小,画出相同大小的Path即可
    mPathXOR.op(mPath0, Path.Op.XOR);
    canvas.clipPath(mPathXOR);
}else {
    canvas.clipPath(mPath0, Region.Op.XOR);
}

2. Restricciones de texto sin formato HTTP

Cuando  targetSdkVersion> = Build.VERSION_CODES.P  , el valor por defecto limita la petición HTTP, y el registro pertinente de:

java.net.UnknownServiceException: CLEARTEXT communication to xxx not permitted by network security policy

La primera solución: código de aplicación que añadir el nodo siguiente en AndroidManifest.xml

<application android:usesCleartextTraffic="true">

La segunda solución: el nuevo directorio de XML en el directorio res, se ha construido un nuevo archivo XML network_security_config.xml saltado en xml, y luego añadir la siguiente aplicación en AndroidManifest.xml Código nodo

android:networkSecurityConfig="@xml/network_config"

nombre al azar, de la siguiente manera:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

lector de 3.Android propiedad Q (10)

comportamiento Android Q cambios relacionados no elaborados, la mayor parte del blog en línea en la adaptación de Android Q están hablando de un cambio de comportamiento, que se basará en los problemas prácticos que se plantean en la solución práctica

1, los discos de sistema de exploración, vídeo, imágenes, selector de video se proporciona por el ContentResolver, el código principal es el siguiente:

private static final String[] IMAGE_PROJECTION = {
            MediaStore.Images.Media.DATA,
            MediaStore.Images.Media.DISPLAY_NAME,
            MediaStore.Images.Media._ID,
            MediaStore.Images.Media.BUCKET_ID,
            MediaStore.Images.Media.BUCKET_DISPLAY_NAME};

 Cursor imageCursor = mContext.getContentResolver().query(
                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    IMAGE_PROJECTION, null, null, IMAGE_PROJECTION[4] + " DESC");

String path = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[0]));
String name = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[1]));
int id = imageCursor.getInt(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[2]));
String folderPath = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[3]));
String folderName = imageCursor.getString(imageCursor.getColumnIndexOrThrow(IMAGE_PROJECTION[4]));

//Android Q 公有目录只能通过Content Uri + id的方式访问,以前的File路径全部无效,如果是Video,记得换成MediaStore.Videos
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
      path  = MediaStore.Images.Media
                       .EXTERNAL_CONTENT_URI
                       .buildUpon()
                       .appendPath(String.valueOf(id)).build().toString();
 }

2, se determina si existe un archivo de directorio público, comenzando desde el Android Q, directorio público API de archivos fallan, no directamente por el nuevo archivo (ruta) .exists (); determinar si existe el archivo de directorio público, el derecho de la siguiente manera:

public static boolean isAndroidQFileExists(Context context, String path){
        if (context == null) {
            return false;
        }
        AssetFileDescriptor afd = null;
        ContentResolver cr = context.getContentResolver();
        try {
            Uri uri = Uri.parse(path);
            afd = cr.openAssetFileDescriptor(Uri.parse(path), "r");
            if (afd == null) {
                return false;
            } else {
                close(afd);
            }
        } catch (FileNotFoundException e) {
            return false;
        }finally {
            close(afd);
        }
        return true;
}

3, guardar o descarga el archivo en un directorio público, mapa de bits salvó Del mismo modo, como Download, tipo MIME_TYPE puede referirse a su propio tipo de archivo correspondiente, describen aquí sólo para APK

public static void copyToDownloadAndroidQ(Context context, String sourcePath, String fileName, String saveDirName){
        ContentValues values = new ContentValues();
        values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
        values.put(MediaStore.Downloads.MIME_TYPE, "application/vnd.android.package-archive");
        values.put(MediaStore.Downloads.RELATIVE_PATH, "Download/" + saveDirName.replaceAll("/","") + "/");

        Uri external = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
        ContentResolver resolver = context.getContentResolver();

        Uri insertUri = resolver.insert(external, values);
        if(insertUri == null) {
            return;
        }

        String mFilePath = insertUri.toString();

        InputStream is = null;
        OutputStream os = null;
        try {
            os = resolver.openOutputStream(insertUri);
            if(os == null){
                return;
            }
            int read;
            File sourceFile = new File(sourcePath);
            if (sourceFile.exists()) { // 文件存在时
                is = new FileInputStream(sourceFile); // 读入原文件
                byte[] buffer = new byte[1444];
                while ((read = is.read(buffer)) != -1) {
                    os.write(buffer, 0, read);
                }
                is.close();
                os.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            close(is,os);
        }

}

4, guardar la imagen relacionada

 /**
     * 通过MediaStore保存,兼容AndroidQ,保存成功自动添加到相册数据库,无需再发送广告告诉系统插入相册
     *
     * @param context      context
     * @param sourceFile   源文件
     * @param saveFileName 保存的文件名
     * @param saveDirName  picture子目录
     * @return 成功或者失败
     */
    public static boolean saveImageWithAndroidQ(Context context,
                                                  File sourceFile,
                                                  String saveFileName,
                                                  String saveDirName) {
        String extension = BitmapUtil.getExtension(sourceFile.getAbsolutePath());

        ContentValues values = new ContentValues();
        values.put(MediaStore.Images.Media.DESCRIPTION, "This is an image");
        values.put(MediaStore.Images.Media.DISPLAY_NAME, saveFileName);
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/png");
        values.put(MediaStore.Images.Media.TITLE, "Image.png");
        values.put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/" + saveDirName);

        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        ContentResolver resolver = context.getContentResolver();

        Uri insertUri = resolver.insert(external, values);
        BufferedInputStream inputStream = null;
        OutputStream os = null;
        boolean result = false;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(sourceFile));
            if (insertUri != null) {
                os = resolver.openOutputStream(insertUri);
            }
            if (os != null) {
                byte[] buffer = new byte[1024 * 4];
                int len;
                while ((len = inputStream.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
                os.flush();
            }
            result = true;
        } catch (IOException e) {
            result = false;
        } finally {
            Util.close(os, inputStream);
        }
        return result;
}

4.EditText por defecto no recibe el foco, el teclado no se eleva automáticamente

Este problema ocurre en  targetSdkVersion> = Build.VERSION_CODES.P  caso, y la versión del dispositivo Android P anteriormente, se ha encontrado ahora ningún cambio relevante se determina a partir de la fuente, la solución se añadió el siguiente código de onCreate:

mEditText.post(() -> {
       mEditText.requestFocus();
       mEditText.setFocusable(true);
       mEditText.setFocusableInTouchMode(true);
});

5.Sólo actividades de pantalla completa pueden solicitar orientación  异常

El problema se produce en  targetSdkVersion> = Build.VERSION_CODES.O_MR1  , que es  API 27 , cuando el dispositivo es Android 26 veces (más del 27 ha sido reparado, Google podría sentirse inadecuado, y cambiado de nuevo), si la actividad transparente de pantalla completa no fijado dirección, se produce la excepción, pero cuando probamos en el mijo, Meizu Android 26 modelos, y no la excepción, se informa de que los modelos Huawei esa excepción, así es como FML. . . De ninguna manera, quitar o código de estilo transparente se pueden eliminar en una dirección fija, otra solución

6. Instalación de APK documentos intención y otros relacionados con la Intención

/*
* 自Android N开始,是通过FileProvider共享相关文件,但是Android Q对公有目录 File API进行了限制
* 从代码上看,又变得和以前低版本一样了,只是必须加上权限代码Intent.FLAG_GRANT_READ_URI_PERMISSION
*/ 
private void installApk() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){
            //适配Android Q,注意mFilePath是通过ContentResolver得到的,上述有相关代码
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse(mFilePath) ,"application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            startActivity(intent);
            return ;
        }

        File file = new File(saveFileName + "osc.apk");
        if (!file.exists())
            return;
        Intent intent = new Intent(Intent.ACTION_VIEW);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
		    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri contentUri = FileProvider.getUriForFile(getApplicationContext(), "net.oschina.app.provider", file);
            intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
        } else {
            intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        startActivity(intent);
}

7.Activity transparente, la propiedad relevante windowIsTranslucent

Android10 otro sumidero, si desea mostrar una actividad translúcida, que antes android10 Actividad estilo normal, solo necesita ajustar windowIsTranslucent = true puede ser, pero a Android10, no tiene el efecto, pero si el conjunto dinámico View.setVisibility () , la interfaz será más que un borrón ...

Solución: utilizar el tema de diálogo estilo, y establecer windowIsFloating = true, esta vez el problema de nuevo, si el diseño raíz de actividad no se establece fitsSystemWindow = true, el diseño predeterminado enraizarán padddingTop una altura barra de estado. La interfaz se ve normal, por lo que si usted tiene una adaptación dinámica de la altura de la barra de estado Código de actividad, tenemos que establecer fitsSystemWindow = true diseño raíz, de lo contrario van a encontrar padddingTop una altura extra de barra de estado

8. portapapeles compatibles

Sólo cuando la aplicación es interactiva y supervisar la situación con el fin de acceder al cambio del portapapeles portapapeles, no se puede acceder directamente desde el portapapeles onResume de devolución de llamada, los beneficios de hacerlo es evitar algunos de los contenidos de la pantalla posterior respuesta de la aplicación portapapeles loco.

Hemos apk desarrollo de la práctica hoyo encontrado temporalmente en estos, por supuesto Android Q cambia es bastante grande, por ejemplo, así como el archivo privado recinto de seguridad de aplicaciones, localizar y permisos pop-up restricciones actividad de fondo, éstos deben ser apropiados a paso en boxes en función de su propia práctica equipado, calificado como posible leer la documentación oficial, las mejoras de referencia.

aprendizaje adjunta Java / C / C ++ / máquina / Algoritmos y Estructuras de Datos / front-end / Android / Python / programador de lectura / libros individuales libros Daquan:

(Haga clic en la derecha para abrir allí en el blog personal en seco): seca Técnica de floración
===== >> ① [Java Daniel lo lleve en el camino a avanzado] << ====
===== >> ② [+ acm algoritmo de estructura de datos Daniel lo lleve en el camino a avanzado] << ===
===== >> ③ [base de datos de Daniel lo lleve en el camino a avanzado] << == ===
===== >> ④ [Daniel cliente web para llevarlo en el camino a avanzado] << ====
===== >> ⑤ [pitón máquina de aprendizaje y Daniel le llevará a la entrada camino avanzada] << ====
===== >> ⑥ [arquitecto Daniel lo lleve en el camino a avanzado] << =====
===== >> ⑦ [C ++ Daniel avanzó para llevarlo en el camino] << ====
===== >> ⑧ [ios Daniel lo lleve en el camino a avanzado] << ====
=====> > ⑨ [seguridad web Daniel lo lleve en el camino a avanzado] << =====
===== >> ⑩ [sistema operativo Linux y Daniel se toman en el camino a avanzado] << = ====

No hay frutas consumidas, espero que jóvenes amigos, amigos desea aprender técnicas, superando todos los obstáculos en el camino de la carretera determinada para atar en la tecnología, entender el libro, y luego golpear en el código, entender el principio, e ir a la práctica, se se le dan vida, su trabajo, su futuro un sueño.

Publicado 47 artículos originales · ganado elogios 0 · Vistas 282

Supongo que te gusta

Origin blog.csdn.net/weixin_41663412/article/details/104863691
Recomendado
Clasificación