How to Call my Fragment's TextViews and Button from my Activity? - java

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.

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.

There are many ways to achieve what you are tying to do, I will be using RxJava.
Add RxJava in your project:
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
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;
}
}
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;
}
}
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);
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();
});

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'
}

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) {
}
});
}
});
}

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);
}

Related

Problem resolving an android.content.res.Resources error

I understand that this error has been addressed severally and I've checked most of them like Android: android.content.res.Resources$NotFoundException: String resource ID #0x5, android.content.res.Resources$NotFoundException: String resource ID to see if I could find a solution to my problem but I couldn't and most of them are hard to understand. I can't tell if my code is an int/string so I don't know exactly what to correct, so I need help.
I got this error at runtime:
android.content.res.Resources$NotFoundException: String resource ID #0x601ee924
at android.content.res.Resources.getText(Resources.java:348)
at android.widget.TextView.setText(TextView.java:5848)
at com.tex.lightweatherforecast.Activity.HomeActivity$1.onResponse(HomeActivity.java:66)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$3wC8FyV4pyjrzrYL5U0mlYiviZw.run(Unknown Source:6)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
My codes:
HomeActivity.java
public class HomeActivity extends AppCompatActivity {
public static String BaseUrl = "https://api.openweathermap.org";
public static String AppId = "";
public static String lat = "9.0574";
public static String lon = "7.4898";
// User Timezone name, current time
TextView time_zone, time_field;
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.textView4);
time_field = findViewById(R.id.textView9);
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
NavController navController = Navigation.findNavController(this, R.id.fragment);
NavigationUI.setupWithNavController(bottomNavigationView, navController);
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());
constraintLayout = findViewById(R.id.layout);
constraintLayout.setBackgroundResource(R.drawable.dubai);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
// run on ui thread
runOnUiThread(() -> {
if (count < drawable.length) {
constraintLayout.setBackgroundResource(drawable[count]);
count = (count + 1) % drawable.length;
}
});
}
}, 5000, 5000);
}
}
#Override
public void onFailure(#NotNull Call<WeatherResponse> call, #NotNull Throwable t) {
}
});
}
}
FirstFragment.java
public class FirstFragment extends Fragment {
public static String BaseUrl = "https://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 current_temp, current_output, rise_time, set_time, temp_out, Press_out, Humid_out, Ws_out, Visi_out, UV_out;
// 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
View rootView = inflater.inflate(R.layout.fragment_first, container, false);
current_temp = rootView.findViewById(R.id.textView10);
current_output = rootView.findViewById(R.id.textView11);
rise_time = rootView.findViewById(R.id.textView25);
set_time = rootView.findViewById(R.id.textView26);
temp_out = rootView.findViewById(R.id.textView28);
Press_out = rootView.findViewById(R.id.textView29);
Humid_out = rootView.findViewById(R.id.textView30);
Ws_out = rootView.findViewById(R.id.textView33);
Visi_out = rootView.findViewById(R.id.textView34);
UV_out = rootView.findViewById(R.id.textView35);
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;
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) {
t.printStackTrace();
}
});
return rootView;
}
}
In my String.xml:
<string name="blank">%s ℃</string>
android.content.res.Resources$NotFoundException: String resource ID #0x601ee924
at android.content.res.Resources.getText(Resources.java:348)
at android.widget.TextView.setText(TextView.java:5848)
at com.tex.lightweatherforecast.Activity.HomeActivity$1.onResponse(HomeActivity.java:66)
As shown above, the exception is raised in HomeActivity in onResponse() method line (66) where you try to set a text into a TextView.
So, In HomeActivity you've:
time_field.setText(response.body().getCurrent().getDt());
And as per documentation, .getDt() returns an integer, so you can't set it directly to TextView unless you convert it to a String.
To solve this, replace that line of code with one of:
// 1st
time_field.setText(String.valueOf(response.body().getCurrent().getDt()));
// 2nd
time_field.setText("" + response.body().getCurrent().getDt());
You need to cast value of position to String. Concatenating with another String is one of the ways to do it
setText("" + position)

adapter.notifyDataSetChanged() not updating UI across classes

I have an app that utilizes a TSL 1128 reader to read RFID tags. It uses the IASCIICommandResponder Library to communicate with the reader.
I have one Class called orderFullfill.java that is responsible for the Listview and updating the UI for this class. Th
The Reader functionality is set up in another class (orderResponder.java) that implements this IASCIICommandResponder, so that it can run in the background whilst orderFullfill shows the changes made to the ArrayList.
I have tried passing the Arrayadapter from orderFullfill.java to orderResponder to call notifyDataSetChanged(); but that has no effect. I have to call addPigNumber() method on a button click to update my listview.
Ideally I need the listview to update when a new tag is added to the list. Please can someone help me apply notifyDataSetChanged() in the right place so that when I can a tag it will add to the list automatically. I am very grateful for any help that is received.
public class orderFullfill extends AppCompatActivity implements PopupMenu.OnMenuItemClickListener {int where; public static ArrayList scannedPigs = new ArrayList<String>();
// The Reader currently in use
private Reader mReader = null;
private boolean mIsSelectingReader = false;
// The model that performs actions with the reader
private TriggerModel mModel;
public static String dispatchweek;
public static String customer;
public static String accountnumber;
public static String supplyfarm;
public static String breed;
public static int numberofpigs;
public static int pigNum;
public static ArrayAdapter<String> adapter;
public static String weekNow;
public static Context mContext;
Switch trick; TextView nameholder;
/**
* #return the current AsciiCommander
*/
protected AsciiCommander getCommander()
{
return AsciiCommander.sharedInstance();
}
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.orderfullfill);
mContext = orderFullfill.this;
addPigNumber();
InventoryCommand iCommand = InventoryCommand.synchronousCommand();
iCommand.setFilterStrongest(TriState.YES);//high power reading
trick = (Switch) findViewById(R.id.scanM2);
trick.setVisibility(View.INVISIBLE);
trick.setChecked(true);
trick.setText(getResources().getString(R.string.lowPowerScan));
trick.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
InventoryCommand iCommand = new InventoryCommand();
//InventoryCommand iCommand = InventoryCommand.synchronousCommand();
if(isChecked)
{
iCommand.setTakeNoAction(TriState.YES);
iCommand.setFilterStrongest(TriState.YES);// low power reading
getCommander().executeCommand(iCommand);
trick.setText(getResources().getString(R.string.lowPowerScan));
}
if(!isChecked)
{
trick.setText(getResources().getString(R.string.highPowerScan));
iCommand.setFilterStrongest(TriState.NO);//high power reading
iCommand.setTakeNoAction(TriState.NO);
getCommander().executeCommand(iCommand);
}
}
});
nameholder = (TextView)findViewById(R.id.nameView);
nameholder.setText(customer);
AsciiCommander.createSharedInstance(getApplicationContext());
final AsciiCommander commander = getCommander();
// Ensure that all existing responders are removed
commander.clearResponders();
// Add the LoggerResponder - this simply echoes all lines received from the reader to the log
// and passes the line onto the next responder
// This is ADDED FIRST so that no other responder can consume received lines before they are logged.
// commander.addResponder(new LoggerResponder());// logcat input
// Add responder to enable the synchronous commands
// commander.addSynchronousResponder();
commander.addResponder(new orderResponder());
// Configure the ReaderManager when necessary
ReaderManager.create(getApplicationContext());
// Add observers for changes
ReaderManager.sharedInstance().getReaderList().readerAddedEvent().addObserver(mAddedObserver);
ReaderManager.sharedInstance().getReaderList().readerUpdatedEvent().addObserver(mUpdatedObserver);
ReaderManager.sharedInstance().getReaderList().readerRemovedEvent().addObserver(mRemovedObserver);
// Create a (custom) model and configure its commander and handler
mModel = new TriggerModel();
mModel.setCommander(getCommander());
mModel.initialise();
ListView scroller = (ListView)findViewById(R.id.listviewD);
scroller.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
PopupMenu popup = new PopupMenu(orderFullfill.this, view);
popup.setOnMenuItemClickListener(orderFullfill.this);
popup.inflate(R.menu.edit_menu);
where = position;
popup.show();
}
});
weekNow = orderResponder.getWeeknow();
}
public ArrayAdapter getAdapter()
{
adapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, scannedPigs);
return adapter;
}
public void addPigNumber()
{
adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_spinner_item, scannedPigs);
TextView counter = findViewById(R.id.editTextNumber);
if(numberofpigs >= 0 )
{
counter.setText("Pigs Left: " +numberofpigs);
if(numberofpigs == 0)
{
counter.setBackgroundColor(Color.parseColor("#BCBDF3E8"));
}
}
ListView scroller = findViewById(R.id.listviewD);
try {
adapter.setDropDownViewResource(R.layout.support_simple_spinner_dropdown_item);
scroller.setAdapter(adapter);
}catch (Exception e)
{
String result ="";
result.equals(e.toString());
}
}
public void orderdetailsOnclick(View view) {
addPigNumber();
AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("Customer Order: " + customer);
alert.setMessage("Account Number: " + accountnumber + "\r\n" +
"Dispatch Week: " + dispatchweek + "\r\n" +
"Supply Farm: " + supplyfarm + "\r\n" +
"Breed: "+ breed + "\r\n" + "Number of Pigs: " + pigNum);
alert.setCancelable(true);
alert.show();
}
#Override
public synchronized void onResume()
{
super.onResume();
addPigNumber();
// Register to receive notifications from the AsciiCommander
LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, new IntentFilter(AsciiCommander.STATE_CHANGED_NOTIFICATION));
// Remember if the pause/resume was caused by ReaderManager - this will be cleared when ReaderManager.onResume() is called
boolean readerManagerDidCauseOnPause = ReaderManager.sharedInstance().didCauseOnPause();
// The ReaderManager needs to know about Activity lifecycle changes
ReaderManager.sharedInstance().onResume();
// The Activity may start with a reader already connected (perhaps by another App)
// Update the ReaderList which will add any unknown reader, firing events appropriately
ReaderManager.sharedInstance().updateList();
// Locate a Reader to use when necessary
AutoSelectReader(!readerManagerDidCauseOnPause);
mIsSelectingReader = false;
displayReaderState();
}
#Override
public synchronized void onPause() {
super.onPause();
// Register to receive notifications from the AsciiCommander
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
addPigNumber();
ReaderManager.sharedInstance().onPause();
}
#Override
protected void onDestroy()
{
super.onDestroy();
// Remove observers for changes
ReaderManager.sharedInstance().getReaderList().readerAddedEvent().removeObserver(mAddedObserver);
ReaderManager.sharedInstance().getReaderList().readerUpdatedEvent().removeObserver(mUpdatedObserver);
ReaderManager.sharedInstance().getReaderList().readerRemovedEvent().removeObserver(mRemovedObserver);
// readResponder.tempList = false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.reader_menu, menu);
// Reset, connect, disconnect dropdown menu
mResetMenuItem = menu.findItem(R.id.reset_reader_menu_item);
mConnectMenuItem = menu.findItem(R.id.connect_reader_menu_item);
mDisconnectMenuItem= menu.findItem(R.id.disconnect_reader_menu_item);
return true;
}
//----------------------------------------------------------------------------------------------
// ReaderList Observers
//----------------------------------------------------------------------------------------------
Observable.Observer<Reader> mAddedObserver = new Observable.Observer<Reader>()
{
#Override
public void update(Observable<? extends Reader> observable, Reader reader)
{
// See if this newly added Reader should be used
AutoSelectReader(true);
}
};
Observable.Observer<Reader> mUpdatedObserver = new Observable.Observer<Reader>()
{
#Override
public void update(Observable<? extends Reader> observable, Reader reader)
{
}
};
Observable.Observer<Reader> mRemovedObserver = new Observable.Observer<Reader>()
{
#Override
public void update(Observable<? extends Reader> observable, Reader reader)
{
// Was the current Reader removed
if( reader == mReader)
{
mReader = null;
// Stop using the old Reader
getCommander().setReader(mReader);
}
}
};
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId())
{
case R.id.delete_menu:
boolean complete = false;
scannedPigs.remove(where);
numberofpigs = numberofpigs + 1;
//myDB.deleteEntry(scannedItems); -> IF YOU ADD IT TO THE DB REMOVE IT
//select items from the list
addPigNumber();
return true;
case R.id.edit_menu_:
return true;
}
return super.onOptionsItemSelected(item);
}}
orderfullfill.xml
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.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"
android:orientation="vertical">
<TextView
android:id="#+id/editTextNumber"
android:layout_width="177dp"
android:layout_height="56dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="80dp"
android:textSize="30sp"
app:layout_constraintBottom_toTopOf="#+id/listviewD"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
<ListView
android:id="#+id/listviewD"
android:layout_width="354dp"
android:layout_height="221dp"
android:layout_marginBottom="12dp"
app:layout_constraintBottom_toTopOf="#+id/scanM2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.421"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="#+id/invoiceMaker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="#string/makeInvoice"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.75"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/scanM2" />
<TextView
android:id="#+id/nameView"
android:layout_width="333dp"
android:layout_height="52dp"
android:layout_marginLeft="25dp"
android:layout_marginTop="16dp"
android:layout_marginRight="25dp"
android:layout_marginBottom="303dp"
android:textSize="20dp"
app:layout_constraintBottom_toTopOf="#+id/scanM2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="#+id/orderdetailsBtn"
android:layout_width="119dp"
android:layout_height="54dp"
android:layout_marginTop="68dp"
android:layout_marginEnd="20dp"
android:layout_marginRight="20dp"
android:onClick="orderdetailsOnclick"
android:text="#string/showOrder"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.887"
app:layout_constraintStart_toEndOf="#+id/editTextNumber"
app:layout_constraintTop_toTopOf="parent" />
<Switch
android:id="#+id/scanM2"
android:layout_width="359dp"
android:layout_height="39dp"
android:layout_below="#id/listviewD"
android:layout_marginTop="232dp"
android:text="#string/highPowerScan"
android:textOff="No"
android:textOn="Yes"
android:textSize="27dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.461"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/orderdetailsBtn" />/android.support.constraint.ConstraintLayout>
orderResponder.java -> this is the class that the TSL reader communicates with via ASCII when reading RFID tags. The method Splicer adds the RFID values to the ArrayAdapter then notifyDataSetChanged(); is called. However nothing happens when this method is called from outside orderFullfill.class.
public class orderResponder extends Application implements IAsciiCommandResponder {
public static boolean tempList;
NoteHelper myDB;
public List<String> getReadInput() {
return readInput;
}
public void setReadInput(List<String> readInput) {
this.readInput = readInput;
}
public static List<String> readInput = new ArrayList<>();
#Override
public boolean isResponseFinished() {
return false;
}
#Override
public void clearLastResponse() {
}
#Override
public boolean processReceivedLine(String s, boolean b) throws Exception {
isitMe(s);
return false;
}
public List<String> getList()
{
return readInput;
}
public boolean isitMe (String input)
{
String firstFourChars = "";
//get first 4 chars to see if it contains "EP: "
if(input.length()>4)
{
firstFourChars = input.substring(0,4);
}
else
{
firstFourChars = input;
}
if(firstFourChars.equals("EP: "))// this is the inital identifier for the RFID tags
{
splicer(input);
return true;
}
else
{
return false;
}
}
//takes the last 24 characters removing the 'EP: '
public void splicer (String input)
{ // ArrayAdapter magic = orderFullfill.getAdapter(); THIS Didnt work
orderFullfill.adapter = new ArrayAdapter<String>(orderFullfill.mContext, android.R.layout.simple_spinner_item, orderFullfill.scannedPigs);
String output ="";
output = input.substring(input.length() -24);//maybe take 24 chars
if (orderFullfill.scannedPigs.size() == 0) {
// orderFullfill.scannedPigs.add(output);
orderFullfill.adapter.add(output);
orderFullfill.adapter.notifyDataSetChanged();
orderFullfill.numberofpigs = orderFullfill.numberofpigs - 1;
} else//if the list has values check you are not duplicating the values
{
if (orderFullfill.scannedPigs.contains(output)) {
return;//you are already in the list
} else//you are unique you can join the list
{
// orderFullfill.scannedPigs.add(output);
orderFullfill.adapter.add(output);
orderFullfill.adapter.notifyDataSetChanged();
orderFullfill.numberofpigs = orderFullfill.numberofpigs - 1;
}
}
}
public static String getWeeknow()
{
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
String dateH = formatter.format(date);
//String dateH = date.toString();
String[] array = dateH.split("\\/");
String output ="";
int month = Integer.parseInt(array[1]);
month = month -1;
Calendar calendar = Calendar.getInstance();
calendar.set(Integer.parseInt(array[2]),month,Integer.parseInt(array[0]));
int weekOfyear = calendar.get(Calendar.WEEK_OF_YEAR);
output = String.valueOf(weekOfyear);
return output;
}}
create orderResponder constructor method. and send your activity(orderFullfill.this) and context to orderResponder as parameter. call like this;
((orderFullfill)activity).adapter = new ArrayAdapter<String>(context, android.R.layout.simple_spinner_item, ((orderFullfill)activity).scannedPigs);
((orderFullfill)activity).adapter.notifyDataSetChanged();
i hope it works.

How to make my Fragment make use of my Activity Data?

I have an Activity hosting 3 Fragments, my activity contains some data that I want my first fragment to use.
I tried invoking the following method so that the activity can communicate with the fragment:
FirstFragment fragmentFirst = (FirstFragment)
getSupportFragmentManager().findFragmentById(R.id.firstFragment);
assert fragmentFirst != null;
fragmentFirst.doSomething("some param");
For the activity class and:
public void doSomething(String param) {
// do something in fragment
}
For the fragment class, but it brought out an: Attempt to invoke virtual method 'void com.tex.lightweatherforecast.FirstFragment.doSomething(java.lang.String)' on a null object reference
error at runtime.
My Activity code is:
public class HomeActivity extends AppCompatActivity {
public static String BaseUrl = "http://api.openweathermap.org/";
public static String AppId = "9c547bfc852923c3b30d0d62a5ae35e8";
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);
FirstFragment fragmentFirst = (FirstFragment)
getSupportFragmentManager().findFragmentById(R.id.firstFragment);
assert fragmentFirst != null;
fragmentFirst.doSomething("some param");
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(response.body().getCurrent().getTemp() + " ℃");
current_output.setText(response.body().getCurrent().getWeather().get(0).getDescription());
rise_time.setText(response.body().getCurrent().getSunrise() + " AM");
set_time.setText(response.body().getCurrent().getSunset() + " PM");
temp_out.setText(response.body().getCurrent().getTemp() + " ℃");
Press_out.setText(response.body().getCurrent().getPressure() + " hpa");
Humid_out.setText(response.body().getCurrent().getHumidity() + " %");
Ws_out.setText(response.body().getCurrent().getWindSpeed() + " Km/h");
Visi_out.setText(response.body().getCurrent().getVisibility() + " m");
}
}
#Override
public void onFailure(#NonNull Call<WeatherResponse> call, #NonNull Throwable t) {
}
});
}
});
}
}
Any help will be Appreciated
I think you are getting this error because the fragment is not active. and if it's active and this approach worked, it's pretty bad approach, there are other ways in when we use the new LiveData and ViewModel arch style.
If you think that DataSource(LiveData usually) will be needed by children(Fragments) make this DataSource owned by the Parent (activity) and keep watching that DataSource inside the fragment(i.e. make observers of this LiveData inside different fragments)
If you need to make a callback from the Fragment to the activity use Contracts(Interfaces) and implement that contract inside the activity(this contract might contain functions like doSomething()) and call that from inside the fragment like this:
(((ContractName)activity).doSomething(passData))
If you want to pass activity data in your first destination fragment, avoid setting up graph in activity layout file.
Remove graph implementation from activity layout. And implement it as below in activity's onCreate method.
NavController navController = Navigation.findNavController(this, R.id.nav_controller);
Bundle bundle = new Bundle();
bundle.putString("key", "value");
navController.setGraph(navController.getGraph(), bundle);
Update your graph file by referring below code.
<navigation 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:id="#+id/navigation_graph"
app:startDestination="#id/homeFragment">
<fragment android:id="#+id/homeFragment"
android:name="com.java.HomeFragment"
android:label="home_fragment"
tools:layout="#layout/fragment_home">
<argument
android:name="key"
app:argType="string"/>
</fragment>
...
...
</navigation>
In your home fragment, get arguments value.
String data = getArguments().getString("key");

Android Data binding issue Binding adapter call twice

I have simple imageview in my layout and I have a api which gives me a image url. I integrate Data binding in my layout. Now after parsing the api I'm setting the model through this line binding.setUserinfo(memberObj.getMemberdata());
Now I have also a binding adapter where imgurl code is written. Now the custom binding adapter calls twice when activity start and after parsing the api.
Now i want to notify the UI after api has been successfully parsed.
Here is my code of xml activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data class="MainBinding">
<variable
name="userinfo"
type="com.myapplication.retrofit.pojo.ImgTest"/>
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.myapplication.retrofit.MainActivity">
<ImageView
android:layout_width="250dp"
android:layout_height="250dp"
android:id="#+id/imageView"
app:image_url="#{userinfo.imgUrl}"
/>
</RelativeLayout>
</layout>
Here is my Pojo: ImgTest.java
public class ImgTest extends BaseObservable {
String imgUrl;
#Bindable
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
notifyPropertyChanged(BR.imgUrl);
}
}
Here is my CustomBinder.java
public class CustomBinders {
private static final String TAG = "CustomBinders";
#BindingAdapter({"image_url"})
public static void loadImageWithOUtProgressBar(ImageView view, String imageUrl){
Log.d(TAG, "before loadImageWithOUtProgressBar: "+imageUrl);
Log.d(TAG, "after loadImageWithOUtProgressBar: "+imageUrl);
Picasso.with(view.getContext())
.load(imageUrl)
.into(view);
}
}
Here is MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
RestManager mManager;
MainBinding binding;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this,R.layout.activity_main);
mManager = new RestManager();
Call<ResponseBody> getUserInfo = mManager.getService().getUserInfo("25","sell");
getUserInfo.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
int sc = response.code();
Log.d(TAG, "onResponse: "+sc);
if(response.isSuccessful())
{
ImgTest img = new ImgTest();
try {
String res = response.body().string();
JSONObject jobj = new JSONObject(res);
JSONObject obj = jobj.getJSONObject("memberdata");
String imgUrl = "";
imgUrl = obj.getString("prifile_picture");
img.setImgUrl(imgUrl);
binding.setUserinfo(img);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
}
Please let know how to solve this issue. Thanks in advance.
As Ravi says in the comments, it is working as intended. After you create the initial binding, the values should be set to the values as they are. If you haven't set anything then they will be set to null.
You can change the behavior by explicitly telling the binding to not bind. Add an OnRebindCallback to the binding:
private OnRebindCallback<ActivityMainBinding> delayRebindCallback =
new OnRebindCallback<ActivityMainBinding>() {
#Override
public boolean onPreBind(ActivityMainBinding binding) {
return false;
}
};
// ... and then after creating the binding ...
binding.addOnRebindCallback(delayRebindCallback);
In your onResponse (assuming it is on the UI thread):
binding.removeOnRebindCallback(delayRebindCallback);
binding.setUserinfo(img);
binding.executePendingBindings();
If it isn't on the UI thread, you will have to post an executable to run the binding.executePendingBindings() on the UI thread.

Not hide layout when load data in RecyclerView on Android

I want develop application for one website and i want load site posts into RecyclerView. I want show load layout for first entry in application and when load posts data into RecyclerView, hide this layout and show RecyclerView!
I write this codes, but it's not work me and always show emptyLayout.
Main Activity 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:id="#+id/main_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/appBackground"
tools:context=".Activities.Main_page">
<include
android:id="#+id/main_toolbar"
layout="#layout/toolbar" />
<android.support.v7.widget.RecyclerView
android:id="#+id/main_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/main_toolbar" />
<RelativeLayout
android:id="#+id/main_empty_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<include layout="#layout/empty_page_layout" />
</RelativeLayout>
</RelativeLayout>
MainActivity java :
public class Main_page extends AppCompatActivity {
private static final long RIPPLE_DURATION = 250;
private Toolbar toolbar;
private RelativeLayout root;
private ImageView menu_image;
private RecyclerView main_recyclerView;
private MainAdapter mAdaper;
private List<MainDataModel> dataModels = new ArrayList<MainDataModel>();
private List<MainDataModel> dataModelsArray;
private Context context;
protected Handler handler;
private RelativeLayout loadLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_page);
if (!EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().register(this);
}
handler = new Handler();
context = getApplicationContext();
loadLayout = (RelativeLayout) findViewById(R.id.main_empty_layout);
toolbar = (Toolbar) findViewById(R.id.main_toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
getSupportActionBar().setTitle(null);
}
LoadData();
// Menu
root = (RelativeLayout) findViewById(R.id.main_root);
View guillotineMenu = LayoutInflater.from(this).inflate(R.layout.menu_layout, null);
root.addView(guillotineMenu);
menu_image = (ImageView) toolbar.findViewById(R.id.toolbar_logo);
new GuillotineAnimation.GuillotineBuilder(guillotineMenu, guillotineMenu.findViewById(R.id.menu_layout_image), menu_image)
.setStartDelay(RIPPLE_DURATION)
.setActionBarViewForAnimation(toolbar)
.setClosedOnStart(true)
.build();
// RecyclerView and setData
main_recyclerView = (RecyclerView) findViewById(R.id.main_recycler);
main_recyclerView.setHasFixedSize(true);
main_recyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdaper = new MainAdapter(this, dataModels);
main_recyclerView.setAdapter(mAdaper);
if (dataModels.isEmpty()) {
main_recyclerView.setVisibility(View.GONE);
loadLayout.setVisibility(View.VISIBLE);
} else {
main_recyclerView.setVisibility(View.VISIBLE);
loadLayout.setVisibility(View.GONE);
}
}
#Subscribe
public void onEvent(List<MainDataModel> mainInfoModels) {
mAdaper.add(mainInfoModels);
}
private void LoadData() {
final MainDataInfo dataInfo = new MainDataInfo();
dataInfo.getMainDataInfo(this);
}
}
AsyncTask code:
public class MainDataInfo {
private Context mContext;
public void getMainDataInfo(Context context) {
mContext = context;
new getInfo().execute(ServerIP.getIP());
}
private class getInfo extends AsyncTask<String, Void, String> {
EventBus bus = EventBus.getDefault();
private String ou_response;
private List<MainDataModel> infoModels;
#Override
protected void onPreExecute() {
CustomProcessDialog.createAndShow(mContext);
infoModels = new ArrayList<>();
}
#Override
protected String doInBackground(String... params) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(ServerIP.getIP())
.build();
Response response;
try {
response = client.newCall(request).execute();
ou_response = response.body().string();
response.body().close();
if (ou_response != null) {
try {
JSONObject postObj = new JSONObject(ou_response);
JSONArray postsArray = postObj.getJSONArray("posts");
infoModels = new ArrayList<>();
for (int i = 0; i <= infoModels.size(); i++) {
JSONObject postObject = (JSONObject) postsArray.get(i);
int id = postObject.getInt("id");
String title = postObject.getString("title");
Log.d("Data", "Post id: " + id);
Log.d("Data", "Post title: " + title);
//Use the title and id as per your requirement
infoModels.add(new MainDataModel(
postObject.getInt("id"),
postObject.getString("title"),
postObject.getString("content"),
postObject.getString("thumbnail")));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return ou_response;
}
#Override
protected void onPostExecute(String result) {
CustomProcessDialog.dissmis();
if (result != null) {
bus.post(infoModels);
}
}
}
}
when delete emptyLayout from mainActivity, RecyclerView show all posts. when insert this layout (emptyLayout) recyclerView is not VISIBLE and EmptyLayout is not GONE!
How can i fit this problem? tnx all <3
I presume that you don't make your call at the good place because dataModels is always empty.
Indeed, you have to do your call only after the onPostExecute() method on your AsyncTask which loads your data.
You can use an interface (AsyncResponse in example below) to catch the end of AyncTask process.
Here AynscResponse :
public interface AsyncResponse {
void endTask(List<MainDataModel> dataModels);
}
In your AsyncTask :
private AsyncResponse listener;
#Override
protected void onPostExecute(List<MainDataModel> dataModels) {
listener.processFinish(dataModels);
}
Finally in your activity :
// Set by default the visibility
main_recyclerView.setVisibility(View.GONE);
loadLayout.setVisibility(View.VISIBLE);
public void processFinish(List<MainDataModel> dataModels) {
if (dataModels.isEmpty()) {
// Handle error with an empty list
} else {
main_recyclerView.setVisibility(View.VISIBLE);
loadLayout.setVisibility(View.GONE);
}
}

Categories

Resources