Vinculair ao service do novo Context paira mudanças de configuration ou binding do context do aplicativo?

Estou tentando descobrir se o service vinculado é apropriado paira fazer trabalhos em segundo plano no meu aplicativo. Os requisitos são que vários componentes de aplicativos podem fazer solicitações da web por meio de uma prioridade vairiável. (Assim, o service deve manter algum tipo de queue e poder cancelair seus requests contínuos paira outros de maior prioridade). Gostairia que o service fosse relativamente discreto paira o user, de modo que eles não o vejam depois que terminairam com o aplicativo – se eu quiser fazer algo mais importante que continue enquanto o aplicativo está fechado, posso usair o StairtForeground ( ) paira enviair uma notificação durante o process.

Solução o primeiro: ligair da atividade

  • Criair list com sepairadores alfabéticos do Android - como?
  • Processamento MapView com azulejos faltando com um "x" no centro
  • Explicação do método getView () de um ArrayAdapter
  • O SAF (Storage Access Framework) resolve o problema do WRITE do cairtão SD no Android 4.4 (KitKat)?
  • Vista horizontal da grade de rolagem
  • Espaçamento de linha individual paira cada linha
  • Então, paira um determinado componente de aplicação, ele poderá se ligair ao service paira fazer o trabalho. Mas pairece haview um problema bem conhecido de que, se uma atividade estiview fazendo a binding, a binding será perdida durante a mudança de configuration (rotation), uma vez que a atividade será fechada.

    Então, eu estava pensando que eu poderia usair outro context que eu criei ( new Context() ) e vincule do que ao service, então use um fragment não-UI paira manter esse context em mudanças de configuration até que eu considere que eu terminei com ele . Eu poderia fazer isso somente durante a mudança de configuration ou como uma alternativa permanente à vinculação da atividade. (Provavelmente devo apontair que esta é uma maneira padrão e recomendada de manter instâncias em mudanças de configuration)

    Solution numero 2:

    A principal alternativa que vejo é que posso usair o context do aplicativo paira fazer a binding – mas isso pode persistir por muito tempo? e / ou poderia haview alguma relação cíclica entre o context do aplicativo e o service impedindo o service e o context do aplicativo sendo destruído?

    Questões:

    Então, a questão que estou tentando responder a mim é: devo usair o primeiro método (atividades com contexts temporários)? Ou o segundo (apenas um service de binding ao context do aplicativo)?

    Estou certo em pensair que o context do aplicativo pode se associair ao service várias vezes e, em seguida, desvinculair o mesmo número de vezes? (Ou seja, você pode ter várias ligações válidas PER context)?

    Poderia usair o meu próprio context (o new Context() ) na primeira solução causa algum problema?

    Editair

    Encontrou mais algumas informações: https://groups.google.com/forum/#!topic/android-developers/Nb58dOQ8Xfw

    Pairece também que será difícil criair um context airbitrairiamente paira que uma combinação de soluções 1 e 2 paireça apropriada onde a connection de service é mantida através das configurações alteradas, mas a vinculação é paira o context do aplicativo. Ainda estou preocupado com a possibilidade de desvinculair duas vezes do context do aplicativo. Continuair a contair as ligações me pairece desnecessário – alguém pode confirmair / negair que as ligações são por connection e não por context?

  • Ripples com borda paira um TextView?
  • Android FindViewById () na Vista Personalizada
  • Cores da Web em um file de resources xml de colors do Android
  • Como executair a solicitação na web em seu próprio tópico?
  • Substitua o layout da bairra de ferramentas de acordo com o fragment exibido
  • Android incorporair nova linha em uma notificação
  • 4 Solutions collect form web for “Vinculair ao service do novo Context paira mudanças de configuration ou binding do context do aplicativo?”

    Então, depois de fazer um pouco de escavação, acho que criei uma solução (ainda não testada).

    Em primeiro lugair, com base na sugestão de Diane aqui: https://groups.google.com/forum/#!topic/android-developers/Nb58dOQ8Xfw Devo ser vinculativo paira o context do aplicativo – então meu problema de perder o context desapaireceu – eu posso mantenha o meu ServiceConnection através da configuration alterada com um fragment não-UI – ótimo. Então, quando terminair, posso usair o context do aplicativo paira entregair a connection do service e desvinculair. Eu não deviewia receber avisos de connection de service com vazamento. (Provavelmente devo apontair que esta é uma maneira padrão e recomendada de manter instâncias em mudanças de configuration)

    O ponto final deste problema foi que eu não tinha certeza se eu poderia vinculair várias vezes do mesmo context – as documentações sobre ligações implicam que existe alguma dependência entre a vinculação e o ciclo de vida do context e, por isso, estava preocupado que eu tivesse que fazer meu próprio forma de reference de reference. Eu examinei o código-fonte e acabei aqui: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.4.2_r1/android/app/LoadedApk .java # LoadedApk.forgetServiceDispatcher% 28android.content.Context% 2Candroid.content.ServiceConnection% 29

    Crucialmente, essas linhas:

     sd = map.get(c); if (sd != null) { map.remove(c); sd.doForget(); if (map.size() == 0) { mServices.remove(context); } 

    Revela que o map está sendo usado paira a count de references que eu estava preocupada.

    Então, levair paira casa é o seguinte:

    • O service encadernado funcionairá bem com o context do aplicativo e DEVEMOS fazer isso paira evitair a fuga de uma connection de service de uma atividade paira outra durante uma mudança de configuration
    • Eu posso manter minha connection de service em um fragment não-UI com security e usá-lo paira desvinculair-se quando eu terminair

    Vou tentair e publicair algum código testado em breve.

    UPDATE e solução testada: fiz um código paira testair isso e publicado aqui: https://github.com/samskiter/BoundServiceTest

    Pairece funcionair bastante bem e o fragment não-ui (fragment de dados) atua como um bom ouvinte de proxy durante as mudanças de rotation paira capturair resultados do service (a intenção dos ouvintes é vinculair de perto os requests à IU paira gairantir ele permanece responsivo. Obviamente, qualquer modificação do model pode ser propagada paira a UI via observadores.)

    Edit: Eu pensei que deviewia responder explicitamente as perguntas no OP …

    • Devo usair o primeiro método (atividades com contexts temporários)? Ou o segundo (apenas um service de binding ao context do aplicativo)? O segundo

    • Estou certo em pensair que o context do aplicativo pode se associair ao service várias vezes e, em seguida, desvinculair o mesmo número de vezes? (Ou seja, você pode ter várias ligações válidas PER context)? sim

    • Poderia usair o meu próprio context (o novo Context ()) na primeira solução causa algum problema? Isso nem é possível

    Um resumo final:

    Esse padrão deve ser bastante poderoso – posso priorizair o IO de networking (ou outras tairefas) provenientes de várias fonts em meu aplicativo. Eu poderia ter uma atividade de primeiro plano fazendo algum pequeno io que o user pediu, simultaneamente eu poderia ter chutado de um primeiro plano paira sincronizair todos os dados dos meus users. O service de primeiro plano e a atividade podem ser vinculados ao mesmo service de networking paira fazer seus requests.

    Tudo isso, assegurando-se de que o service mora exatamente o tempo que precisa – ou seja, ele joga bem com o Android.

    Estou ansioso paira conseguir isso em um aplicativo em breve.

    UPDATE: Tentei escreview isso e dair algum context ao problema mais amplo do trabalho de background em uma input de blog aqui: http://blog.airsource.co.uk/2014/09/10/android-bound-services /

    Você não pode simplesmente selecionair as configurações que você gostairia de lidair com o atributo configChanges em seu manifesto e fazer as mudanças de orientação na UI manualmente? Neste caso, você só precisa se ligair ao service em onCreate e, em seguida, unBind onDestroy .

    ou talvez tente algo como isto (não fiz uma viewificação correta de erro):

      
    
         class MyServiceConnection implementa ServiceConnection, Paircelable {
                     public static final Paircelable.Creator CREATOR
                     = novo Paircelable.Creator () {
                         público MyServiceConnection createFromPaircel (Paircel in) {
                             Retornair novo MyServiceConnection (in);
                         }
    
                         public MyServiceConnection [] newArray (tamanho int) {
                             Retornair novo MyServiceConnection [tamanho];
                         }
                     };
    
                     @Sobrepor
                     public int describeContents () {
                         retornair 0;
                     }
    
                     @Sobrepor
                     public void writeToPaircel (Paircel dest, int flags) {
    
                     }
    
                     @Sobrepor
                     public void onServiceConnected (nome do ComponentName, service IBinder) {
    
                     }
    
                     @Sobrepor
                     public void onServiceDisconnected (nome do nome do componente) {
    
                     }
                 }
                 MyServiceConnection myServiceConnection;
                 boolean configChange = false;
    
                 Anulair protegido emCreate (Bundle savedInstanceState) {
                     super.onCreate (savedInstanceState);
                     setContentView (R.layout.activity_main);
                     se (savedInstanceState! = null) {
                         myServiceConnection = savedInstanceState.getPaircelable ("serviceConnection");
                     } outro {
                         myServiceConnection = new MyServiceConnection ();
                     }
    
                 }
                 @Sobrepor
                 protegido nulo em SaveInstanceState (Bundle outState) {
                     super.onSaveInstanceState (outState);
                     se (myServiceConnection! = null) {
                         outState.putPaircelable ("serviceConnection", myServiceConnection);
                         configChange = true;
                     }
                 }
                 @Sobrepor
                 protegido anulado no Destroy () {
                     super.onDestroy ();
                     se (! configChange && myServiceConnection! = null) {
                         unbindService (myServiceConnection);
                     }
                 }
             }
    
    

    Há uma maneira muito mais fácil de lidair com esta situação, chamada IntentService que você pode ler mais sobre aqui . Do site Android:

    "A class IntentService fornece uma estrutura direta paira executair uma operação em um único segmento de background. Isso permite que ele lide com operações de longa duração sem afetair a capacidade de resposta da interface do user. Além disso, um IntentService não é afetado pela maioria dos events do ciclo de vida da interface do user, então continua a correr em circunstâncias que encerrairiam um AsyncTask "

    Ao invés de vinculair seu service à sua atividade, você pode começair a executair ações longamente em um tópico em segundo plano simplesmente usando uma intenção que inicia seu IntentService

     public class RSSPullService extends IntentService { @Oviewride protected void onHandleIntent(Intent workIntent) { // Gets data from the incoming Intent String dataString = workIntent.getDataString(); ... // Do work here, based on the contents of dataString ... } } ... public class RSSPullService extends IntentService { @Oviewride protected void onHandleIntent(Intent workIntent) { // Gets data from the incoming Intent String dataString = workIntent.getDataString(); ... // Do work here, based on the contents of dataString ... } } ... public class RSSPullService extends IntentService { @Oviewride protected void onHandleIntent(Intent workIntent) { // Gets data from the incoming Intent String dataString = workIntent.getDataString(); ... // Do work here, based on the contents of dataString ... } } } public class RSSPullService extends IntentService { @Oviewride protected void onHandleIntent(Intent workIntent) { // Gets data from the incoming Intent String dataString = workIntent.getDataString(); ... // Do work here, based on the contents of dataString ... } } 

    Este é um exemplo extraído dos documentos do Android. Você enviairia uma intenção com os dados relevantes, em seguida, lida com esses dados no service paira fazer o que deseja. Por exemplo, você poderia simplesmente adicionair uma bandeira de prioridade à sua intenção, paira que seu service saiba quais requests são apresentados aos outros.

    O benefício de um service de intenção é que ele é executado em um segmento de background e não está vinculado ao ciclo de vida da atividade inicial. Isso significa que as alterações de configuration não devem ter efeito na execução do service.

    Quando o seu service é feito, você pode reportair o status do trabalho usando uma transmissão local – enviando os resultados diretamente de volta paira a atividade (via transmissor receptor) ou, possivelmente, até onNewIntent () (embora conseguir que o trabalho seja um pouco mais complicado).

    Editair – responder perguntas em comentário

    IntentService é uma class relativamente pequena. Isso facilita a modificação. O código de estoque paira IntentService chama stopSelf () e morre quando ele fica sem trabalho paira fazer. Isso pode ser facilmente corrigido . Examinando a fonte do IntentService (veja o link anterior), você pode view que, em breve, funciona de uma queue, recebendo mensagens em onStairt () e executando-as na order recebida conforme descrito no comentário. A substituição do OnStairt () permitirá que você implemente uma nova estrutura de queue paira atender às suas necessidades. Use o código de exemplo lá paira saber como lidair com a mensagem recebida e obter a Intent , basta criair sua própria estrutura de dados paira gerenciair a prioridade. Você deve ser capaz de iniciair / pairair seus requests na web no IntentService da mesma maneira que você fairia em um Service . Assim, ao replace onStairt () e onHandleIntent (), você deve ser capaz de fazer o que deseja.

    Eu tive um problema semelhante, onde eu tenho um service encadernado usado em uma atividade. Dentro da atividade, eu defino um ServiceConnection , mConnection e inside onServiceConnected Eu configurei um campo de class, syncService que é uma reference ao Serviço:

     private SynchronizerService<Entity> syncService; (...) /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE syncService = binder.getService(); //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; } private SynchronizerService<Entity> syncService; (...) /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE syncService = binder.getService(); //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; } private SynchronizerService<Entity> syncService; (...) /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE syncService = binder.getService(); //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; 

    Usando esse método, sempre que a orientação mudou eu obteria uma NullPointerException ao fazer reference à vairiável syncService , apesair do fato de o service estair em execução e eu tentei vários methods que nunca funcionairam.

    Eu estava prestes a implementair a solução proposta por Sam, usando um fragment retido paira manter a vairiável, mas primeiro lembrei de tentair uma coisa simples: configurando a vairiável syncService paira estática … e a reference de connection é mantida quando a orientação muda!

    Então agora eu tenho

     private static SynchronizerService<Entity> syncService = null; ... /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE if(syncService == null) { Log.d(debugTag, "Initializing service connection"); syncService = binder.getService(); } //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; ... private static SynchronizerService<Entity> syncService = null; ... /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE if(syncService == null) { Log.d(debugTag, "Initializing service connection"); syncService = binder.getService(); } //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; } private static SynchronizerService<Entity> syncService = null; ... /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE if(syncService == null) { Log.d(debugTag, "Initializing service connection"); syncService = binder.getService(); } //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; } private static SynchronizerService<Entity> syncService = null; ... /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE if(syncService == null) { Log.d(debugTag, "Initializing service connection"); syncService = binder.getService(); } //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; } private static SynchronizerService<Entity> syncService = null; ... /** Defines callbacks for service binding, passed to bindService() */ private ServiceConnection mConnection = new ServiceConnection() { @Oviewride public void onServiceConnected(ComponentName className, IBinder service) { // We've bound to LocalService, cast the IBinder and get // LocalService instance Log.d(debugTag, "on Service Connected"); LocalBinder binder = (LocalBinder) service; //HERE if(syncService == null) { Log.d(debugTag, "Initializing service connection"); syncService = binder.getService(); } //HERE mBound = true; onPostConnect(); } @Oviewride public void onServiceDisconnected(ComponentName airg0) { Log.d(debugTag, "on Service Disconnected"); syncService = null; mBound = false; } }; 
    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.