# Methode von Fragment durch Activity rufen scheitert



## CT9288 (22. Aug 2021)

Hallo Ihr lieben. Ich habe mal wieder ein Problem, nachdem ich schon seit 2 Stunden im Internet am suchen bin und einfach keine Lösung finde. Kurzer Umriss: es handelt sich um eine BattleActivity.java die in ihrer .xml datei ein Framelayout enthält, indem eine von zwei Fragments angezeigt werden soll. Das Anzeigen läuft und scheinbar auch der Wechsel zwischen beiden. Nun, wenn die BattleActivity startet, soll zuerst BattleTextFragment geladen werden, zusammen mit einem von 3 Strings, der zufällig generiert wird. Wenn ich diese Funktion innerhalb des Fragments ablaufen lasse, funktioniert das auch prima, aber nun möchte ich (es ist ein Kampf Szenario) die zwei Fragments über die BattleActivity laufen lassen, dafür müsste ich nun die TextView innerhalb des BattleTextFragments durch BattleActivity verändern, indem ich eine Methode gerufen hätte, die man innerhalb des Fragments findet. Aber das scheitert und ich weiß nicht weiter.

[CODE lang="java" title="BattleActivity.java"]package com.manticore.monochromia;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import android.content.Intent;
import android.os.Bundle;

public class BattleActivity extends AppCompatActivity {

    private Randomizer rnd = new Randomizer();

    private Fragment frag1 = new BattleTextFragment();

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


        SetFragment(frag1);
        Battle();
    }


    @Override
    public void onBackPressed(){
        super.onBackPressed();
        this.finish();
        Intent i = new Intent(this, DebugMenuActivity.class);
        startActivity(i);
        overridePendingTransition(0,0);
        i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
    }

    private void SetFragment(Fragment fragment){

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragmentContainer, fragment);
        fragmentTransaction.commit();

    }

    public void Battle(){
        BattleStart();
    }

    public void BattleStart(){
        BattleTextFragment frag1 = (BattleTextFragment) getFragmentManager().findFragmentById(R.id.fragBtlTxt);
        // bei dem oberen zeigt mir die Doku immer "Inconvertible types; cannot cast 'android.app.Fragment' to 'com.manticore.monochromia.BattleTextFragment'"
        int ranNum = rnd.Randymizer(0, 3);
        frag1.UpdateBattleText(ranNum);
    }

}[/CODE]

[CODE lang="xml" title="activity_battle.xml"]<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:weightSum="2"
    androidrientation="horizontal"
    android:background="@color/colorPrimary"
    tools:context=".BattleActivity">

    <RelativeLayout
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent">

        <ImageView
            android:id="@+id/delete"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_centerInParent="true"
            android:scaleType="fitXY"
            app:srcCompat="@drawable/mob_shellshock" />

    </RelativeLayout>

    <LinearLayout
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        androidrientation="vertical"
        android:weightSum="6">

        <RelativeLayout
            android:layout_weight="1"
            android:layout_width="match_parent"
            android:layout_height="0dp">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="25sp"
                android:layout_centerInParent="true"
                android:layout_toStartOf="@id/slash"
                android:layout_marginRight="10dp"
                android:text="53"/>

            <TextView
                android:id="@+id/slash"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="25sp"
                android:layout_centerInParent="true"
                android:text="/"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="25sp"
                android:layout_centerInParent="true"
                android:layout_toEndOf="@id/slash"
                android:layout_marginLeft="10dp"
                android:text="100"/>

        </RelativeLayout>

        <FrameLayout
            android:id="@+id/fragmentContainer"
            android:layout_weight="5"
            android:layout_width="match_parent"
            android:layout_height="0dp" />

    </LinearLayout>

</LinearLayout>[/CODE]

[CODE lang="java" title="BattleTextFragment.java"]package com.manticore.monochromia;

import android.content.Intent;
import android.os.Bundle;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class BattleTextFragment extends Fragment implements View.OnClickListener {

    private Randomizer rnd = new Randomizer();
    private BattleText btlTxt = new BattleText();

    ImageView changeFragment;
    public TextView battleText;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_battle_text, container, false);

        battleText = (TextView) view.findViewById(R.id.battleText);

        changeFragment = (ImageView) view.findViewById(R.id.changeFragment);
        changeFragment.setOnClickListener(this);

        return view;
    }

    @Override
    public void onClick(View v){
        //implement your things
        Fragment battleActionFragment = new BattleActionFragment();
        FragmentTransaction transaction= getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragmentContainer, battleActionFragment);
        transaction.addToBackStack(null);
        transaction.commit();
    }


    public void UpdateBattleText(int i){
        battleText.setText(btlTxt.btlIntrTxt_);
    }
}[/CODE]

[CODE lang="xml" title="fragment_battle_text.xml"]<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fragBtlTxt"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".BattleTextFragment">

    <TextView
        android:id="@+id/battleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_margin="10dp"
        android:textAlignment="center"
        android:textSize="25sp"
        android:text="@string/battleTextFragment" />

    <ImageView
        android:id="@+id/changeFragment"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_margin="10dp"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        app:srcCompat="@drawable/game_orb"/>

</RelativeLayout>[/CODE]

ich weiß nicht weiter, ich hatte so nen guten Lauf, und jetzt hänge ich mal wieder an einer so blöden Stelle. Ich wette, dass nur irgendwo wieder ein blödes Semicolon fehlt...
ich danke euch schon jetzt für euren Beistand_


----------



## CT9288 (22. Aug 2021)

Okay. Es hat sich etwas geändert.

[CODE lang="java" title="BattleActivity.java"][...]

public void BattleStart(){
        BattleTextFragment frag1 = (BattleTextFragment) getSupportFragmentManager().findFragmentById(R.id.fragBtlTxt);
        int ranNum = rnd.Randymizer(0, 3);
        frag1.UpdateBattleText(ranNum);
    }[/CODE]

habe statt getFragmentManager nun getSupportFragmentManager geschrieben. Der Fehler hat sich nun in einen nullpointer Fehler geändert.

[CODE title="Debug"]E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.manticore.monochromia, PID: 16482
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.manticore.monochromia/com.manticore.monochromia.BattleActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.manticore.monochromia.BattleTextFragment.UpdateBattleText(int)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3139)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3282)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1970)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7156)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void com.manticore.monochromia.BattleTextFragment.UpdateBattleText(int)' on a null object reference
        at com.manticore.monochromia.BattleActivity.BattleStart(BattleActivity.java:65)
        at com.manticore.monochromia.BattleActivity.Battle(BattleActivity.java:59)
        at com.manticore.monochromia.BattleActivity.onCreate(BattleActivity.java:35)
        at android.app.Activity.performCreate(Activity.java:7340)
        at android.app.Activity.performCreate(Activity.java:7331)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1275)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3119)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3282) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1970) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7156) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975) 
[/CODE]


----------



## Jw456 (22. Aug 2021)

CT9288 hat gesagt.:


> Okay. Es hat sich etwas geändert.
> 
> [CODE lang="java" title="BattleActivity.java"][...]
> 
> ...


Erstmal solltest du prüfen ob überhaupt das richtige Fragment geladen wurde (angezeigt wird)


```
public void BattleStart() {

        if (findViewById(R.id.fragBtlTxt) != null) {
            BattleTextFragment frag1 = (BattleTextFragment) getSupportFragmentManager().findFragmentById(R.id.fragBtlTxt);
            frag1.UpdateBattleText(ranNum);
        }
    }
```


----------



## Jw456 (22. Aug 2021)

Frage zum  ersten Start deines Fragment.
was ist die Variable "fragment"

```
fragmentTransaction.replace(R.id.fragmentContainer, fragment);
```
wo und wie wird die erstellt?

Zweitens macht man das setzen des ersten Fragment nicht mit replace sondern mit add.
Du hast ja noch kein Fragment geladen was du tauschen willst.


----------



## Jw456 (22. Aug 2021)

welche compileSdkVersion  und targetSdkVersion benutzt du ? 
denn getSupportFragmentManager ist seit API 28 veraltet. 
Ich denke du benutzt auch androidx .


----------



## CT9288 (22. Aug 2021)

Vielen Dank für deine Antwort, ich versuche mal, deine Gegenfragen zu beantworten:
1.    Ja, augenscheinlich benutze ich androidx, zumindest werden die meisten Importe mit androidx initiiert. Was genau hat es damit auf sich? Zur Info, alles was ich lerne und weiß, weiß ich aus Tutorials auf Youtube und ein paar anderen Seiten, dass viele der Tutorials veraltet sind, leuchtet mir ein, aber andere Quellen habe ich teilweise nicht, die es mir so verständlich erklären, wie die Video-Tutorials.
2.    compileSdkVersion = 29
3.    targetSdkVersion =29
4.    Wenn es nicht getFragmentManager ist und auch nicht getSupportFragmentManager, dann, keine Ahnung
5.    Fragment in diesem Zusammenhang ist ja nur eine Methodeninterne Variabel.
Ich habe ein neues Objekt meines Fragments erstellt:
[…]
private Fragment frag1 = new BattleTextFragment();
[…]
Dann in meiner onCreate
SetFragment(frag1);

Und das ist die ganze Methode SetFragment:
private void SetFragment(Fragment fragment){

        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragmentContainer, fragment);
        fragmentTransaction.commit();

    }

Du siehst, bei fragment handelt es sich um mein frag1, und ja, womöglich ist replace falsch, aber laden kann ich das Fragment damit. Es gibt nur ein Problem, wenn ich über die Activity eine TextView im Fragment verändern möchte.
Wenn ich das nicht zum laufen bekomme, dann muss ich mir ne Alternative suchen.
Mein Hintergrundgedanke ist, wie bei Pokemon oder so, du hast die Auswahl aus Angriff, Items, etc. wenn du dann eines gewählt hast, verschwindet die Auswahl und macht Platz für ein Textfeld, in dem der Kampfablauf dargestellt wird. So ähnlich hätte ich es hier gerne.


----------



## Jw456 (23. Aug 2021)

Du importirst 
import androidx.fragment.app.FragmentManager;
Also solltest du auch den benutzen und nicht den aus den Support libs. 

Und das im gesamten Projekt gleich. Kein Mischen zwischen Support und nicht Support. 

Wenn du denn menager im Fragment brauchst dann benutze den Context der Activity dazu.


----------



## Jw456 (23. Aug 2021)

versuche  es mit dem getSupportFragmentManager()
AppCompatActivity erbt von








						FragmentActivity  |  Android Developers
					






					developer.android.com
				




Wird denn dein  erstes Fragment überhaupt in den Frame Layout angezeigt auf dem Bildschirm?


Was ich auch nicht gut finde ist das du eine Instanzvariable „frag1“ hast.
Und in der Methode BattleStart() eine lokale Variable mit dem gleichen Bezeichner erstellt.  Das führt oft zu Verwechslungen.
Auch sollten Methoden Namen  mit kleinen  Buchstaben  beginnen.  Am besten mit einem kleinen Verb.

*Mit*

```
fragment =  getSupportFragmentManager().findFragmentById(R.id.fragment_container);
```
*bekommst du die Instanz des letzten hinzugefügten Fragments .*

deshalb vorher prüfen  ob die id des layouts auch gefunden wird. Und auch das Fragment aus  dem du eine Methode aufgufen willst geladen ist.


```
public void BattleStart() {

        if (findViewById(R.id.fragBtlTxt) != null) {
            BattleTextFragment frag1 = (BattleTextFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentContainer);
            frag1.UpdateBattleText(ranNum);
        }
    }
```


----------

