Not hide layout when load data in RecyclerView on Android - java

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

Related

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

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

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.

ListView onScroll add more items

private class getArticles extends AsyncTask<Void, Void, Void> {
String url;
getArticles(String paramUrl) {
this.url = paramUrl;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog = new ProgressDialog(App.this);
mProgressDialog.setMessage("Učitavanje artikala...");
mProgressDialog.setIndeterminate(false);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
arraylist = new ArrayList<>();
try {
Document document = Jsoup.connect(url).get();
Elements els = document.select("ul.category3 > li");
for (Element el : els) {
HashMap<String, String> map = new HashMap<>();
Elements slika = el.select("div.category3-image > a > img");
Elements naslov = el.select("div.category3-text > a.main-headline");
Element datum_noformat = el.select("div.category3-text > div.headlines-info > ul.headlines-info > li").first();
Element datum = datum_noformat.html(datum_noformat.html().replaceAll("Posted ", ""));
Elements desc = el.select("div.category3-text > p");
Elements link = el.select("div.category3-text > a.main-headline");
Element br_kom = el.select("div.category3-text > div.headlines-info > ul.headlines-info > li.comments-icon").first();
map.put("naslov", naslov.text());
map.put("datum", datum.text());
map.put("desc", desc.text());
map.put("ikona", slika.attr("src"));
map.put("link", link.attr("abs:href"));
map.put("brkom", br_kom.text());
arraylist.add(map);
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
listview = (ListView) findViewById(R.id.listview);
adapter = new ArtikliAdapter(App.this, arraylist);
listview.setAdapter(adapter);
mProgressDialog.dismiss();
}
I searched for a lot of codes for onlistview scrolling, but didn't know how to implement it. The problem is, when I call my asynctask, I have an url param,
like new getArticles("http://example.com").execute();
I want to implement an onscrolllistener, but it goes like this, my param is usually set to: http://www.example.com/category/categoryname/, so the second page goes like http://www.example.com/category/categoryname/page/2/, the third one goes http://www.example.com/category/categoryname/page/3/ and so on. Each page has got 7 items that need to be parsed.
How could I implement onscrolllistener, because of the url param?
Thanks in advance.
Base on this link, I have written following solution to add elements ( 30 elements at a time, i.e page size = 30) to listview asynchronously.
Create a class named EndlessListView as follows:
public class EndlessListView extends ListView implements OnScrollListener {
private View footer;
private boolean isLoading;
private EndlessListener listener;// listner
private EndlessAdapter endlessAdapter;// adapter.
private int maxNoOfElement;
public EndlessListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnScrollListener(this);
}
public EndlessListView(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnScrollListener(this);
}
public EndlessListView(Context context) {
super(context);
this.setOnScrollListener(this);
}
public void setListener(EndlessListener listener) {
this.listener = listener;
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() == null)
return;
if (getAdapter().getCount() == 0 || getAdapter().getCount() <= 5)
return;
int l = visibleItemCount + firstVisibleItem;
if (l >= totalItemCount && !isLoading) {
// It is time to add new data. We call the listener
Log.e("LOAD", "DATA");
isLoading = true;
listener.loadData();
}
}
public void setMaxElemnt(int maxNoOfElement) {
this.maxNoOfElement = maxNoOfElement;
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
public void setLoadingView(int resId) {
LayoutInflater inflater = (LayoutInflater) super.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
footer = (View) inflater.inflate(resId, null);
this.addFooterView(footer);
}
public void setAdapter(EndlessAdapter adapter) {
super.setAdapter(adapter);
this.endlessAdapter = adapter;
}
public void addNewData(List<Integer> data) {
endlessAdapter.setData(data);
endlessAdapter.notifyDataSetChanged();
isLoading = false;
}
public static interface EndlessListener {
public void loadData();
}
}
After this we have to create the adapter for it,called
EndlessAdapter
public class EndlessAdapter extends BaseAdapter {
private List<Integer> mIntegers;
private Context context;
public EndlessAdapter(Context context) {
this.context = context;
}
public void setData(List<Integer> mIntegers) {
this.mIntegers = mIntegers;
}
#Override
public int getCount() {
if (mIntegers == null)
return 0;
return mIntegers.size();
}
#Override
public Integer getItem(int index) {
if (mIntegers == null) {
return null;
} else {
return mIntegers.get(index);
}
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
class ViewHolder {
TextView textView;
}
#Override
public View getView(int index, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = ((LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.rows, viewGroup, false);
holder.textView = (TextView) view.findViewById(R.id.mtext);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.textView.setText(getItem(index) + "");
return view;
}
}
Now in xml of the activity we could use EndlessListView(in com.example.stackoverflow package) as follows :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.stackoverflow.EndlessListView
android:id="#+id/endlessListView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
After this step we need to make following change in the MainActivity
public class MainActivity extends Activity implements EndlessListener {
private EndlessAdapter adapter;
private EndlessListView endlessListView;
private List<Integer> data;
private int gStartIndex = 30;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
endlessListView = (EndlessListView) findViewById(R.id.endlessListView);
adapter = new EndlessAdapter(this);
data = new ArrayList<Integer>();
endlessListView.setLoadingView(R.layout.footer);
// endlessListView.showFooter();
endlessListView.setListener(this);
endlessListView.setAdapter(adapter);
gStartIndex = 0;
fillData(gStartIndex);
}
private void fillData(int startIndex) {
new AsyncLoadData().execute(startIndex);
}
#Override
public void loadData() {
fillData(gStartIndex);
}
private class AsyncLoadData extends AsyncTask<Integer, Integer, Void> {
#Override
protected Void doInBackground(Integer... params) {
int gendIndex = params[0] + 30;
gStartIndex = gendIndex;
/***
* Here you could add your n/w code. To simulate the n/w comm. i am
* adding elements to list and making it sleep for few sec.
* */
for (int i = params[0]; i < gendIndex; i++) {
publishProgress(i);
}
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
data.add(values[0]);
}
#Override
protected void onPostExecute(Void result) {
endlessListView.addNewData(data);
}
}
}
This custom ScrollListView that I just found has OnBottomReachedListener which you can implement from your Activity or Fragment and receive events when user hits the bottom of the page. You would also need to track the current page and when bottom is hit to download the next page. The latest data should be added to your existing ArrayList and you should call notifyDataSetChanged() on your adapter so ListView can render the new data. You don't have to create new adapter, you just need to update the data source which is your ArrayList.
If you support orientation change you would must to save in onSaveInstanceState() your current page number so when Activity or Fragment is recreated it can continue from correct page. And you would have to keep the ArrayList data source safe of configuration changes because you don't want to downloaded it again. I would suggest using the Fragment with setRetainInstance() set to true to persist ArrayList.
Here is my custom code for keeping data around using RetainFragment:
/**
* A simple non-UI Fragment that stores a single Object
* and is retained over configuration changes.
*/
public class RetainFragment<E extends Object> extends Fragment {
/** Object for retaining. */
private E mObject;
/**
* Empty constructor as per the Fragment documentation
*/
public RetainFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Make sure this Fragment is retained over a configuration change
setRetainInstance(true);
}
/**
* Store a single object in this Fragment.
*
* #param object The object to store
*/
public void setObject(E object) {
mObject = object;
}
/**
* Get the stored object.
*
* #return The stored object
*/
public E getObject() {
return mObject;
}
}
Example of RetainFragment usage in your Activity:
FragmentManager fm = getFragmentManager();
mRetainFragment = (RetainFragment<ArrayList>) fm.findFragmentByTag(RETAIN_FRAG);
if (mRetainFragment == null) {
mRetainFragment = new RetainFragment<>();
mRetainFragment.setObject(new ArrayList());
fm.beginTransaction().add(mRetainFragment, RETAIN_FRAG).commit();
}
ArrayList yourArrayList = mRetainFragment.getObject();
// Now your ArrayList is saved accrossed configuration changes
here what you want fist add onscrolllistner to listview
boolean loading_flage = false;
yourlistview.setOnScrollListener(new OnScrollListener() {
#Override
public void onScrollStateChanged(
AbsListView view,
int scrollState) {
// TODO Auto-generated method stub
}
#Override
public void onScroll(AbsListView view,
int firstVisibleItem,
int visibleItemCount,
int totalItemCount) {
final int lastItem = firstVisibleItem
+ visibleItemCount;
if ((lastItem == totalItemCount)
& loading_flage == false) {
//this to prevent the list to make more than one request in time
loading_flage = true;
//you can put the index for your next page here
loadMore(int page);
}
}
});
and then in loading more after loading the page set the loading with false and parse the data add it to the data that you aleardy have
//notify the adapter
adapter.notifyDataSetChanged();
loading_flage = false;
You can achieve by adding the scrolllistener on listview and check condition if list last visible item is last in ArrayList then call the asynctask with incremented page number and update the listview,mean while add the view on listview and after getting the result from server remove the loading more view from the listview like this -
AndroidListViewLoadMoreActivity.java
public class AndroidListViewLoadMoreActivity extends Activity {
ArrayList<Country> countryList;
MyCustomAdapter dataAdapter = null;
int page = 0;
boolean loadingMore = false;
View loadMoreView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ListView listView = (ListView) findViewById(R.id.listView1);
loadMoreView = ((LayoutInflater)this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.loadmore, null, false);
listView.addFooterView(loadMoreView);
//create an ArrayAdaptar from the String Array
countryList = new ArrayList<Country>();
dataAdapter = new MyCustomAdapter(this,
R.layout.country_info, countryList);
listView.setAdapter(dataAdapter);
//enables filtering for the contents of the given ListView
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Country country = (Country) parent.getItemAtPosition(position);
Toast.makeText(getApplicationContext(),
country.getCode(), Toast.LENGTH_SHORT).show();
}
});
listView.setOnScrollListener(new OnScrollListener(){
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
int lastInScreen = firstVisibleItem + visibleItemCount;
if((lastInScreen == totalItemCount) && !(loadingMore)){
String url = "http://10.0.2.2:8080/CountryWebService" +
"/CountryServlet";
grabURL(url);
}
}
});
String url = "http://example.com";
grabURL(url);
}
public void grabURL(String url) {
Log.v("Android Spinner JSON Data Activity", url);
new GrabURL().execute(url);
}
private class GrabURL extends AsyncTask<String, Void, String> {
private static final int REGISTRATION_TIMEOUT = 3 * 1000;
private static final int WAIT_TIMEOUT = 30 * 1000;
private final HttpClient httpclient = new DefaultHttpClient();
final HttpParams params = httpclient.getParams();
HttpResponse response;
private String content = null;
private boolean error = false;
private ProgressDialog dialog =
new ProgressDialog(AndroidListViewLoadMoreActivity.this);
protected void onPreExecute() {
dialog.setMessage("Getting your data... Please wait...");
dialog.show();
}
protected String doInBackground(String... urls) {
String URL = null;
loadingMore = true;
try {
URL = urls[0];
HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT);
HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT);
ConnManagerParams.setTimeout(params, WAIT_TIMEOUT);
HttpPost httpPost = new HttpPost(URL);
//add name value pair for the country code
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("page",String.valueOf(page)));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
response = httpclient.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
content = out.toString();
} else{
//Closes the connection.
Log.w("HTTP1:",statusLine.getReasonPhrase());
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e) {
Log.w("HTTP2:",e );
content = e.getMessage();
error = true;
cancel(true);
} catch (IOException e) {
Log.w("HTTP3:",e );
content = e.getMessage();
error = true;
cancel(true);
}catch (Exception e) {
Log.w("HTTP4:",e );
content = e.getMessage();
error = true;
cancel(true);
}
return content;
}
protected void onCancelled() {
dialog.dismiss();
Toast toast = Toast.makeText(AndroidListViewLoadMoreActivity.this,
"Error connecting to Server", Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP, 25, 400);
toast.show();
}
protected void onPostExecute(String content) {
dialog.dismiss();
Toast toast;
if (error) {
toast = Toast.makeText(AndroidListViewLoadMoreActivity.this,
content, Toast.LENGTH_LONG);
toast.setGravity(Gravity.TOP, 25, 400);
toast.show();
} else {
displayCountryList(content);
}
}
}
private void displayCountryList(String response){
JSONObject responseObj = null;
try {
Gson gson = new Gson();
responseObj = new JSONObject(response);
JSONArray countryListObj = responseObj.getJSONArray("countryList");
//countryList = new ArrayList<Country>();
if(countryListObj.length() == 0){
ListView listView = (ListView) findViewById(R.id.listView1);
listView.removeFooterView(loadMoreView);
}
else {
for (int i=0; i<countryListObj.length(); i++){
//get the country information JSON object
String countryInfo = countryListObj.getJSONObject(i).toString();
//create java object from the JSON object
Country country = gson.fromJson(countryInfo, Country.class);
//add to country array list
countryList.add(country);
dataAdapter.add(country);
}
page++;
dataAdapter.notifyDataSetChanged();
loadingMore = false;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Make MyCustomAdapter.java as adapter
private class MyCustomAdapter extends ArrayAdapter<Country> {
private ArrayList<Country> countryList;
public MyCustomAdapter(Context context, int textViewResourceId,
ArrayList<Country> countryList) {
super(context, textViewResourceId, countryList);
this.countryList = new ArrayList<Country>();
this.countryList.addAll(countryList);
}
private class ViewHolder {
TextView code;
TextView name;
TextView continent;
TextView region;
}
public void add(Country country){
Log.v("AddView", country.getCode());
this.countryList.add(country);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
Log.v("ConvertView", String.valueOf(position));
if (convertView == null) {
LayoutInflater vi = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.country_info, null);
holder = new ViewHolder();
holder.code = (TextView) convertView.findViewById(R.id.code);
holder.name = (TextView) convertView.findViewById(R.id.name);
holder.continent = (TextView) convertView.findViewById(R.id.continent);
holder.region = (TextView) convertView.findViewById(R.id.region);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Country country = this.countryList.get(position);
holder.code.setText(country.getCode());
holder.name.setText(country.getName());
holder.continent.setText(country.getContinent());
holder.region.setText(country.getRegion());
return convertView;
}
}
}
Create Country.Java as pojo -
public class Country {
String code = null;
String name = null;
String continent = null;
String region = null;
Double lifeExpectancy = null;
Double gnp = null;
Double surfaceArea = null;
int population = 0;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContinent() {
return continent;
}
public void setContinent(String continent) {
this.continent = continent;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public Double getLifeExpectancy() {
return lifeExpectancy;
}
public void setLifeExpectancy(Double lifeExpectancy) {
this.lifeExpectancy = lifeExpectancy;
}
public Double getGnp() {
return gnp;
}
public void setGnp(Double gnp) {
this.gnp = gnp;
}
public Double getSurfaceArea() {
return surfaceArea;
}
public void setSurfaceArea(Double surfaceArea) {
this.surfaceArea = surfaceArea;
}
public int getPopulation() {
return population;
}
public void setPopulation(int population) {
this.population = population;
}
}
Create main.xml for main layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:padding="10dp"
android:text="#string/some_text" android:textSize="20sp" />
<ListView android:id="#+id/listView1" android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Create country_info.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="6dip" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Code: "
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView1"
android:layout_below="#+id/textView1"
android:text="Name: "
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView2"
android:layout_below="#+id/textView2"
android:text="Continent: "
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="#+id/textView3"
android:layout_below="#+id/textView3"
android:text="Region: "
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="#+id/continent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/textView3"
android:layout_alignBottom="#+id/textView3"
android:layout_toRightOf="#+id/textView3"
android:text="TextView" />
<TextView
android:id="#+id/region"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/textView4"
android:layout_alignBottom="#+id/textView4"
android:layout_alignLeft="#+id/continent"
android:text="TextView" />
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textView3"
android:layout_toRightOf="#+id/textView3"
android:text="TextView" />
<TextView
android:id="#+id/code"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/textView2"
android:layout_alignLeft="#+id/name"
android:text="TextView" />
</RelativeLayout>
Footer View Text - loadmore.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:gravity="center_horizontal"
android:padding="3dp"
android:layout_height="fill_parent">
<TextView
android:id="#id/android:empty"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center"
android:padding="5dp"
android:text="Loading more data..."/>
</LinearLayout>
Don't forget to mention internet permission with -
<uses-permission android:name="android.permission.INTERNET" />
First, you need a OnScrollListener method like this:
private OnScrollListener onScrollListener() {
return new OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int threshold = 1;
int count = listView.getCount();
if (scrollState == SCROLL_STATE_IDLE) {
if (listView.getLastVisiblePosition() >= count - threshold && pageCount < 2) {
Log.i(TAG, "loading more data");
// Execute LoadMoreDataTask AsyncTask
//It reached ListView bottom
getDataFromUrl(url_page2);
}
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
}
};
}
set List View scroll listener by listView.setOnScrollListener(onScrollListener());
I have a full tutorial post HERE! You can visit it!

App crashes at setImageResource()

I am getting a NullPointerException at
image.setImageResource(R.drawable.cover);
Here's my code:
NewsFeed.this.runOnUiThread(new Runnable(){
#Override
public void run() {
//Your code to run in GUI thread here
image.setImageResource(R.drawable.cover);
}
});
This code is running in a doInBackground() method. This is my ImageView in XML:
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
NewsFeed.java
public class NewsFeed extends ListActivity {
MainActivity mainAct = new MainActivity();
private ProgressDialog pDialog;
// json url
// json tags
// JSON Node names
private static final String TAG_DATA = "data";
private static final String TAG_ID = "id";
private static String TAG_MESSAGE = "message";
private static final String TAG_CREATETIME = "created_time";
protected static final String JSONObject = null;
// contacts JSONArray
JSONArray contacts = null;
TimerTask timerTask;
Handler handler;
Timer ourtimer;
String url, gotToken, static_token, imgUrl, nextUrl = "none",
prevUrl = "none", paging;
ImageView image;
Bitmap myBitmap;
// Hashmap for ListView
ArrayList<HashMap<String, String>> contactList;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
// Bundle gotBasket = getIntent().getExtras();
// gotToken = gotBasket.getString("Access_Token");
static_token = "xxxxxxxxxxxxxxxx";
url = "https://graph.facebook.com/v2.2/awaaziitkgp/feed?access_token="
+ static_token;
setContentView(R.layout.news_feed);
image = (ImageView) findViewById(R.id.imageView1);
final TextView button1 = (TextView) findViewById(R.id.button1);
final TextView newPosts = (TextView) findViewById(R.id.nextPosts);
final TextView prevPosts = (TextView) findViewById(R.id.previousPosts);
contactList = new ArrayList<HashMap<String, String>>();
ListView lv = getListView();
// Calling async task to get json
new GetContacts().execute();
}
private class GetContacts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
}
#Override
protected Void doInBackground(Void... arg0) {
// Creating service handler class instance
ServiceHandler sh = new ServiceHandler();
// Making a request to url and getting response
String jsonStr = sh.makeServiceCall(url, ServiceHandler.GET);
Log.d("Response: ", "> " + jsonStr);
if (jsonStr != null) {
try {
JSONObject jsonObj = new JSONObject(jsonStr);
// Getting JSON Array node
contacts = jsonObj.getJSONArray(TAG_DATA);
JSONObject pagingObj = jsonObj.getJSONObject("paging");
// String nextObj = pagingObj.getString("next");
nextUrl = pagingObj.getString("next");
// JSONObject prevObj= pagingObj.getJSONObject("previous");
prevUrl = pagingObj.getString("previous");
Log.d("contact.length", String.valueOf(contacts.length()));
// looping through All Contacts
for (int i = 0; i < 25; i++) {
JSONObject c = contacts.getJSONObject(i);
// tmp hashmap for single contact
HashMap<String, String> data = new HashMap<String, String>();
String message = null;
String id = c.getString(TAG_ID);
data.put(TAG_ID, id);
if (c.has("description") == true) {
message = c.getString("description");
Log.d("Getting Description", message);
}
if (c.has("picture") == true) {
try {
Log.d("IT HAS PICTURE! TADA!!", "Image Found");
imgUrl = c.getString("picture");
Thread thread = new Thread(){
public void run(){
System.out.println("Thread Running");
NewsFeed.this.runOnUiThread(new Runnable(){
#Override
public void run() {
//Your code to run in GUI thread here
URL newUrl = null;
try {
newUrl = new URL(imgUrl);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
myBitmap = getBitmapFromUrl(newUrl);
image.setImageBitmap(myBitmap);
}
});
}
};
thread.start();
} catch (Exception e) {
Log.d("ERROR LOADING IMAGE",
"Why you do this, InputStream? Why?");
}
}else{
NewsFeed.this.runOnUiThread(new Runnable(){
#Override
public void run() {
//Your code to run in GUI thread here
((ImageView) findViewById(R.id.imageView1)).setImageResource(R.drawable.cover);
}
});
}
}
} catch (JSONException e) {
e.printStackTrace();
}
} else {
Log.e("ServiceHandler", "Couldn't get any data from the url");
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
Here you can get a solution.
((ImageView)findViewById(R.id.image_view1)).setImageResource(R.drawable.cover);
XML Snippet:
<ImageView
android:id="#+id/image_view1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
You are trying to inflate a layout then use a view from another layout..
since you used R.layout.activity_main you can only use the views inside that layout nothing more..
but in your case you used the image1 = (ImageView) findViewById(R.id.dice1); which will reference a null value because it reside in your MAIN.xml not in activity_main.
So what you need to do is instead of using the activity_main layout use the appropriate layout which is setContentView(R.layout.MAIN);

Why JSON parser not working on Android?

I have an app which downloads YouTube JSON data. The code works perfectly in a desktop app, but not in android (the list is null when trying to iterate through it). Here's my code which matters:
public String DownloadJSONData(){
BufferedReader reader = null;
String webc = "";
try{
URL url = new URL("http://gdata.youtube.com/feeds/api/users/thecovery/uploads?v=2&alt=json");
reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while((read = reader.read(chars)) != -1){
buffer.append(chars,0,read);
}
webc = buffer.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
return webc;
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println(webc);
return webc;
}
public void GetData() throws JSONException {
JSONObject obj = new JSONObject(DownloadJSONData());
JSONArray feed = obj.getJSONObject("feed").getJSONArray("entry");
for(int i = 0; i < feed.length(); i++){
EPISODE_NAME.add(feed.getJSONObject(i).getJSONObject("title").getString("$t"));
EPISODE_LINK.add(feed.getJSONObject(i).getJSONArray("link").getJSONObject(0).getString("href"));
}
ListView episodes = (ListView) findViewById(R.id.episodeChooser);
ArrayAdapter<String> episodesSource = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,EPISODE_NAME);
}
}
In the onCreate method, I call the GetData() method, and I try to set the adapter to the ListView from the EPISODE_NAME ArrayList, but it's null. I also tried to set the adapter after the method, in onCreate, but no luck. Anyone can help?
It works fine
Add Below permission in Manifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
ManiActivity.java
public class MainActivity extends Activity {
private ListView listView;
private List<FeedsDTO> feedsList = new ArrayList<FeedsDTO>();
private FeedsDTO dto = null;
private BackgroundThread backgroundThread;
private CustomAdapter customAdapter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listview);
backgroundThread = new BackgroundThread();
backgroundThread.execute();
}
private void setListViewAdapter(){
customAdapter = new CustomAdapter(this, R.layout.listitem, feedsList);
listView.setAdapter(customAdapter);
}
private class BackgroundThread extends AsyncTask<Void, Void, String> {
private ProgressDialog progressBar = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressBar = new ProgressDialog(MainActivity.this);
progressBar.setCancelable(false);
progressBar.show();
}
#Override
protected String doInBackground(Void... params) {
BufferedReader reader = null;
String webc = "";
try{
URL url = new URL("http://gdata.youtube.com/feeds/api/users/thecovery/uploads?v=2&alt=json");
reader = new BufferedReader(new InputStreamReader(url.openStream()));
StringBuffer buffer = new StringBuffer();
int read;
char[] chars = new char[1024];
while((read = reader.read(chars)) != -1){
buffer.append(chars,0,read);
}
webc = buffer.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
return webc;
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println(webc);
return webc;
}
#Override
protected void onPostExecute(String result) {
JSONObject obj;
try {
obj = new JSONObject(result);
JSONArray feed = obj.getJSONObject("feed").getJSONArray("entry");
Log.i("=======", "========="+feed.length());
for(int i = 0; i < feed.length(); i++){
dto = new FeedsDTO();
dto.setName(feed.getJSONObject(i).getJSONObject("title").getString("$t"));
dto.setLink(feed.getJSONObject(i).getJSONArray("link").getJSONObject(0).getString("href"));
feedsList.add(dto);
dto = null;
}
Log.i("=======LIst Size", "========="+feedsList.size());
progressBar.dismiss();
setListViewAdapter();
} catch (JSONException e) {
e.printStackTrace();
}
super.onPostExecute(result);
}
}
}
CustomAdapter.java
public class CustomAdapter extends ArrayAdapter<FeedsDTO>{
private LayoutInflater inflater;
private int layoutID;
public CustomAdapter(Context cntx, int resource, List<FeedsDTO> objects) {
super(cntx, resource, objects);
this.inflater =(LayoutInflater) cntx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.layoutID = resource;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
try {
ViewHolder holder = null;
if (convertView == null) {
convertView = inflater.inflate(layoutID, null);
holder = new ViewHolder();
holder.NameTV = (TextView) convertView.findViewById(R.id.textview);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
FeedsDTO feedsDTO = getItem(position);
holder.NameTV.setText(feedsDTO.getName());
feedsDTO = null;
} catch (Exception e) {
e.printStackTrace();
}
return convertView;
}
private class ViewHolder{
TextView NameTV;
}
}
FeedsDTO.java
public class FeedsDTO {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
private String link;
}
listitem.xlm:-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textview"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</TextView>
I hope this code will work perfectly
Most apps include several different activities that allow the user to
perform different actions. Whether an activity is the main activity
that's created when the user clicks your app icon or a different
activity that your app starts in response to a user action, the system
creates every new instance of Activity by calling its onCreate()
method.
You must implement the onCreate() method to perform basic application
startup logic that should happen only once for the entire life of the
activity. For example, your implementation of onCreate() should define
the user interface and possibly instantiate some class-scope
variables.
For example, the following example of the onCreate() method shows some
code that performs some fundamental setup for the activity, such as
declaring the user interface (defined in an XML layout file), defining
member variables, and configuring some of the UI.
You are basically mixing stuff left and right. First create your Interface in the onCreate() and do the logic in onStart().
You should read the android lifecycle. See here

Categories

Resources