Aglutinante
- Descripción general del marco de carpeta
- Servidor y cliente de diseño
- Carpeta y servicio
- Objeto de carpeta en el servicio del sistema
-
- Servicios gestionados por ServiceManger
- Entendiendo al Pesebre
- Teclas de acceso directo a funciones
- Cree títulos correctamente para ayudar a crear una tabla de contenido.
- Cómo cambiar el estilo del texto
- Insertar enlaces e imágenes
- Cómo insertar un hermoso fragmento de código
- Genera una lista que funcione para ti
- Crear un formulario
- Crear una lista personalizada
- Cómo crear un pie de página
- Los comentarios también son esenciales.
- Fórmula matemática KaTeX
- Nueva función de diagrama de Gantt para enriquecer tus artículos
- diagrama UML
- diagrama de flujo
- Exportar e importar
Descripción general del marco de carpeta
Binder es una arquitectura que proporciona tres módulos: interfaz de servidor, controlador de Binder e interfaz de cliente, como se muestra en la figura.
Servidor
Veamos primero el servidor. Un servidor Binder es en realidad un objeto de la clase Binder. Una vez que se crea el objeto, se inicia internamente un hilo oculto .
Luego, el hilo recibirá el mensaje enviado por el controlador Binder y , después de recibir el mensaje, ejecutará la función onTransact () en el objeto Binder y ejecutará diferentes funciones de servicio de acuerdo con los parámetros de la función . Por lo tanto, para implementar un servicio Binder, debe sobrecargar el método onTransact().
El contenido principal de la función sobrecargada
onTransact()
esonTransact()
convertir los parámetros de la función en los parámetros de la función de servicio. La fuente de los parámetros de la función es ingresadaonTransact()
por el cliente al llamar a la función. Por lo tanto, si hay una entrada de formato fijo , entonces habrá una salida en formato fijo.transact()
transact()
onTransact()
conductor de carpeta
Cuando se crea cualquier objeto Binder del lado del servidor, también se creará un objeto mRemote en el controlador Binder. El tipo de este objeto también es la clase Binder. Cuando el cliente quiere acceder a servicios remotos, siempre utiliza el objeto mRemote.
cliente
Si el cliente desea acceder al servicio remoto deberá obtener la referencia mRemote correspondiente al servicio remoto en el controlador de Binder. Después de obtener el objeto mRemote, puede llamar a su método transact(). En el controlador Binder, el objeto mRemote también sobrecarga el método transact(). El contenido sobrecargado incluye principalmente los siguientes elementos.
-
En el modo de comunicación de mensajes entre subprocesos, los parámetros pasados por el cliente se envían al servidor.
-
Suspenda el hilo actual, que es el hilo del cliente, y espere la notificación después de que el hilo del servidor termine de ejecutar la función de servicio especificada.
-
Después de recibir la notificación del hilo del servidor, continúe ejecutando el hilo del cliente y regrese al área de código del cliente.
Se puede ver desde aquí que para los desarrolladores de aplicaciones, el cliente parece llamar directamente al Binder correspondiente al servicio remoto, pero en realidad se transfiere a través del controlador de Binder. Es decir, hay dos objetos Binder, uno es el objeto Binder en el lado del servidor y el otro es el objeto Binder en el controlador Binder, la diferencia es que el objeto en el controlador Binder no generará un hilo adicional.
¿Cómo obtiene el cliente la referencia mRemote correspondiente en el controlador de Binder?
¿Cómo envía mensajes el controlador de Binder al servidor?
Servidor y cliente de diseño
Servidor de diseño
El servidor es un objeto de clase Binder, simplemente cree una nueva clase de servidor basada en la clase Binder. A continuación se toma como ejemplo el diseño de una clase MusicPlayerService.
Suponiendo que el Servicio solo proporciona dos métodos: start (String filePath) y stop (), entonces el código de esta clase puede ser el siguiente:
public class MusicPlayerService extends Binder {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case 1000:
data.enforceInterface("MusicPlayerService");
String filePath = data.readString();
start(filePath);
// replay.writeXXX();
break;
}
return super.onTransact(code, data, reply, flags);
}
public void start(String filePath) {
}
public void stop() {
}
}
La variable de código se acuerda entre el cliente y el servidor y se utiliza para identificar qué función en el servidor espera llamar el cliente.
Aquí se supone que 1000 es el valor acordado por ambas partes para llamar a la función start().
enforceInterface() es para algún tipo de verificación, que corresponde al writeInterfaceToken() del cliente.
readString() se utiliza para recuperar una cadena del paquete. Después de eliminar la variable filePath, puede llamar a la función start() en el lado del servidor.
Si el cliente espera que el servidor devuelva algunos resultados, puede llamar a las funciones relacionadas proporcionadas por Parcel en la respuesta del paquete de devolución para escribir los resultados correspondientes.
Cuando desee iniciar el servicio, solo necesita inicializar un objeto MusicPlayerService. Por ejemplo, puede inicializar un MusicPlayerService en la actividad principal y luego ejecutarlo. En este momento, puede encontrar que se está ejecutando un subproceso más, Binder-Thread3.
Si no se crea MusicPlayerService, solo hay 2 subprocesos correspondientes a los objetos Binder. Es decir, Binder-Thread1 y Binder-Thread2.
¿De dónde vinieron estos dos procesos?
diseño del cliente
Para utilizar el servidor, primero debe obtener una referencia a la variable mRemote correspondiente al servidor en el controlador de Binder. Una vez que tenga una referencia a la variable, puede llamar al método transact() de la variable. El prototipo de función de este método es el siguiente:
public final boolean transact(int code, Parcel data, Parcel reply,int flags)
Entre ellos, los datos representan el paquete (Parcel) que se pasará al servicio remoto de Binder, y los parámetros requeridos por la función del servicio remoto deben colocarse en este paquete. Solo se pueden colocar variables de tipos específicos en el paquete, que incluyen tipos atómicos de uso común, como String, int, long, etc. Además de las variables atómicas generales, Parcel también proporciona un método writeParcel() que puede incluir un pequeño paquete en el paquete. Por lo tanto, al llamar al servicio remoto de Binder, el parámetro de la función de servicio debe ser una clase atómica o debe heredar de la clase Parcel ; de lo contrario, no se puede pasar.
Por lo tanto, para el cliente de MusicPlayerService, el método transact() se puede llamar de la siguiente manera.
IBinder mRemote = null;
String filePath = "/sdcard/music/heal_the_world.mp3";
int code = 1000;
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("MusicPlayerService");
data.writeString(filePath);
mRemote.transact(code, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
En primer lugar, el cliente no crea el paquete, sino que lo solicita llamando a Parcel.obtain().
El cliente proporciona tanto los datos como las variables de respuesta, y el servidor coloca la variable de respuesta en los resultados devueltos.
writeInterfaceToken
() marca el nombre del servicio remoto. Teóricamente, este nombre no es necesario porque dado que el cliente ha obtenido la referencia de Binder del servicio remoto especificado, no llamará a otros servicios remotos. El controlador de Binder utilizará este nombre para garantizar que el cliente realmente quiera llamar al servidor especificado.
writeString
() se utiliza para agregar una variable de cadena al paquete. onTransact
Tenga en cuenta que el contenido agregado en el paquete está en orden. Este orden debe ser acordado por el cliente y el servidor con anticipación. Las variables se eliminarán en el método () del servidor en el orden acordado .
Luego llame al método transact(). Después de llamar a este método,
Cuando el hilo del cliente ingresa al controlador de Binder, el controlador de Binder suspenderá el hilo actual y enviará un mensaje al servicio remoto, que contiene el paquete pasado por el cliente. Una vez que el servidor recibe el paquete, lo desensamblará y luego ejecutará la función de servicio especificada. Una vez completada la ejecución, el resultado de la ejecución se colocará en el paquete de respuesta proporcionado por el cliente. Luego, el servidor envía un mensaje de notificación al controlador de Binder, lo que hace que el hilo del cliente regrese del área de código del controlador de Binder al área de código del cliente.
El significado del último parámetro de transact() es el modo de ejecutar llamadas IPC, que se divide en dos tipos: uno es bidireccional, representado por la constante 0, lo que significa que el servidor devolverá ciertos datos después de ejecutar el servicio especificado; el otro Es unidireccional, representado por la constante 1, lo que significa que no se devuelven datos.
Finalmente, el cliente puede analizar los datos devueltos de la respuesta. Del mismo modo, los datos contenidos en el paquete de devolución también deben estar en orden, y este orden debe ser acordado por adelantado entre el servidor y el cliente.
Carpeta y servicio
Hay dos problemas importantes en el proceso anterior de escribir manualmente el servidor y el cliente de Binder.
Primero, ¿cómo obtiene el cliente la referencia del objeto Binder del servidor?
En segundo lugar, el cliente y el servidor deben acordar dos cosas de antemano:
-
El orden de los parámetros de la función del servidor en el paquete.
-
Identificadores de tipo int de diferentes funciones en el lado del servidor. Ese es el valor del parámetro de código en el método de transacción.
Servicio
Entonces, ¿cómo resuelve la clase Servicio las dos cuestiones importantes planteadas al principio de esta sección?
En primer lugar, AmS proporciona la función startService () para iniciar el servicio al cliente. Para el cliente, puede usar las dos funciones siguientes para establecer una conexión con un servicio, y su prototipo está en la clase android.app.ContextImpl.
@Override
public ComponentName startService(Intent service) {
try {
ComponentName cn = ActivityManagerNative.getDefault().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()));
if (cn != null && cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
}
return cn;
} catch (RemoteException e) {
return null;
}
}
Esta función se utiliza para iniciar intent
el servicio especificado. Después del inicio, el cliente aún no tiene una referencia de Binder del servidor, por lo que todavía no puede llamar a ninguna función de servicio.
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context");
}
try {
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags);
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0;
} catch (RemoteException e) {
return false;
}
}
Esta función se utiliza para vincular un servicio, que es la clave de la primera pregunta importante. El segundo parámetro es una clase de interfaz y la definición de la interfaz se muestra en el siguiente código:
/**
* Interface for monitoring the state of an application service. See
* {@link android.app.Service} and
* {@link Context#bindService Context.bindService()} for more information.
* <p>Like many callbacks from the system, the methods on this class are called
* from the main thread of your process.
*/
public interface ServiceConnection {
/**
* Called when a connection to the Service has been established, with
* the {@link android.os.IBinder} of the communication channel to the
* Service.
*
* @param name The concrete component name of the service that has
* been connected.
*
* @param service The IBinder of the Service's communication channel,
* which you can now make calls on.
*/
public void onServiceConnected(ComponentName name, IBinder service);
public void onServiceDisconnected(ComponentName name);
}
Tenga en cuenta la segunda variable Servicio en el método onServiceConnected() en esta interfaz. Cuando el cliente solicita a AmS que inicie un Servicio, si el Servicio se inicia normalmente, AmS llamará de forma remota al objeto ApplicationThread en la clase ActivityThread. Los parámetros de la llamada contendrán la referencia de Binder del Servicio, y luego ApplicationThread devolverá la llamada al interfaz bindService.conn. Por lo tanto, en el cliente, su parámetro Servicio se puede guardar como una variable global en el método onServiceConnected (), de modo que se pueda llamar al servicio remoto en cualquier momento y en cualquier lugar del cliente. Esto resuelve el primer problema importante, que es cómo el cliente obtiene la referencia de Binder del servicio remoto.
AIDL garantiza el orden de los parámetros dentro del paquete.
Con respecto a la segunda pregunta, el SDK de Android proporciona una herramienta Aidl que puede convertir un archivo Aidl en un archivo de clase Java. En el archivo de clase Java, los métodos transact y onTransact () se sobrecargan al mismo tiempo, unificando el almacenamiento. y leer los parámetros del paquete permite al diseñador centrarse en el código de servicio en sí.
A continuación, veamos qué hace la herramienta Aidl. Como se muestra en el ejemplo de la primera sección de este capítulo, aquí todavía se supone que se va a escribir un servicio MusicPlayerService, que contiene dos funciones de servicio, a saber, start() y stop(). Luego, primero puede escribir un archivo IMusicPlayerService.aidl. Como se muestra en el siguiente código:
package com.haiii.android.client;
interface IMusicPlayerService{
boolean start(String filePath);
void stop();
}
El nombre del archivo debe seguir ciertas especificaciones. La primera letra "I" no es necesaria. Sin embargo, para unificar el estilo del programa, el significado de "I" es la clase IInterface, es decir, esta es una clase que puede proporcionar acceso a servicios remotos. El nombre posterior: MusicPlayerService corresponde al nombre de clase del servicio, que puede ser arbitrario, pero la herramienta Aidl nombrará la clase Java de salida con este nombre.
La sintaxis del archivo Aidl es básicamente similar a la de Java: el paquete especifica el nombre del paquete correspondiente al archivo Java de salida . Si el archivo necesita hacer referencia a otras clases de Java, puede usar la palabra clave import, pero debe tenerse en cuenta que solo se pueden escribir los siguientes tres tipos de contenido en el paquete:
- Tipos atómicos de Java, como int, long, String y otras variables.
- Referencia de carpeta.
- Objeto que implementa Parcelable.
Por lo tanto, básicamente, las clases Java a las que se hace referencia mediante la importación solo pueden ser de los tres tipos anteriores.
La interfaz es una palabra clave, a veces se agrega un unidireccional delante de la interfaz, lo que significa que los métodos proporcionados por el servicio no tienen valor de retorno, es decir, todos son de tipo vacío.
Echemos un vistazo al código del archivo IMusicPlayerService.java generado por Aidl. Como sigue:
package com.haiii.client;
public interface IMusicPlayerService extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder
implements com.haiii.client.IMusicPlayerService {
private static final java.lang.String DESCRIPTOR =
"com.haiii.client.IMusicPlayerService";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.haiii.client.IMusicPlayerService interface,
* generating a proxy if needed.
*/
public static com.haiii.client.IMusicPlayerService
asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin =
(android.os.IInterface) obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.haiii.client.IMusicPlayerService))) {
return ((com.haiii.client.IMusicPlayerService) iin);
}
return new com.haiii.client.IMusicPlayerService.Stub.Proxy(obj);
}
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data,
android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_start: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
boolean _result = this.start(_arg0);
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
case TRANSACTION_stop: {
data.enforceInterface(DESCRIPTOR);
this.stop();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.haiii.client.IMusicPlayerService {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
public boolean start(java.lang.String filePath) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(filePath);
mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);
_reply.readException();
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public void stop() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public boolean start(java.lang.String filePath) throws android.os.RemoteException;
public void stop() throws android.os.RemoteException;
}
Estos códigos realizan principalmente las siguientes tres tareas.
Servicio IMusicPlayer
Defina uno
Java interface
, que contiene la función de servicio declarada en el archivo Aidl. El nombre de la clase esIMusicPlayerService
y la clase se basa enIInterface
la interfaz, es decir,asBinder
se debe proporcionar una función ().
Apoderado
Defina una clase Proxy, que servirá como proxy para que los programas cliente accedan al servidor. El llamado proxy sirve principalmente para la segunda cuestión importante mencionada anteriormente: unificar el orden de escritura de los parámetros en el paquete.
Talón
Defina una clase Stub, que es una clase abstracta basada en la clase Binder e implementa
IMusicPlayerService
la interfaz, utilizada principalmente por el servidor. La razón por la que esta clase se define como una clase abstracta es porque las funciones de servicio específicas deben ser implementadas por programadores, por lo queIMusicPlayerService
las funciones definidas en la interfaz no necesitan implementarse específicamente en la clase Stub. Al mismo tiempo, el método () está sobrecargado en la clase StubonTransact
. Dado quetransact
el orden de escritura de los parámetros en el paquete dentro del método () está definido por la herramienta Aidl, en elonTransact
método (), la herramienta Aidl naturalmente sabe en qué orden. debería estar adentro. Obtenga los parámetros correspondientes del paquete.
Algunas constantes int también se definen en la clase Stub, como TRANSACTION_start, estas constantes corresponden a las funciones de servicio, de aquí provienen los valores del primer código de parámetro de los métodos transact() y onTransact().
En la clase Stub, además de las tareas mencionadas anteriormente, Stub también proporciona una función asInterface(). Lo que hace esta función se proporciona de la siguiente manera:
La razón para proporcionar esta función es que, además de otros procesos, los servicios proporcionados por el servidor también pueden ser utilizados por otras clases dentro del proceso de servicio. Para este último, obviamente no es necesario llamarlo a través de IPC, pero puede ser se llama directamente dentro del proceso. , y hay una función queryLocalInterface (descripción de cadena) dentro de Binder, que determina si el objeto Binder es una referencia local de Binder según la cadena de entrada.
Al crear un servicio, se crea un objeto Binder dentro del proceso del servidor y también se crea un objeto Binder en el controlador de Binder. Si el Binder del proceso del servidor se obtiene del proceso del cliente, solo se devolverá el objeto Binder en el controlador de Binder. Si el objeto Binder se obtiene dentro del proceso del servidor, se obtendrá el objeto Binder del propio servidor.
Por lo tanto, la función asInterface() utiliza el método queryLocalInterface() para proporcionar una interfaz unificada. Ya sea un cliente remoto o un proceso interno del servidor, después de obtener el objeto Binder, puede usar el objeto Binder obtenido como parámetro de asInterface () para devolver una interfaz IMusicPlayerService, que usa la clase Proxy o usa directamente la uno implementado por Stub. Función de servicio correspondiente.
Objeto de carpeta en el servicio del sistema
En las aplicaciones, getSystemService(String serviceName)
a menudo se utilizan métodos para obtener un servicio del sistema. Entonces, ¿cómo se pasan las referencias de Binder de estos servicios del sistema al cliente?
Cabe señalar que los servicios del sistema no se startService()
inician con . getSystemService()
La función se implementa en la clase ContextImpl. Esta función devuelve muchos servicios. Consulte el código fuente para obtener más detalles. Estos Servicios generalmente son administrados por ServiceManager.
Servicios gestionados por ServiceManger
ServiceManager es un proceso independiente. Su función es como se muestra en el nombre. Administra varios servicios del sistema. La lógica de administración es la siguiente:
ServiceManager en sí también es un servicio. El marco proporciona una función del sistema para obtener la referencia de Binder correspondiente al servicio. , eso esBinderInternal.getContextObject()。
Después de que la función estática devuelva ServiceManager, puede obtener la referencia de Binder de otros servicios del sistema a través de los métodos proporcionados por ServiceManager.
Cuando se inician otros servicios del sistema, primero pasan sus objetos Binder a ServiceManager, que es el llamado registro (addService).
Consulte a continuación para obtener un Servicio{IMPUT_METHOD_SERVICE}:
if (INPUT_METHOD_SERVICE.equals(name)) {
return InputMethodManager.getInstance(this);
static public InputMethodManager getInstance(Looper mainLooper) {
synchronized (mInstanceSync) {
if (mInstance != null) {
return mInstance;
}
IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE);
IInputMethodManager service = IInputMethodManager.Stub.asInterface(b);
mInstance = new InputMethodManager(service, mainLooper);
}
return mInstance;
}
Es decir, al ServiceManager
obtener InputMethod Service
el objeto Binder b correspondiente y luego usar el objeto Binder como IInputMethodManager.Stub.asInterface()
parámetro, IInputMethodManager
se devuelve una interfaz unificada.
ServiceManager.getService()
El código es el siguiente:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
Es decir, primero sCache
verifique si hay un objeto Binder correspondiente en el caché. Si lo hay, se devolverá. Si no, se llamará getIServiceManager().getService(name)
. La función getIServiceManager()
se utiliza para devolver el único ServiceManager
Binder correspondiente en el sistema. El código es como sigue:
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
BinderInternal.getContextObject()
La función estática se utiliza para devolver el objeto Binder global correspondiente a ServiceManager, esta función no requiere ningún parámetro porque su función es fija. El proceso de todos los demás servicios del sistema obtenidos a través de ServiceManager es básicamente similar al anterior, la única diferencia es que el nombre del servicio pasado a ServiceManager es diferente, porque ServiceManager guarda diferentes objetos Binder según el nombre del servicio (tipo String).
Agregar un servicio a ServiceManager usando addService() generalmente se completa cuando se inicia el proceso SystemService.
Entendiendo al Pesebre
Todos los servicios gestionados por ServiceManager se devuelven al cliente con el Manager correspondiente, por lo que aquí hay una breve descripción de la semántica de Manager en el Framework.
En Android, el significado de Manager debe traducirse como intermediario. El objeto administrado por Manager es el servicio en sí, porque cada servicio específico generalmente proporciona múltiples interfaces API, y son estas API las que administra Manager.
El cliente generalmente no puede acceder a servicios específicos directamente a través de la referencia de Binder. Primero debe obtener la referencia de Binder del servicio remoto a través de ServiceManager y luego usar esta referencia de Binder para construir un intermediario al que el cliente pueda acceder localmente, como el IInputMethodManager anterior. y luego el cliente puede acceder a servicios remotos a través de este corredor.
El diagrama modelo para acceder a servicios remotos a través del Administrador local es el siguiente:
- El nuevo diseño de la interfaz brindará una nueva experiencia de escritura;
- Configure su estilo de resaltado de código favorito en el centro de creación y Markdown mostrará el fragmento de código en el estilo de resaltado seleccionado ;
- Se agregó la función de arrastrar y soltar imágenes , puede arrastrar imágenes locales directamente al área de edición para mostrarlas directamente;
- Nueva sintaxis de fórmula matemática KaTeX ;
- Se agregó la función de sintaxis de sirena 1 que admite diagramas de Gantt ;
- Se agregó la función de editar artículos de Markdown en múltiples pantallas;
- Funciones agregadas como modo de escritura de enfoque, modo de vista previa, modo de escritura concisa, configuración de rueda sincronizada del área izquierda y derecha, etc. El botón de función está ubicado entre el área de edición y el área de vista previa;
- Se agregó la funcionalidad de lista de verificación .
Teclas de acceso directo a funciones
Deshacer: Ctrl/Command+ Z
Rehacer: Ctrl/Command+ Y
Negrita: Ctrl/Command+ Cursiva B
: Ctrl/Command+ I
Título: Ctrl/Command+ Shift+ H
Lista desordenada: Ctrl/Command+ Shift+ U
Lista ordenada: Ctrl/Command+ Shift+ O
Lista de verificación: + +Insertar código Ctrl/Command: Shift+ C
+ Ctrl/CommandInsertar Shiftenlace K
: Ctrl/Command+ Shift+ L
Insertar imagen: Ctrl/Command+ Shift+ G
Buscar: Ctrl/Command+ F
Reemplazar: Ctrl/Command+G
Cree títulos correctamente para ayudar a crear una tabla de contenido.
Ingréselo directamente una vez #y presiónelo, spacey se generará un título de nivel 1.
Luego de ingresarlo dos veces #y presionarlo space, se generará un título de nivel 2.
Por analogía, admitimos títulos de nivel 6. TOC
Ayuda a generar una tabla de contenidos perfecta utilizando la sintaxis.
Cómo cambiar el estilo del texto
Énfasis en el texto Énfasis en el texto
texto en negrita texto en negrita
marcar texto
Eliminar texto
texto citado
El H2O es un líquido.
El resultado de la operación 2 10 es 1024.
Insertar enlaces e imágenes
Enlace: enlace .
imagen:
Imágenes con dimensiones:
Imagen centrada:
Imagen centrada y dimensionada:
Por supuesto, para hacerlo más conveniente para los usuarios, hemos agregado la función de arrastrar y soltar imágenes.
Cómo insertar un hermoso fragmento de código
Vaya a la página de configuración del blog y elija un estilo de resaltado de fragmento de código que le guste. El mismo estilo de resaltado se muestra a continuación 代码片
.
// An highlighted block
var foo = 'bar';
Genera una lista que funcione para ti
- proyecto
- proyecto
- proyecto
- proyecto
- Proyecto 1
- Proyecto 2
- Proyecto 3
- Tareas programadas
- misión cumplida
Crear un formulario
Una tabla simple se crea así:
proyecto | Valor |
---|---|
computadora | $1600 |
Teléfono móvil | $12 |
catéter | $1 |
Establecer contenido en el centro, izquierda o derecha
Utilice :---------:
el centro
. Utilice :----------
la izquierda.
Utilice ----------:
la derecha.
primera fila | la segunda columna | tercera columna |
---|---|---|
La primera columna de texto está centrada. | La segunda columna de texto está a la derecha. | La tercera columna de texto está a la izquierda. |
Pantalones inteligentes
SmartyPants convierte caracteres de puntuación ASCII en entidades HTML de puntuación tipográfica "inteligentes". Por ejemplo:
TIPO | ASCII | HTML |
---|---|---|
comillas simples | 'Isn't this fun?' |
'¿No es divertido?' |
Citas | "Isn't this fun?" |
"¿No es divertido?" |
guiones | -- is en-dash, --- is em-dash |
– es en el tablero, — es en el tablero |
Crear una lista personalizada
-
Reducción
- Herramienta de conversión de texto a HTML Autores
- John
- lucas
Cómo crear un pie de página
Un texto con notas a pie de página. 2
Los comentarios también son esenciales.
Markdown convierte texto a HTML .
Fórmula matemática KaTeX
Puedes renderizar expresiones matemáticas de LaTeX usando KaTeX :
Infraestructura gamma (n) = (n − 1)! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb NC ( n )=( n.−1 )!∀ norte∈N es la integral vía Euler
Γ ( z ) = ∫ 0 ∞ tz − 1 mi − tdt . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.C ( z )=∫0∞tz - 1 mi− t dt.
Puede encontrar más información sobre las expresiones matemáticas de LaTeX aquí .
Nueva función de diagrama de Gantt para enriquecer tus artículos
- Con respecto a la sintaxis del diagrama de Gantt , consulte aquí .
diagrama UML
Se pueden utilizar diagramas UML para renderizar. Sirena ... Por ejemplo, el diagrama de secuencia se genera a continuación:
Esto producirá un diagrama de flujo. :
- Con respecto a la sintaxis de Mermaid , consulte aquí ,
diagrama de flujo
Seguiremos admitiendo diagramas de flujo de diagramas de flujo:
- Con respecto a la sintaxis del diagrama de flujo , consulte aquí .
Exportar e importar
Exportar
Si quieres probar a usar este editor, puedes editar lo que quieras en este artículo. Cuando termine de escribir un artículo, busque la exportación del artículo en la barra de herramientas superior y genere un archivo .md o .html para guardarlo localmente.
importar
Si desea cargar un archivo .md que haya escrito, puede seleccionar la función de importación en la barra de herramientas superior para importar el archivo con la extensión correspondiente y
continuar con su creación.
Explicación de la nota al pie↩︎