E 'una buona idea usare il mio meccanismo di callback invece dell'implementazione standard come startActivityForResult?

0

Sto provando a creare una semplice app che ha 2 attività, che inseriscono il testo in un'attività e poi la visualizza sulla barra del titolo se un'altra attività:

EditTextActivity:

MainActivity:

SocheilmodostandardperimplementarloèutilizzarestartActivityForResult:

publicclassEditTextActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_text_view);}publicvoidbuttonPressed(Viewview){Intentintent=newIntent();Intent.putExtra("result",    ((EditText)this.findViewById(R.id.editText)).getEditableText().toString());
        this.setResult(0,intent);
        finish();
    }
}

-

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.startActivityForResult(new     Intent(this,EditTextActivity.class),0);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        this.setTitle(data.getExtras().getString("result"));
    }
}

ma penso che questo meccanismo non sia conveniente: se ho più startActivityForResult, il mio onActivityResult sarebbe molto lungo. Inoltre ha una scarsa leggibilità perché la logica per gestire il risultato è all'interno diActivityResult, che è molto lontano da startActivityForResult.

Attualmente Android non può inserire oggetti (callback) nell'intento, quindi cerco di implementare il mio meccanismo di richiamo callback: che apre una mappa statica per memorizzare il callback da un'altra attività:

public class EditTextActivity extends AppCompatActivity {
    public static HashMap<Integer,Callback> callbackMap=new HashMap<>();

    public static void startActivity(AppCompatActivity activity,Callback callback){
    //add callback
    int activityObjectId=System.identityHashCode(activity);
    callbackMap.put(activityObjectId,callback);

    Intent intent=new Intent(activity,EditTextActivity.class);
    intent.putExtra("activityObjectId",System.identityHashCode(activity));
    activity.startActivity(intent);
}

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_text_view);
    }

    public void buttonPressed(View view){
        int activityObjectId=this.getIntent().getIntExtra("activityObjectId",0);
        //remove callback      callbackMap.get(activityObjectId).onActivityResult(((EditText)this.findViewById(R.id.editText)).getEditableText().toString());
        callbackMap.remove(activityObjectId);
        finish();
    }

    public interface Callback{
        void onActivityResult(String s);
    }
}

quindi avvolgere il codice suActivityResult in un oggetto e quindi inserirlo nella mappa prima di startActivity:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        EditTextFragment.startActivity(this,R.id.rootView, new EditTextFragment.Callback() {
            @Override
            public void onActivityResult(String s) {
                MainActivity.this.setTitle(s);
            }
        });
    }
}

Ho intenzione di implementare questo meccanismo di callback (se possibile) in attività, frammenti e altri componenti che richiedono in seguito il callback handler come metodo standard, perché penso che mi permetta di usare un modo unico per implementare i callback, è una buona idea farlo?

    
posta ggrr 31.07.2017 - 04:55
fonte

1 risposta

3

Globali statici dovrebbero essere evitati quando possibile. Loro presentano molti più problemi di quello che risolvono, e di solito ci sono design cambiamenti che possono eliminare la necessità di uno stato globale.

I think [the framework provided] mechanism is not convenient: if I have multiple startActivityForResult, my onActivityResult would be very long. Also it has poor readability because the logic to handle the result is inside onActivityResult, which is far away from startActivityForResult.

Sono d'accordo con la tua analisi. Lascia che ti suggerisca un design diverso che risolva i tuoi dubbi senza utilizzare lo stato globale.

interface ActivityResultListener {
  void onActivityResult(int resultCode, Intent data);
} 

public class CallbackResultActivity extends AppCompatActivity {
  private final Map<Integer, ActivityResultListener> callbacks = new HashMap<>();
  private final AtomicInteger requestCode = new AtomicInteger(0);

  protected startActivityForResult(
    Intent intent, 
    ActivityResultListener callback
  ) {
    int newRequestCode = requestCode.incrementAndGet();
    callbacks.put(newRequestCode, callback);
    startActivityForResult(intent, newRequestCode);
  }

  protected final onActivityResult(int requestCode, int resultCode, Intent data) {
    ActivityResultListener callback = callbacks.get(requestCode);
    if (callback != null) {
      callback.onActivityResult(resultCode, data);
      callbacks.remove(requestCode);
    }
  }
}

Questo crea un'estensione sulla base AppCompatActivity che nasconde la nozione di requestCodes e consente di chiamare startActivityForResult e passare un callback. È abbastanza simile alla tua implementazione, ma è generica, riutilizzabile, verificabile e EditTextActivity non deve sapere nulla sui callback. Puoi usarlo in questo modo:

public class MainActivity extends CallbackResultActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.startActivityForResult(new Intent(this, EditTextActivity.class), 
          new ActivityResultListener() {
            @Override
            public void onActivityResult(int resultCode, Intent data) {
                this.setTitle(data.getExtras().getString("result"));
            }
          });
    }
}
    
risposta data 31.07.2017 - 06:15
fonte

Leggi altre domande sui tag