0

To start with, I'm still new to Android development, I've asked similar questions here before How to make my Fragment make use of my Activity Data? and How to send data from Activity to Fragment?(Android) But it seems that most people did not quite understand what I mean, so let me explain better. Suppose I have a TextView:

<TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:text="@string/current"
            android:textColor="#FF3D19"
            android:textSize="24sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.498"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

and a Button:

<Button
            android:id="@+id/button2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="14dp"
            android:layout_marginTop="92dp"
            android:shadowColor="#FFFFFF"
            android:text="Click"
            android:textColor="#FF5722"
            app:layout_constraintStart_toStartOf="@+id/imageView3"
            app:layout_constraintTop_toTopOf="@+id/imageView3" /> 

in my FirstFragment layout.xml, then i want to call them from my MainActivity i.e current_temp = findViewById(R.id.textView10); to get data i.e current_temp.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃")); from a weather API and findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {. Android Studio will not allow you to just use them like that, so i get this error:

java.lang.NullPointerException: Attempt to invoke virtual method 'void android.view.View.setOnClickListener(android.view.View$OnClickListener)' on a null object reference

whenever I run the app. I don't get any other error before running, so the reason is that I've not instantiated any method or maybe callback or interface that will tell the Activity to make use of my fragment's TextViews and Button. So that's what I've been stuck with for days trying to fix, but most people just misunderstood me and started suggesting I should learn ViewModel or LiveData. I watched several tutorials on ViewModel including Codinginflow, they never talked about linking activity to fragment TextViews, they only made a fragment send data to another fragment which is not what I want. My request is similar to this Android: Can't update textview in Fragment from Activity. NullPointerException tried and failed, So I need step by step procedures on how to apply it.

Full Code: HomeActivity

public class HomeActivity extends AppCompatActivity {
    public static String BaseUrl = "http://api.openweathermap.org/";
    public static String AppId = "";
    public static String lat = "9.0574";
    public static String lon = "7.4898";
    // User Timezone name, current time, current temperature, current condition, sunrise, sunset, temperature, pressure, humidity, wind_speed, visibility, UV Index
    TextView time_zone, time_field, current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, UV_out;
    ConstraintLayout constraintLayout;
    public static int count = 0;
    int[] drawable = new int[]{R.drawable.dubai, R.drawable.central_bank_of_nigeria, R.drawable.eiffel_tower, R.drawable.hong_kong, R.drawable.statue_of_liberty};
    Timer _t;

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

        time_zone = findViewById(R.id.textView9);
        time_field = findViewById(R.id.textView4);
        current_temp = findViewById(R.id.textView10);
        current_output = findViewById(R.id.textView11);
        rise_time = findViewById(R.id.textView25);
        set_time = findViewById(R.id.textView26);
        temp_out = findViewById(R.id.textView28);
        Press_out = findViewById(R.id.textView29);
        Humid_out = findViewById(R.id.textView30);
        Ws_out = findViewById(R.id.textView33);
        Visi_out = findViewById(R.id.textView34);
        UV_out = findViewById(R.id.textView35);

        BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
        NavController navController = Navigation.findNavController(this, R.id.fragment);
        NavigationUI.setupWithNavController(bottomNavigationView, navController);

        findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getCurrentData();
                constraintLayout = findViewById(R.id.layout);
                constraintLayout.setBackgroundResource(R.drawable.dubai);
                _t = new Timer();
                _t.scheduleAtFixedRate(new TimerTask() {
                    @Override
                    public void run() {
                        runOnUiThread(new Runnable() { // run on ui thread
                            @Override
                            public void run() {
                                if (count < drawable.length) {

                                    constraintLayout.setBackgroundResource(drawable[count]);
                                    count = (count + 1) % drawable.length;
                                }
                            }
                        });
                    }
                }, 5000, 5000);
            }

            void getCurrentData() {
                Retrofit retrofit = new Retrofit.Builder().baseUrl(BaseUrl).addConverterFactory(GsonConverterFactory.create()).build();
                WeatherService service = retrofit.create(WeatherService.class);
                Call<WeatherResponse> call = service.getCurrentWeatherData(lat, lon, AppId);
                call.enqueue(new Callback<WeatherResponse>() {
                    @Override
                    public void onResponse(@NonNull Call<WeatherResponse> call, @NonNull Response<WeatherResponse> response) {
                        if (response.code() == 200) {
                            WeatherResponse weatherResponse = response.body();
                            assert weatherResponse != null;

                            assert response.body() != null;
                            time_zone.setText(response.body().getTimezone());
                            time_field.setText(response.body().getCurrent().getDt());
                            current_temp.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                            current_output.setText(response.body().getCurrent().getWeather().get(0).getDescription());
                            rise_time.setText(getString(R.string.blank, response.body().getCurrent().getSunrise() + " AM"));
                            set_time.setText(getString(R.string.blank, response.body().getCurrent().getSunset() + " PM"));
                            temp_out.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                            Press_out.setText(getString(R.string.blank, response.body().getCurrent().getPressure() + " hpa"));
                            Humid_out.setText(getString(R.string.blank, response.body().getCurrent().getHumidity() + " %"));
                            Ws_out.setText(getString(R.string.blank, response.body().getCurrent().getWindSpeed() + " Km/h"));
                            Visi_out.setText(getString(R.string.blank, response.body().getCurrent().getVisibility() + " m"));
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<WeatherResponse> call, @NonNull Throwable t) {
                    }
                });
            }
        });
    }
}

FirstFragment

public class FirstFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;

public FirstFragment() {
    // Required empty public constructor
}

/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment SecondFragment.
 */
// TODO: Rename and change types and number of parameters
public static FirstFragment newInstance(String param1, String param2) {
    FirstFragment fragment = new FirstFragment();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}

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

Taking the whole functionality to Fragment won't work too, because retrofit can only be called from Activity. But if you have any solid suggestions, I'll appreciate it.

Leo
  • 2,097
  • 21
  • 35
Chinez
  • 551
  • 2
  • 6
  • 29
  • 1
    Have a look here: https://stackoverflow.com/a/35747982/6383029 – Mustansir Jan 11 '21 at 16:35
  • So you want to access the button and textview in the fragment from the activity? – rahat Jan 11 '21 at 16:41
  • I would suggest you take the whole functionality related to the `first fragment` into the `firstfragment` class, Lets say you have 3 or more fragments then keeping all three fragments' functionality in the activity would be tough and would discourage the usage of the fragment, It would be the best approach to take the things related to a particular fragment into that frament. – rahat Jan 11 '21 at 16:47
  • @rahat I can't do that because I can't call retrofit in my fragment and the activity has some textviews too – Chinez Jan 11 '21 at 19:47
  • @Mustansir didn't work for me – Chinez Jan 11 '21 at 19:54
  • @Chinez can you be a little more explicit on what you are trying to achieve here? Are you trying to update `textView` in a `fragment` from the `activity` which holds these `fragments`? Or is it the other way around? – Mustansir Jan 12 '21 at 07:33
  • @Mustansir I have textviews and button in my fragment.xml, I want to use them in my activity – Chinez Jan 12 '21 at 10:06
  • 1
    @Chinez What do you mean by " use them in activity"? Do you want it to update from activity? – Mustansir Jan 12 '21 at 13:55
  • @Mustansir I don't know what you mean by update, but I'm using the textviews to fetch data, that's the simplest way I can put it – Chinez Jan 13 '21 at 15:44
  • @Chinez does the problem solved? – Ticherhaz FreePalestine Jan 20 '21 at 14:02
  • @Ticherhaz no, tried all the suggestions to no avail – Chinez Jan 20 '21 at 14:48
  • @Chinez from your question, you already tried to put Retrofit inside the Fragment and it is not working? – Ticherhaz FreePalestine Jan 20 '21 at 14:53
  • It worked when I tried putting it in @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { but showed errors with the setup a person suggested. The problem is that most people don't tell me exactly where to place codes in. Fragment is to big and contains onCreate, OnCreateView and the rest. They should be saying the specific places the codes should be called in for easier setting – Chinez Jan 20 '21 at 15:03
  • @Chinez What was the error? I put these codes (Retrofit) at the `onCreateView` – Ticherhaz FreePalestine Jan 20 '21 at 15:07
  • @Ticherhaz please check my comments on Umair Saeed answer – Chinez Jan 20 '21 at 15:11
  • I would recommend you to move your `R.id.textView9` and the others to fragment.xml. Let the activity is only for bottom navigation and fragment adapter. All the views will be inside the fragment.xml and fragment.class @Chinez – Ticherhaz FreePalestine Jan 20 '21 at 15:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/227603/discussion-between-chinez-and-ticherhaz). – Chinez Jan 20 '21 at 15:34

5 Answers5

2

I suggest you two ways can update data to Text View of Fragment from Activity.

1. Call method update Text View of fragment from Activity (simple way)

  • Create a method updateData()in fragment class to update data to Text View.
  • You declare a fragment parameter in activity class and assign to this parameter when add fragment to activity.
  • When you receive data from api in activity, call fragment.updateData()

fragment_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <TextView
        android:id="@+id/temp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/hud"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:text="TextView"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/temp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

home_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

FirstFragment.kt

class FirstFragment : Fragment(R.layout.fragment_layout) {

    private lateinit var temp: TextView
    private lateinit var hud: TextView

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        temp = view.findViewById(R.id.temp)
        hud = view.findViewById(R.id.hud)
    }

    fun setDataToView(data: WeatherResponse) {
        temp.text = data.temp
        hud.text = data.hud
    }
}

HomeActivity.kt

class HomeActivity: AppCompatActivity() {

    private val fragment = FirstFragment()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.home_activity)

        addFragment()

        fragment.view?.findViewById<Button>(R.id.button2)?.setOnClickListener {
            getCurrentData()
        }


    }

    private fun addFragment(){
        val fm = supportFragmentManager
        fm.beginTransaction().replace(R.id.container, fragment, "FirstFragment").commit()
    }

    private fun getCurrentData(){
        //Your retrofit code in here. I only show code in onResponse()
        //.....
        @Override
        public void onResponse(@NonNull Call<WeatherResponse> call, @NonNull Response<WeatherResponse> response) {
            if (response.code() == 200) {
                fragment.setDataToView(response)
            }
        }

        //....
    }
}

2. Using ViewModel

  • Create a SharedViewModel class with a livedata parameter.

  • In activity, on onCreate() you create a SharedViewModel paramerter like below:

    SharedViewModel viewModel = new SharedViewModel(this).get(SharedViewModel .class);

  • In fragment, on onActivityCreated() you create a SharedViewModel paramerter like below:

    SharedViewModel viewModel = new SharedViewModel(requireActivity()).get(SharedViewModel .class);

  • Finally, you have same ViewModel instance in activity and fragment because both using activity context. When you receive data from api, update your livedata parameter in activity, fragment also receives livedata parameter onChanged event and then you can update Text View.

Tungken
  • 1,917
  • 1
  • 15
  • 18
  • for no 1, you did not show me how to do it, no 2 you did not show me where to place them, I put both in the oncreate and getting Cannot resolve symbol 'SharedViewModel' – Chinez Jan 11 '21 at 19:45
  • Okay. On the first one, what do I put in "yourData"? looking at my textviews for example? – Chinez Jan 12 '21 at 10:09
  • Do I write like my textviews and button there like i.e time_zone, time_field, click or I just use "yourData" how it is? – Chinez Jan 12 '21 at 10:12
  • @Chinez "yourData" is response data from api. Your all Text View is on fragment, right? And you want send data from api in activity to fragment to update text view fields with this data?. If all right, you must put all text view to fragment and then call api in activity, pass api data to "your data" like the way one. – Tungken Jan 12 '21 at 15:00
  • Please take me like as a noob, I'm just barely 4 months on Android, so I'm not so familiar with most of these big concepts. In order for me to get my response from the API, the activity needs to be linked to where my textviews are(fragment) if not I get an NPE, that's what I'm trying to do. You said "you must put all textview to fragment" (that's where my textviews are in my fragment's layout.xml but I'm calling them in my activity, so I need to create a method, callback/interface to link them. That's what I need help for – Chinez Jan 12 '21 at 17:10
  • 2
    @Chinez Normally, you shouldn't call view of fragment in activity. Instead, you call a function from fragment which update all text view with data. If you want still call view of fragment from activity, you must follow step 1 and 2 in first way. And then you call view like this `fragment.getView(). findViewById(R.id.textView9).setText(response.body().getTimezone());` when you receive response from api – Tungken Jan 13 '21 at 16:18
  • Still didn't work, followed the full procedure. but thanks – Chinez Jan 13 '21 at 16:45
  • @Chinez I add full simple code to my answer in Kotlin. Please read carefully! – Tungken Jan 14 '21 at 04:15
  • okay, but since you know I asked the question in java, why answering in kotlin? I know they're somehow related but I have no knowledge of kotlin for now, planning on learning after using java for a while – Chinez Jan 14 '21 at 11:59
  • I accepted this because calling the view from the fragment was a better suggestion – Chinez Feb 23 '21 at 01:07
1

There are many ways to achieve what you are tying to do, I will be using RxJava.

  1. Add RxJava in your project:

implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'

  1. Create a POJO class to hold your data which then later can be transferred using RxJava bus
public class WeatherReport {

    private String time_zone;
    private String time_field;
    private String current_temp;
    private String current_output;
    private String rise_time;
    private String set_time;
    private String temp_out;
    private String Press_out;
    private String Humid_out;
    private String Ws_out;
    private String Visi_out;

    public String getCurrent_output() {
        return current_output;
    }

    public String getCurrent_temp() {
        return current_temp;
    }

    public String getHumid_out() {
        return Humid_out;
    }

    public String getPress_out() {
        return Press_out;
    }

    public String getRise_time() {
        return rise_time;
    }

    public String getSet_time() {
        return set_time;
    }

    public String getTemp_out() {
        return temp_out;
    }

    public String getTime_field() {
        return time_field;
    }

    public String getTime_zone() {
        return time_zone;
    }

    public String getVisi_out() {
        return Visi_out;
    }

    public String getWs_out() {
        return Ws_out;
    }

    public void setCurrent_output(String current_output) {
        this.current_output = current_output;
    }

    public void setCurrent_temp(String current_temp) {
        this.current_temp = current_temp;
    }

    public void setHumid_out(String humid_out) {
        Humid_out = humid_out;
    }

    public void setPress_out(String press_out) {
        Press_out = press_out;
    }

    public void setRise_time(String rise_time) {
        this.rise_time = rise_time;
    }

    public void setSet_time(String set_time) {
        this.set_time = set_time;
    }

    public void setTemp_out(String temp_out) {
        this.temp_out = temp_out;
    }

    public void setTime_field(String time_field) {
        this.time_field = time_field;
    }

    public void setTime_zone(String time_zone) {
        this.time_zone = time_zone;
    }

    public void setVisi_out(String visi_out) {
        Visi_out = visi_out;
    }

    public void setWs_out(String ws_out) {
        Ws_out = ws_out;
    }
}
  1. Create a RxJava bus
import io.reactivex.rxjava3.subjects.BehaviorSubject;

public class RxJavaBus {

    private static final BehaviorSubject<WeatherReport> behaviorSubject
            = BehaviorSubject.create();


    public static BehaviorSubject<WeatherReport> getSubject() {
        return behaviorSubject;
    }

}
  1. Now from your activity(or from wherever you want to transfer data) use RxBus like this:
WeatherReport weatherReport = new WeatherReport();
        
weatherReport.setCurrent_output("Some DATA");
weatherReport.setCurrent_temp("Some DATA");
weatherReport.setHumid_out("Some DATA");
weatherReport.setPress_out("Some DATA");
weatherReport.setRise_time("Some DATA");
weatherReport.setSet_time("Some DATA");
weatherReport.setTime_field("Some DATA");
weatherReport.setVisi_out("Some DATA");
weatherReport.setTemp_out("Some DATA");
weatherReport.setWs_out("Some DATA");
weatherReport.setTime_zone("some DATA");

RxJavaBus.getSubject().onNext(weatherReport);
  1. Now you receive your data in your fragment (or wherever you want) like this:
RxJavaBus.getSubject().subscribe(weatherReportFromActivity -> {

            weatherReportFromActivity.getCurrent_output();
            weatherReportFromActivity.getCurrent_temp();
            weatherReportFromActivity.getHumid_out();
            weatherReportFromActivity.getPress_out();
            weatherReportFromActivity.getRise_time();
            weatherReportFromActivity.getSet_time();
            weatherReportFromActivity.getWs_out();
            weatherReportFromActivity.getTime_zone();
            weatherReportFromActivity.getVisi_out();
            weatherReportFromActivity.getTime_field();
            weatherReportFromActivity.getTemp_out();
});
Mustansir
  • 2,445
  • 1
  • 21
  • 32
  • First, I followed all your methods step by step. Everything worked well except step(5). When I placed it in my fragment's oncreate method, they said: Result of '' is ignored e.g Result of 'getCurrent_output()' is ignored. Also, you didn't address the button (findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {). Then is there anything i should remove before using this rxjava? – Chinez Jan 13 '21 at 22:26
  • Yes, it would ignore the results. To get the results, you would need to store for example `String myReport = weatherReportFromActivity.getCurrent_output();` and then use it to set on your `textView`. Or you can directly place your `textView` inside `subscribe` method – Mustansir Jan 14 '21 at 05:52
  • Variable 'myReport' is never used – Chinez Jan 14 '21 at 12:03
  • Where are your textview situated which you want to update? – Mustansir Jan 14 '21 at 18:19
  • Only time_zone and time_field are in the activity, the rest are in fragment(including the button) and I'm calling the fragment's view from the activity – Chinez Jan 14 '21 at 21:11
  • 1
    You cannot call Fragment's view unless you have a reference to it. Update your code with `textView` in `fragment` – Mustansir Jan 15 '21 at 06:00
  • Okay, can you please suggest a snippet to follow from the code I posted? Because this means I may have to call retrofit from fragment too – Chinez Jan 15 '21 at 08:19
  • I tried using the fragment myself but I'm unable to. It seems quite complicated than activity for me, please help – Chinez Jan 15 '21 at 09:58
1

You're getting a NullPointerException because findViewById(R.id.button2) returns null.

  • You need to use the fragment's view as the root. The activity.findViewById(...) call uses the activity's view as the root - it's searching activity_home.xml, which doesn't have button2. You can access the fragment's version with fragment.getView().findViewById(R.id._), BUT:
  • You need to make sure that the fragment has at finished its onCreateView() step in the life cycle. So it has to be launched and inflated. Otherwise, again, the button doesn't exist.

You can make sure your setup is called at the right time and with the view by making it a callback in the fragment life cycle.

//This class can be anywhere - it can be global, private inner, anonymous
class SetupCallback extends FragmentLifeCycleCallback {
    @Override
    void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
        ButtonView button = v.findViewById(R.id.button2);
        if(button != null) {    //This gets called for all fragments so check for null
            button.setOnClickListener(new OnClickListener {...});

        }

        //Repeat for any other elements in the view e.g.
        TextView someText = v.findViewById(R.id.someTextView);
        someText.setText(R.string.message);
    }
}

//In the activity setup - I usually put in onCreate()
SupportFragmentManager.supportFragmentManager = getSupportFragmentManager();
supportFragmentManager.registerFragmentLifecycleCallbacks(new SetupCallback());
//anonymous version:
//supportFragmentManager.registerFragmentLifecycleCallbacks(new FragmentLifecycleCallback() { /*contents of class*/ });

Alternatively you could possibly initialise the Retrofit and Weather service in the Activity, pass them in to the fragment with the constructor or a bundle, then use them to setup the onClickListener in onCreateView().

The RxJava and SharedView approaches are alternatives to having a listener stuck on all the fragment life cycle calls, vs having alternative architectures which make the fragment more reactive.

This needs the androidx.lifecycle.common dependency. If you're using gradle that would be:

dependencies {
    implementation 'androidx.lifecycle:lifecycle-common:2.3.0-rc1'
}

user3252344
  • 678
  • 6
  • 14
  • I appreciate the way you explained it. But I'm getting errors in both the fragment and activity after using the above codes. 'Cannot resolve symbol FragmentLifeCycleCallBack', Cannot resolve symbol 'ButtonView' and ''if' statement has an empty body'(In fragment). Then 'cannot resolve symbol SupportFragmentManger' and 'cannot resolve symbol registerFragmentLifecycleCallbacks' in the activity. – Chinez Jan 17 '21 at 16:20
  • And apart from just the button, I also have textviews from my fragment class which I'm calling in my activity e.g current_output.setText(response.body().getCurrent().getWeather().get(0).getDescription()); and i don't understand that //Do your setup listener here part – Chinez Jan 17 '21 at 16:39
  • And where exactly do i create the class SetupCallback extends FragmentLifeCycleCallback { from. Because I tried it in my fragment's oncreateView – Chinez Jan 17 '21 at 16:40
  • @Chinez do the edits answer those comments? – user3252344 Jan 21 '21 at 04:44
1

Create a class to get retrofit client like below

 class RetrofitClient {
    private Retrofit retrofit;
    private String BASE_URL = "";

    public ServiceAPI getRetrofitInstance() {
        if (retrofit == null) {
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
        }
        return retrofit.create(WeatherService.class);
   }

Now you can call apis inside fragment like this

WeatherService service = RetrofitClient().getRetrofitInstance()
    
    void getCurrentData() {
                  
                    Call<WeatherResponse> call = service.getCurrentWeatherData(lat, lon, AppId);
                    call.enqueue(new Callback<WeatherResponse>() {
                        @Override
                        public void onResponse(@NonNull Call<WeatherResponse> call, @NonNull Response<WeatherResponse> response) {
                            if (response.code() == 200) {
                                WeatherResponse weatherResponse = response.body();
                                assert weatherResponse != null;
    
                                assert response.body() != null;
                                time_zone.setText(response.body().getTimezone());
                                time_field.setText(response.body().getCurrent().getDt());
                                current_temp.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                                current_output.setText(response.body().getCurrent().getWeather().get(0).getDescription());
                                rise_time.setText(getString(R.string.blank, response.body().getCurrent().getSunrise() + " AM"));
                                set_time.setText(getString(R.string.blank, response.body().getCurrent().getSunset() + " PM"));
                                temp_out.setText(getString(R.string.blank, response.body().getCurrent().getTemp() + " ℃"));
                                Press_out.setText(getString(R.string.blank, response.body().getCurrent().getPressure() + " hpa"));
                                Humid_out.setText(getString(R.string.blank, response.body().getCurrent().getHumidity() + " %"));
                                Ws_out.setText(getString(R.string.blank, response.body().getCurrent().getWindSpeed() + " Km/h"));
                                Visi_out.setText(getString(R.string.blank, response.body().getCurrent().getVisibility() + " m"));
                            }
                        }
    
                        @Override
                        public void onFailure(@NonNull Call<WeatherResponse> call, @NonNull Throwable t) {
                        }
                    });
                }
            });
        }
  • Okay but please, can you rewrite this same code in Java? Var, val, and fun won't work on my code – Chinez Jan 19 '21 at 16:42
  • I'm Getting 7 errors from the fragment class - getRetrofitInstance has private access in RetrofitClient.java , Variable getCurrentData is never used, Cannot resolve symbol lat, lon, appid, and 2 errors in RetrofitClient class - cannot resolve symbol ServiceAPI and private getRetrofitInstance is never used – Chinez Jan 20 '21 at 12:05
  • I called my API inside fragment in the @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { – Chinez Jan 20 '21 at 12:06
  • lat and log are parameters of your API( Latitude and Longitude). also updated my ans for other issues. – Umair Saeed Jan 21 '21 at 12:54
0

Set the data you want to update in the bundle set fragment arguments and call the newInstance then update your views accordingly.

From Activity

   FirstFragment.newInstance("yourData","yourData");

In your Fragment

if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
End User
  • 792
  • 6
  • 14
  • I don't know how – Chinez Jan 11 '21 at 19:46
  • I have 12 TextViews and one button and there's a provision for only two data(in "yourdata", "yourdata") or how do I do it? – Chinez Jan 12 '21 at 10:16
  • send your response object which you get in your API callback as an argument in the fragment then use the data to update your view – End User Jan 12 '21 at 10:35
  • For me to get my response from the API callback, I must link the activity to the fragment which I'm trying to achieve – Chinez Jan 12 '21 at 10:45