Rufen Sie die Aktivitätsmethode vom Adapter aus auf

118

Ist es möglich, eine Methode aufzurufen, die in Activityfrom definiert ist ListAdapter?

(Ich will ein , um Buttonin list'sReihe und wenn diese Taste angeklickt wird, soll es das Verfahren durchführt, die in entsprechender Aktivität definiert ist. Ich habe versucht, Satz onClickListenerin meiner , ListAdapteraber ich weiß nicht , wie diese Methode nennen, was sein Weg ist. ..)

Wenn ich verwendet Activity.this.method()habe, erhalte ich die folgende Fehlermeldung:

No enclosing instance of the type Activity is accessible in scope

Irgendeine Idee ?

user1602687
quelle
Sie können activity.this in keiner anderen Klasse aufrufen, es sei denn, es handelt sich um eine innere Klasse dieser Aktivität. Folgen Sie @Eldhose M Babu Lösung für Ihren Fall
Archie.bpgc

Antworten:

306

Ja, du kannst.

Im Adapter Neues Feld hinzufügen:

private Context mContext;

Fügen Sie im Adapterkonstruktor den folgenden Code hinzu:

public AdapterName(......, Context context) {
  //your code.
  this.mContext = context;
}

In der getView (...) des Adapters:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
  @Override
  public void onClick(View v) {
    if (mContext instanceof YourActivityName) {
      ((YourActivityName)mContext).yourDesiredMethod();
    }
  }
});

Ersetzen Sie durch Ihre eigenen Klassennamen, in denen Sie Ihren Code, Ihre Aktivität usw. sehen.

Wenn Sie denselben Adapter für mehr als eine Aktivität verwenden müssen, gehen Sie wie folgt vor:

Erstellen Sie eine Schnittstelle

public interface IMethodCaller {
    void yourDesiredMethod();
}

Implementieren Sie diese Schnittstelle in Aktivitäten, für die Sie diese Funktion zum Aufrufen von Methoden benötigen.

Rufen Sie dann in Adapter getView () wie folgt auf:

Button btn = (Button) convertView.findViewById(yourButtonId);
btn.setOnClickListener(new Button.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mContext instanceof IMethodCaller) {
            ((IMethodCaller) mContext).yourDesiredMethod();
        }
    }
});

Du bist fertig. Wenn Sie diesen Adapter für Aktivitäten verwenden müssen, für die dieser Aufrufmechanismus nicht erforderlich ist, wird der Code nicht ausgeführt (wenn die Prüfung fehlschlägt).

Eldhose M Babu
quelle
29
Da dies eine beliebte Frage ist, würde ich dringend empfehlen, diese Lösung NICHT ZU VERWENDEN. Sie sollten hier das Casting von Klassen vermeiden, da dies zu Laufzeitausnahmen führen kann.
Igor Filippov
3
Eldhose bro, ich habe nichts gegen dich, aber die Antwort unten ist die beste Vorgehensweise. Sie können sogar Kommentare lesen. Sie sollten mContext nicht in Ihre Aktivität umwandeln, da Sie die Wiederverwendung von Code vermeiden. Jetzt kann dieser Adapter nur innerhalb der Aktivität verwendet werden, in die Sie Ihre mContext-Variable umgewandelt haben. Wenn Sie einen Listener definiert haben, können Sie denselben Adapter in einer anderen Aktivität wiederverwenden. Vertrauen Sie mir, ich habe genug Zeit in der Industrie verbracht und ich versuche nur, Ihnen hier zu helfen. Bitte nehmen Sie es nicht persönlich.
Varundroid
2
Diese Lösung ist eine der besten, die ich je auf SO gefunden habe. Vielen Dank, Herr Babu. Wenn Sie die Methoden der Aktivität auf diese Weise aufrufen, erhält die gesamte App eine Leistungssteigerung von 500% -> Ich muss die Datenbank im Adapter, auf den ich zugreifen muss, nicht neu laden. "Jahre in der Industrie" interessieren mich nicht, ich suche nach stabilen und funktionierenden Lösungen und ich bin mir ziemlich sicher, dass ich keinen besseren Weg finden werde, um Zugang zu bekommen. Vielleicht könnte ich die Datenbank als Singleton einrichten, aber auf diese Weise möchte ich mein Projekt nicht "entstrukturieren".
Martin Pfeffer
2
@RAM Wenn Sie dieselbe Methode in mehr als einer Aktivität aufrufen müssen, müssen Sie eine Schnittstelle mit diesem Methodennamen erstellen. Implementieren Sie diese Schnittstelle dann in alle Aktivitäten, für die Sie den Methodenaufruf benötigen. Überprüfen Sie dann im Klick-Listener die Instanz Ihrer Benutzeroberfläche, anstatt den Aktivitätsnamen zu verwenden.
Eldhose M Babu
1
Hervorragende Antwort. Daumen hoch
Alok Rajasukumaran
126

Sie können es so machen:

Schnittstelle deklarieren:

public interface MyInterface{
    public void foo();
}

Lassen Sie Ihre Aktivität es umsetzen:

public class MyActivity extends Activity implements MyInterface{
    public void foo(){
        //do stuff
    }
}

Übergeben Sie dann Ihre Aktivität an ListAdater:

public MyAdapter extends BaseAdater{
    private MyInterface listener;

    public MyAdapter(MyInterface listener){
        this.listener = listener;
    }
}

Und irgendwo im Adapter, wenn Sie diese Aktivitätsmethode aufrufen müssen:

listener.foo();
Igor Filippov
quelle
5
Ich habe zuerst an die obige Methode gedacht, wie Sie es bei Fragmenten tun würden, aber dies ist die beste Lösung!
Brux
1
Was ist mein InterfaceListener? Wie kann es initialisiert werden? public MyAdapter (MyInterface Listener) {this.listener = Listener; }
Gilberto Ibarra
6
Wie übergibt man die Schnittstelle an den Adapter (aus der Aktivität)
Brandon
1
@Brandon können Sie übergeben, es ist Konstruktorparameter im Adapter.
Igor Filippov
5
@Brandon, füge einfach 'this' hinzu, um die Schnittstelle an den Adapter zu übergeben. MyAdapter = new MyAdapter (this);
Ajinkya
67

Original:

Ich verstehe die aktuelle Antwort, brauchte aber ein klareres Beispiel. Hier ist ein Beispiel dafür, was ich mit einem Adapter(RecyclerView.Adapter) und einem verwendet habe Activity.

In Ihrer Aktivität:

Dies wird das implementieren interface, was wir in unserem haben Adapter. In diesem Beispiel wird es aufgerufen, wenn der Benutzer auf ein Element im Feld klickt RecyclerView.

public class MyActivity extends Activity implements AdapterCallback {

    private MyAdapter myAdapter;

    @Override
    public void onMethodCallback() {
       // do something
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        myAdapter = new MyAdapter(this);
    }
}

In Ihrem Adapter:

In der Activityhaben wir unsere initiiert Adapterund dies als Argument an den Konstruktor weitergegeben. Dies wird interfaceunsere Rückrufmethode einleiten . Sie sehen, dass wir unsere Rückrufmethode für Benutzerklicks verwenden.

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private AdapterCallback adapterCallback;

    public MyAdapter(Context context) {
        try {
            adapterCallback = ((AdapterCallback) context);
        } catch (ClassCastException e) {
            throw new ClassCastException("Activity must implement AdapterCallback.", e);
        }
    }

    @Override
    public void onBindViewHolder(MyAdapter.ViewHolder viewHolder, int position) {
        // simple example, call interface here
        // not complete
        viewHolder.itemView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                try {
                    adapterCallback.onMethodCallback();
                } catch (ClassCastException e) {
                   // do something
                }
            }
        });
    }

    public static interface AdapterCallback {
        void onMethodCallback();
    }
}
Jared Burrows
quelle
6
danke dafür, es ist genau das, wonach ich gesucht habe. up-Abstimmung
Nactus
das hat bei mir funktioniert! imo, vollständigster Arbeitscode bisher!
publicknowledge
2
Vielen Dank für diese Lösung
Steve
4
Diese Antwort sollte mehr positive Stimmen haben, es ist eine saubere und perfekte Lösung.
Opiatefuchs
Hi @Jared - Können Sie das gleiche Beispiel EventBuswie vorgeschlagen korrigieren ?
Tohid
13

Einfach und einfach.

Verwenden Sie dies in Ihrem Adapter einfach.

((YourParentClass) context).functionToRun();

Ck Maurya
quelle
4
Dies ist keine gute Vorgehensweise, da Sie Ihre Klasse darauf beschränken, nur mit dem YourParentClass-Typ anstelle einer Klasse zu arbeiten. Sie funktioniert jedoch, wenn Sie sich nicht für die Wiederverwendung interessieren. Wenn Sie auch eine Klasse umbenennen, bricht der Code ...
Gustavo Baiocchi Costa
7

Ein weiterer Weg ist ::

Schreiben Sie eine Methode in Ihren Adapter, sagen wir public void callBack () {}.

Wenn Sie jetzt ein Objekt für den Adapter in der Aktivität erstellen, überschreiben Sie diese Methode. Die Override-Methode wird aufgerufen, wenn Sie die Methode im Adapter aufrufen.

Myadapter adapter = new Myadapter() {
  @Override
  public void callBack() {
    // dosomething
  }
};
Prashanth Debbadwar
quelle
5

Für Kotlin:

Rufen Sie in Ihrem Adapter einfach an

(context as Your_Activity_Name).yourMethod()
Numair
quelle
0
if (parent.getContext() instanceof yourActivity) {
  //execute code
}

Diese Bedingung ermöglicht es Ihnen, etwas auszuführen, wenn die Aktivität, die die GroupViewanfordernden Ansichten von der getView()Methode von Ihnen hat, adapteristyourActivity

HINWEIS: parentIst das GroupView

Abd Salam Baker
quelle
Diese GroupView fordert Ansichten vom Adapter an, wenn sie die getView()Methode aufruft. Wir erhalten also den Kontext dieser GroupView und untersuchen sie anhand der obigen Bedingung
Abd Salam Baker,
0

In Kotlin gibt es jetzt eine sauberere Möglichkeit, Lambda-Funktionen zu verwenden, ohne dass Schnittstellen erforderlich sind:

class MyAdapter(val adapterOnClick: (Any) -> Unit) {
    fun setItem(item: Any) {
        myButton.setOnClickListener { adapterOnClick(item) }
    }
}

class MyActivity {
    override fun onCreate(savedInstanceState: Bundle?) {
        var myAdapter = MyAdapter { item -> doOnClick(item) }
    }


    fun doOnClick(item: Any) {

    }
}
Klinge
quelle