Hola,
Recibo un error si intento sujetar el objeto Cajón y mostrarlo más de una vez.
¿Es posible, por consideraciones de rendimiento, crear exactamente un cajón (estático) y usarlo en otras actividades?
Me doy cuenta de que la mejor práctica sería realizar una actividad con fragmentos, pero este no es el caso.
Gracias
Un costi
@acosti, si no puede usar una actividad con fragmentos (que definitivamente es la implementación correcta), tendrá que optar por un enfoque diferente.
Definitivamente NO hay posibilidad de que el cajón esté _estático_.
Lo que puede hacer es tener una clase de ayuda que cree el cajón para usted (con la misma lógica) y simplemente llame a este ayudante en todas sus actividades. Pero el cajón .build()
tiene que ser llamado en cada una de esas actividades, de lo contrario no se agrega el cajón.
Ok, entonces mi pregunta sería:
¿Hay alguna manera de que dicha clase auxiliar cree el cajón solo una vez, pero lo construya () varias veces en diferentes etapas de la aplicación?
Lo racional se debe al hecho de que no es barato para mí crear el cajón, ya que está altamente personalizado e interactúa con varios otros componentes de la aplicación. Así que recrearlo cada vez desde cero sería suicida en términos de rendimiento.
@acosti sí, eso es posible. Puede mantener el DrawerBuilder
global una vez. Y llame a build()
por actividad, ya que esto iniciará el inflado de los diseños en su aplicación al final.
Ok mike, gracias. Agradezco la ayuda.
Disculpe Mike, pero no parece funcionar.
Recibo un error de tiempo de ejecución explícito:
"no debes reutilizar un constructor de DrawerBuilder" ... tengo que admitir que ese es uno de los mensajes de error más informativos. ¿Algunas ideas?
@acosti oh Me olvidé de este comportamiento porque tenía que evitar que la gente llamara a .build()
varias veces (lo que haría que tuvieran varios cajones en la misma actividad)
La solución más sencilla sería mantener la información "cara" en todo el mundo y reconstruir el cajón con normalidad. Supongo que obtener los artículos es costoso para usted, así que ¿mantener esos artículos en todo el mundo?
sí, supongo que esa es la solución sensata para mi loco problema.
Si se te ocurre uno mejor para sostener todo el objeto Drawer, me encantaría saberlo.
de cualquier manera, gracias por las rápidas respuestas. tu biblioteca me ha ahorrado toneladas de tiempo.
@acosti , podría hacer una solicitud de extracción y agregar un método reset
al DrawerBuilder
que establece el campo mUsed
nuevo en falso.
esto le permitiría hacer esto. Y aún evitará la reutilización de DrawerBuilder
para personas que no están muy seguras de lo que están haciendo
@acosti creó una nueva versión v5.3.5 que permite esto.
https://github.com/mikepenz/MaterialDrawer/releases/tag/v5.3.5
Hola,
Intenté usar el método .reset () que proporcionó, pero tengo problemas.
Aquí está el error que recibo.
Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
Lo que hice fue:
.withActivity(Activity B)
Y luego se estrelló.
@acosti Creo que esto puede estar relacionado con la reutilización de DrawerLayout
:
https://github.com/mikepenz/MaterialDrawer/issues/1399#issuecomment -233190027
¿Puedes intentar llamar también a withDrawerLayout(-1)
adicionalmente a withActivity
Mierda, eso fue rápido. Gracias tio, de verdad.
Desafortunadamente, el mismo resultado. Déjame pegar todo el registro aquí.
FATAL EXCEPTION: main
Process: com.example.agombiprototypetest.prototypetest, PID: 20689
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.agombiprototypetest.prototypetest/com.example.agombiprototypetest.prototypetest.Prototypes.core.aboutUs}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)`
`Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:4309)
at android.view.ViewGroup.addView(ViewGroup.java:4145)
at android.view.ViewGroup.addView(ViewGroup.java:4117)
at com.mikepenz.materialdrawer.DrawerBuilder.createContent(DrawerBuilder.java:1629)
at com.mikepenz.materialdrawer.DrawerBuilder.buildView(DrawerBuilder.java:1483)
at com.mikepenz.materialdrawer.DrawerBuilder.build(DrawerBuilder.java:1281)
at com.example.agombiprototypetest.prototypetest.BL.Navigation.DrawerNavigationModel.BuildDrawerWithToolbar(DrawerNavigationModel.java:119)
at com.example.agombiprototypetest.prototypetest.BL.Navigation.DrawerNavigationModel.injectView(DrawerNavigationModel.java:96)
at com.example.agombiprototypetest.prototypetest.BL.Models.AgombiNavActivity.onCreate(AgombiNavActivity.java:37)
at android.app.Activity.performCreate(Activity.java:6237)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
at android.app.ActivityThread.-wrap11(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
@acosti hmm falla aquí: https://github.com/mikepenz/MaterialDrawer/blob/develop/library/src/main/java/com/mikepenz/materialdrawer/DrawerBuilder.java#L1629
Lo suficientemente extraño como este se infla recientemente durante .build()
aquí
https://github.com/mikepenz/MaterialDrawer/blob/develop/library/src/main/java/com/mikepenz/materialdrawer/DrawerBuilder.java#L1469
¿Estás seguro de que lo llamaste?
Estoy seguro.
Este es el proceso:
.withActivity(Activity A)
y también restablece el diseño a través de .withDrawerLayout(-1)
built()
reset()
withActivity(Activity B)
y también restablece el diseño a través de .withDrawerLayout(-1)
built
¿Podría enviar estos pasos como muestra para que pueda depurarlos? Gracias
hmm eso va a ser un poco difícil. déjame intentar hacer algo para que lo veas.
Ok, esto será complicado. Por favor, tengan paciencia conmigo y con gusto responderé a cualquier pregunta lo antes posible.
Cada actividad que contiene un cajón usa el siguiente código:
private void initDrawerForActivity(Context activityContext)
{
// Get the activity
AgombiNavActivity activity = (AgombiNavActivity) activityContext;
if (sSharedDrawer == null) {
sSharedDrawer =generateDrawer(activityContext);
}
else {
sSharedDrawer.reset();
}
sSharedDrawer.withActivity(activity)
.withDrawerLayout(-1);
}
El código de generación de cajón de generateDrawer(activityContext)
es el siguiente:
private DrawerBuilder generateDrawer(Context context) {
// Get the menu items
RealmResults<AgombiComponentRealm> menuItems =
NavigationManager.getInstance().getMenu();
List<IDrawerItem> drawerItems = new LinkedList<>();
for (final AgombiComponentRealm menuItem : menuItems) {
// Get the drawer item externally
PrimaryDrawerItem item =
AgombiViewLoader.getInstance().initializeMenuItem(context, menuItem);
drawerItems.add(item);
}
// Get the footer externally
ViewGroup footer = AgombiViewLoader.getInstance().initializeDrawerFooter(context);
DrawerBuilder drawerBuilder = new DrawerBuilder()
.withTranslucentStatusBar(false)
.withDelayDrawerClickEvent(300)
.withDrawerItems(drawerItems)
.withFooter(footer)
.withFooterDivider(false);
// TODO: turn footer to sticky (removing its divider as sticky doesn't work - attempt to solve)
return drawerBuilder;
}
Ahora, la actividad requiere la función de construcción. Pero no es tan sencillo.
Cada actividad de mi proyecto es responsable de su propia navegación, por lo que una actividad puede tener un cajón pero sin una barra de herramientas. O con una barra de herramientas. Así que primero tengo que comprobar esto.
A continuación se muestra el código que verifica si se requiere una barra de herramientas o no y, en consecuencia, invoca la compilación () de DrawerBuilder.
public void injectView(ViewGroup activityLayout) {
Drawer projectedDrawer = null;
Toolbar potentialToolbar = getToolbar();
// Check whether a toolbar is required. If so, build a combined Drawer + Toolbar
if (potentialToolbar == null)
{
projectedDrawer = sSharedDrawer.build();
}
else
{
projectedDrawer = BuildDrawerWithToolbar(sSharedDrawer, activityLayout, getToolbar());
}
}
Y el siguiente es el código adicional que construye el cajón dada una barra de herramientas ...
private Drawer BuildDrawerWithToolbar(DrawerBuilder drawerBuilder, ViewGroup activityLayout, Toolbar optionalToolbar) {
AttachToolbarToLayout(activityLayout, optionalToolbar);
// Create the drawer
return drawerBuilder
.withToolbar(optionalToolbar)
.withActionBarDrawerToggle(true)
.withActionBarDrawerToggleAnimated(true)
.build();
}
Maldita sea.
Espero que esto quede lo suficientemente claro.
Lo siento, mi código es un poco complejo. Tengo una gran tarea que cumplir, pero mis conocimientos en Android son un WIP, jaja. Espero que el código esté bien :)
Avísame si puedes pescar algo, Mike.
Realmente agradezco la ayuda y las respuestas rápidas.
Se actualizó el formato para facilitar el acceso
@mikepenz ¿Cómo usaría fragmentos para hacer esto? No estoy tan familiarizado con los fragmentos.
@acosti perdón por la respuesta tardía. Es bastante complejo lo anterior. Quizás sea más fácil publicar un "zip" que contenga el código de muestra simple
@ caralin3 si tiene una actividad con fragmentos. Simplemente use el oyente y cambie los fragmentos si el usuario selecciona uno nuevo
@mikepenz ¿Tiene un enlace que me pueda ayudar a crear un fragmento?
@ caralin3 la documentación oficial de Android muestra cómo enviar fragmentos a una vista de contenedor
https://developer.android.com/guide/components/fragments.html
simplemente use el oyente para detectar selecciones del usuario y cambie el fragmento
hola @mikepenz ,
Estoy probando un nuevo enfoque: en lugar de volver a dibujar el cajón de nuevo en cada actividad, y en lugar de tener la implementación "1 actividad - muchos fragmentos":
Haré 1 actividad, muchas actividades.
es decir, hay una actividad de cajón, responsable de sostener el cajón y dibujarlo UNA VEZ.
y al navegar - el setContentView tiene una anulación que obtiene el diseño de destino, lo infla y lo coloca en el diseño de la actividad de un cajón en un "marco de contenido".
Entonces, básicamente, supongo que la misma implementación que tendría con los fragmentos, excepto con las actividades y la autogestión.
Mi pregunta es, ¿cómo abordaría esa solución?
Estaba entreteniendo la idea de simplemente (espero que sea simple) anular el diseño del cajón para agregar el "marco de contenido". a partir de ahí, debería ser fácil hacer la inflación del diseño en la anulación de setContentView. ¿tus pensamientos?
¿Soneone lo intentó con Dagger2?
@acosti Recuerdo que había una biblioteca que hacía exactamente esto. Manteniendo una actividad pero llenándola de diferentes puntos de vista según el contexto.
No estoy muy seguro de si este es un enfoque bueno o el mejor. Android viene con un concepto bastante bueno y rico en funciones de Fragment
s que hará exactamente lo que necesita.
También es bastante simple dividir las cosas en fragmentos y manejar fragmentos y hacer el cambio con Drawer
ya que solo necesita confirmar el fragmento correcto cuando se selecciona un elemento. Incluso puede mover toda la lógica de confirmación del fragmento al Listener
del cajón, ya que puede activarlo después del inicio, y también cuando se llama a onCreate con onSavedInstanceState
configurando el fragmento correcto nuevamente.
Ok para finalmente cerrar este problema. Después de investigar, depurar e intentar un poco más. Realmente no es posible reutilizar el mismo DrawerBuilder
, ya que resulta que el RecyclerView
no está contento si se reutiliza el Adapter
.
La solución óptima para este caso de uso es recordar los datos complejos que tiene que buscar y luego simplemente construir el cajón con los elementos, basándose en los datos ya cargados.
Comentario más útil
@acosti creó una nueva versión v5.3.5 que permite esto.
https://github.com/mikepenz/MaterialDrawer/releases/tag/v5.3.5