JSON download to ListView [duplicate] - java

This question already has answers here:
How do I parse JSON in Android? [duplicate]
(3 answers)
Closed 6 years ago.
I found this code that I have modified to suit my needs. However I am facing a bit of an issue. It appears that the data is obtained from the remote host but cannot be parsed into adapter.
I have reviewed my entire code structure to ensure that everything is in place but I cant seem to find the problem. The ListView is inside of a Fragment that is part of a TabbedActivity.
This my code:
Fragment inside a Tabbed Activity
public class shops extends Fragment {
String url="http://link to remote webservice";
//FragmentManager fm;
//newInstance() method return reference to fragment
public static shops newInstance(){
shops fragment = new shops();
return fragment;
}
public shops() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//fm = getFragmentManager();
View view = inflater.inflate(R.layout.fragment_shops, container, false);
final ListView listView = (ListView)view.findViewById(R.id.shops_info);
final Downloader d =new Downloader(getActivity(),url,listView);
d.execute();
//calls DialoFragment
FloatingActionButton fab = (FloatingActionButton) view.findViewById(R.id.fab_edset);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DialogFragment newEdQua = new createNewEdQua();
newEdQua.show(getActivity().getFragmentManager(), "createNewEdQua");
}
});
// Inflate the layout for this fragment
return view;
}
}
Downloader(receives data and parses in the same class)
public class Downloader extends AsyncTask<Void,Integer,String> {
Context c;
String retredq_url;
ListView listView;
String data;
ArrayList<String> shopl=new ArrayList<String>();//its the ArrayList that we bind to ListView
ProgressDialog pd;
public Downloader(Context c, String retredq_url, ListView listView){
this.c=c;
this.retredq_url=retredq_url;
this.listView=listView;
}
//Before job starts
#Override
protected void onPreExecute(){
super.onPreExecute();
pd=new ProgressDialog(c);
pd.setTitle("Refreshing List");
pd.setMessage("Please Wait...");
pd.show();
}
#Override
protected String doInBackground(Void... params) {
data=downloadData();
return data;
}
#Override
protected void onPostExecute(String s){
super.onPostExecute(s);
pd.dismiss();
if (s !=null){
try{
JSONArray ja=new JSONArray(data);
//JSONObject jo=null;
shopl.clear();//we need to add the data to ArrayList, so clear list first to avoid duplicates
for (int i=0;i<ja.length();i++){
String shops=ja.getJSONObject(i).getString("Qualification")+ ja.getJSONObject(i).get("eq_end_date")+
ja.getJSONObject(i).get("eq_loc_shops");//retrieve the column name into a string
shopl.add(shops);
ArrayAdapter<String> adapter=new ArrayAdapter<String>(c,R.layout.list_item_shopl,shopl);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Snackbar.make(view,shopl.get(i),Snackbar.LENGTH_LONG).show();
}
});
}
} catch (JSONException e) {
Log.e("Downloader", "Error", e);
}
/*
//call the Parser here to parse the JSON after we confirm string writer is not null
Parser p=new Parser(c,s,listView);
p.execute();*/
}else {
Toast.makeText(c,"Unable to download data", Toast.LENGTH_SHORT).show();
}
}
private String downloadData(){
//connect and get a stream
InputStream inputStream=null;
String line=null;
try{
URL url=new URL(retredq_url);
HttpURLConnection con=(HttpURLConnection) url.openConnection();
inputStream=new BufferedInputStream(con.getInputStream());
BufferedReader br=new BufferedReader(new InputStreamReader(inputStream));
StringBuffer sb=new StringBuffer();
if (br !=null){
while ((line=br.readLine()) !=null){
sb.append(line+"\n");
}
}else{return null;}
return sb.toString();
} catch (MalformlocRLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (inputStream !=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
JSON output (Checked with ARC plugin on Chrome)
{"qualifications":[{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"}],"success":1}
A slight difference from what ADM sees (The success message comes first here)
{"success":1,"qualifications":[{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"},{"eq_edu_Institution":"Oracle","eq_start_Date":"1998-06-14","eq_end_date":"2005-08-23","Qualification":"Software Engineer"}]}
I defined the success message while struturing the array in php webservice
I intend use the Downloader class in several tabs for the same purpose(retrieve data from url parse and display in ListView). The urls and data are independent ot each other so I guess it should work...

Going over LogCat and reviewing JSON data obtained from server I was able to figure the problem. My previous code would have worked without any issues if the data was an Array with Objects in it. But I checked and the structure of the JSON was an Object with the Array inside.
What I had to do was get the Object with JSONObject then that Object retrieve the Array with JSONArray.. Like this:
JSONObject jsonObject=new JSONObject(data);
JSONArray jsonArray= jsonObject.getJSONArray("qualifications");
//now this Array has Objects needed
for (int i=0;i<jsonArray.length();i++){
String institution=jsonArray.getJSONObject(i).getString("Qualification");
edqua.add(institution);
}
//provide the ArrayAdapter<> needed
ArrayAdapter<String> adapter=new ArrayAdapter<String>(c,R.layout.list_item_edqua,edqua);
listView.setAdapter(adapter);
It should be in a try-catch block.. It is good to know the structure of the JSON that is expected. I was rather asking for an Array when Object was being offerd, hence the type mis-match error. I also realised that I will be unable to use the same class for different data sources, as the tables are completely. Any suggestions of how to use one class for different data urls will appreciated.

As the ArrayList<String> shows, the list item will be like
Qualification eq_end_date eq_loc_shops as a single string, so initialize the adapter like
adapter = new ArrayAdapter<>(context,android.R.layout.simple_list_item_1,shopl);

Most of your code can be reused but the part which starts from data generated by downloadData() to the JSONArrayObject that your listview needs.
So you can extract these code to an Interface(here called IPreParser)'s method (called JSONArrayObject arrayFromData(String)), like this:
public interface IPreParser{
JSONArrayObject arrayFromData(String data);
}
Your Downloader need hold a reference to IPreParser, and invoke its method in onPostExecute(). And you can initialize this reference by declaring doInBackground(IPreParser).
In anywhere you what download and parse your data, just implement IPreParser, and then execute your downloader with downloader.execute(yourImplementor);

Related

doInBackground does not run inside Activity onCreate

What I have :
I have a SearchActivity which receives an ArrayList (NameDesSearch) from a fragment(after a button click) and it updates a simple listview. When I click a list view item a new view is appearing by the corresponding object (orgDesObj) of the clicked list item. This functionality works well.
Currently receiving list (NameDesSearch) consists of names and descriptions. All are strings.
But, I wanted to show lists names only. Hence I tried creating a function (titlefunc()).
Here a new ArrayList ( NameDesTitles ) was crated to add relevent names only.
Issue:
But, seems like Do In background function is not working by the time I call titlefunc().
Attempts:
I put several Log to capture the point.
I'm using the same function (getLocDesOb()) in the list view on item clicked as well.
Surprisingly it works, even the doInBackground function also works.
But when the search activity creates and titlefunc() is called, search list (finalODescriptionArrayList) in doInBackground is empty().
Form the Logs I receive the content of finalODescriptionArrayList as [] and size as 0.
But, when I click list view item finalODescriptionArrayList updates.
I even tried by moving NameDesSearch = getIntent().getStringArrayListExtra("searched"); outside of the function as well.
Seems like my doInBackground method is calling only when the list item clicked but not activity on creates. Every other function works well. I'm not sure by the time when why my titlefunc() is called, why finalODescriptionArrayList does not update.
I would appreciate any suggestions on this. Thank you !
My Code: I have removed Logs for clearness.
public class SearchActivity extends AppCompatActivity {
ListView searchedListView;
String SearchedWord;
private ArrayAdapter<String> orgAdapter;
ArrayList<String> NameDesSearch = new ArrayList<String>();
ArrayList<String> NameDesTitles = new ArrayList<String>();
private OService OService;
ArrayList<ODescription> finalODescriptionArrayList = new ArrayList<ODescription>();
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
searchedListView = (ListView) findViewById(R.id.searched_list_view);
new GetCourse().execute();
titlefunc();
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, NameDesTitles);
searchedListView.setAdapter(arrayAdapter);
searchedListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String selectedItemText = parent.getItemAtPosition(position).toString();
ODescription orgDesObj = getLocDesOb(selectedItemText);
if (orgDesObj != null) {
Intent intent = new Intent(SearchActivity.this, View.class);
intent.putExtra("sOb", orgDesObj);
startActivity(intent);
}
}
});
}
#SuppressLint("StaticFieldLeak")
private class GetCourse extends AsyncTask<Void, Void, Void> {
#TargetApi(Build.VERSION_CODES.N)
#Override
protected Void doInBackground(Void... voids) {
try {
finalODescriptionArrayList = JsontoObject.jsonToObjectData(getResources().openRawResource(R.raw.newdb));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
public ODescription getLocDesOb(String selectedItemText) {
if (finalODescriptionArrayList == null) {
return null;
}
for (ODescription locDescObj : finalODescriptionArrayList) {
if (locDescObj.getName().equals(selectedItemText) || locDescObj.getDescription().equals(selectedItemText)) {
return locDescObj;
}
}
return null;
}
public void titlefunc() {
NameDesSearch = getIntent().getStringArrayListExtra("searched");
for (String searchNameDes : NameDesSearch) {
ODescription orgDesObj2 = getLocDesOb(searchNameDes);
if (orgDesObj2 != null) {
NameDesTitles.add(orgDesObj2.getName());
}
}
}
}
Attempts After Answer Below
AsyncTask update with onPostExecute. Then Since it take a little bit of time a progress bar added with onPreExecute. titlefunc() in oncreate method removed.
This method works now. But, sometimes the same issue exists. Arraylist to adapter is empty so that listview is empty. Seems like still taking lot of time to do the background task.
Updated AsyncTask
#SuppressLint("StaticFieldLeak")
private class GetCourse extends AsyncTask<Void, Void, Void> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(SearchActivity.this);
progressDialog.setMessage("Searching");
progressDialog.setCancelable(false);
progressDialog.show();
}
#TargetApi(Build.VERSION_CODES.N)
#Override
protected Void doInBackground(Void... voids) {
try {
finalODescriptionArrayList = JsontoObject.jsonToObjectData(getResources().openRawResource(R.raw.newdb));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
titlefunc();
arrayAdapter.notifyDataSetChanged();
if (progressDialog.isShowing())
progressDialog.dismiss();
}
}
Modifed titlefunc() - to remove duplicates
Set<String > set = new HashSet<>( NameDesTitles);
NameDesTitles.clear();
NameDesTitles.addAll(set);
Your AsyncTask runs asynchronously, in the background. It will (most likely) not be finished when you call titleFunc() (which is what you are seeing).
You can fix this in many ways. One way would be to update the content of your adapter after the AsyncTask completes. You can do this in onPostExecute() of your AsyncTask which will be called when the background processing completes. In that method you can run your titleFunc() or something similar to filter the results you want to display. You then need to tell your Adapter to update the view by calling notifyDatasetChanged() on the Adapter.

Passing data between two fragments through async task

I have just started out with Java development(android app) and I stumbled upon a problem I don't know how to solve.
So I have two fragments:
1) Fragment with barcode scanner
2) Fragment with just a simple textview
The app should be able to scan barcode, get API response based on the scan result, deserialize it into a Java object and then show value of one variable in the textview located in the second fragment.
I have already implemented the barcode scanner and class to get data from API and turn it into a Java object. The problem is that I can't find a way to send the barcode result to the class that handles the API data retrieval and also how to send the object to the second fragment.
Can someone please direct me in the right way on how to implement it correctly?
1)Barcode fragment
public class BarcodeFragment extends Fragment {
private CodeScanner mCodeScanner;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
final Activity activity = getActivity();
View root = inflater.inflate(R.layout.barcode_fragment, container, false);
CodeScannerView scannerView = root.findViewById(R.id.scanner_view);
mCodeScanner = new CodeScanner(activity, scannerView);
mCodeScanner.setDecodeCallback(new DecodeCallback() {
#Override
public void onDecoded(#NonNull final Result result) {
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(activity.getApplicationContext(), result.getText(), Toast.LENGTH_SHORT).show();
}
});
}
});
scannerView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mCodeScanner.startPreview();
}
});
return root;
}
#Override
public void onResume() {
super.onResume();
mCodeScanner.startPreview();
}
#Override
public void onPause() {
mCodeScanner.releaseResources();
super.onPause();
}
}
2) Class to get data from API and turn it into JAVA object
public class RetrieveFeedTask extends AsyncTask<Void, Void, String> {
Product productFromDatabase;
String resultString;
public RetrieveFeedTask(String barcodeResult){
resultString = barcodeResult;
}
protected void onPreExecute() {
}
protected String doInBackground(Void... urls) {
try {
URL url = new URL("https://api.appery.io/rest/1/apiexpress/api/example/Products?apiKey=12345678&Barcode=" + resultString);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
bufferedReader.close();
return stringBuilder.toString();
}
finally{
urlConnection.disconnect();
}
}
catch(Exception e) {
Log.e("ERROR", e.getMessage(), e);
return null;
}
}
protected void onPostExecute(String response) {
if(response == null) {
response = "THERE WAS AN ERROR";
}
Log.i("INFO", response);
deSerializeProduct(response);
}
public void deSerializeProduct(String response){
response = response.substring(1,response.length() - 3);
StringBuilder stringBuilder = new StringBuilder(response);
stringBuilder.append(",\"productId\":\"23323123sdasd\"}"); // for testing
String responseToDeSerialize = stringBuilder.toString();
ObjectMapper mapper = new ObjectMapper();
try {
productFromDatabase = mapper.readValue(responseToDeSerialize, Product.class);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3) Cart fragment class where to name of the object should appear in the textview
public class CartFragment extends Fragment {
static TextView showReceivedData;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
View view = inflater.inflate(R.layout.cart_fragment, parent, false);
showReceivedData = (TextView) view.findViewById(R.id.resultCode);
return view;
}
}
The asynctask shouldn't outlive the lifecycle of the activity or fragment that starts it. I'm assuming you probably will display some sort of loading status while the network request happens. Here are some options:
If the two fragments are in the same activity, you could pass the result of the scan to the activity, kick off the network request, swap fragments, and send the request result to the second fragment.
The scanner fragment can get the barcode data, kick off the request, show the loading state, and when the result returns, package in the bundle, which the second fragment can read.
Invert the previous model, if it fits your app better, and send just the barcode result in the bundle, and have the second fragment kick off the request while displaying the loading status.
The exact choice will depend on the flow and structure of your app. Additionally, you may want to look into using another multithreading option instead of asynctask, as it has been deprecated and Google is trying to move developers away from it. Some alternatives are the Java concurrency library, RxJava, or if you are willing to use Kotlin in your project, Kotlin coroutines.
Use Bundle to add pass data between Activity and fragments
try This code to Pass data between two fragments
Bundle bundle=new Bundle();
bundle.putString("scanner_data","myData");
Fragment fragment=new HomeFragment();
fragment.setArguments(bundle);
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.add(R.id.framContainer, fragment, "TAg");
ft.commit();
How to get data
Bundle bundle=getArguments();

How to display random items from arraylist<T> derived from a doInBackground?

So i was making this app which displays an arrayList of different poems
I first request the poems from API then the Asynctask returns the poems in the form of Arraylist i wand to show 20 random poems from the list.
This is the Asynctask code
private class TitleAsynctask extends AsyncTask<URL,Void,List<view>> {
private ProgressDialog progressDialog;
#Override
public List<view> doInBackground(URL... urls){
URL url = Query_utils.createurl(POEM_TITLE);
String json = "";
Log.d(LOG_TAG,"this worked");
{
try {
json = Query_utils.makehttprequest(url);
Log.d(LOG_TAG, "make Httprequest works");
} catch (IOException e) {
}
}
List<view> title_view = Query_utils.extracttitlefromjson(json);
return title_view;
}
#RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
#Override
protected void onPostExecute(List<view> data) {
madapter.clear();
if (data != null && !data.isEmpty()){
madapter.addAll(data);
}
}
}
and the onCreate code is
TitleAsynctask task = new TitleAsynctask();
URL url = Query_utils.createurl(POEM_TITLE);
task.execute(url);
ArrayList<view > arr = new ArrayList<view>();
final ListView poem_Title_list = (ListView) findViewById(R.id.list_item);
madapter = new title_adapter(this ,arr);
poem_Title_list.setAdapter(madapter);
I can think of two ways:
Just use a random number generator to generate a number between 0 and the number of entries-1. The disadvantage with this method is that you can get repeats.
Randomly sort the list after fetching. You can do this using Collections.shuffle(list) This way you won't get any repeats but you will sort the whole list which could be a waste if there are hundreds of entries and you only want to show 20.

ArrayList being empty after adding elements

I have this android code which bring a JSON from a server and fill an ArrayList from that JSON
I checked the size of the ArrayList "meals" inside the onresponse void it gives me 1 but when i check it after the StringRequest object i get 0 items .
meals is defined in global scope and initialized inside the oncreateview function
The Code:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i("debug","on create view");
View view =inflater.inflate(R.layout.fragment_meal_list,container,false);
ListView List ;
meals=new ArrayList<meal>();
String url="http://syriankitchen.tk/get_recent.php";
StringRequest mealsrequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try{
JSONObject object= new JSONObject(response);
JSONArray mealsArray = object.getJSONArray("result");
for(int i=0;i<mealsArray.length();i++){
JSONObject cur = mealsArray.getJSONObject(i);
int id= cur.getInt("id");
String name= cur.getString("name");
String description = cur.getString("description");
int price = cur.getInt("price");
meals.add(new meal(id,name,price,description));
}
Log.i("debug","meals size = "+meals.size());
}
catch(JSONException e){
e.printStackTrace();
}
}
},new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(),error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
Volley.newRequestQueue(getActivity()).add(mealsrequest);
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
for(int i=0;i<meals.size();i++)strs.add(meals.get(i).getName());
strs.toArray(mealsnames);
Log.i("debug","meals ou size "+meals.size());
CustomList adapter = new CustomList(getActivity(),mealsnames,meals);
List = (ListView)view.findViewById(R.id.list);
List.setAdapter(adapter);
The problem here is about understanding how asynchronous tasks work. When you are adding a volley request to the queque, it will run in background thread (off the main thread) and control will pass to the next line.
So, after this:
Volley.newRequestQueue(getActivity()).add(mealsrequest);
control passes to this:
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
Now since meals is updated on the background thread, you are not able to get the data by the time control reaches String mealsnames[]=new String[meals.size()];
So you will get zero size (meals.size()) here.
Try to move this portion of the code into onResponse.
Try like this:
public void updateData(){
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
for(int i=0;i<meals.size();i++)strs.add(meals.get(i).getName());
strs.toArray(mealsnames);
Log.i("debug","meals ou size "+meals.size());
CustomList adapter = new CustomList(getActivity(),mealsnames,meals);
List = (ListView)view.findViewById(R.id.list);
List.setAdapter(adapter);
}
and call this method from onResponse:
#Override
public void onResponse(String response) {
try{
JSONObject object= new JSONObject(response);
JSONArray mealsArray = object.getJSONArray("result");
for(int i=0;i<mealsArray.length();i++){
JSONObject cur = mealsArray.getJSONObject(i);
int id= cur.getInt("id");
String name= cur.getString("name");
String description = cur.getString("description");
int price = cur.getInt("price");
meals.add(new meal(id,name,price,description));
}
Log.i("debug","meals size = "+meals.size());
updateData();
}
catch(JSONException e){
e.printStackTrace();
}
}
When you write this -
Volley.newRequestQueue(getActivity()).add(mealsrequest);
That means you are making an asynchronous call and that mealsrequest will run on another thread.
You are printing -
Log.i("debug","meals ou size "+meals.size());
just after you make your mealsrequest. When control reaches this statement your network request is not completed yet. So apparently, you don't have anything in your list. Your list will be populated in onResponse() only, since that method is executed after the network request gets completed.

Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference

I've been looking for a similar problem to mine in order to find a solution, but I seriously couldn't find anything like that.
I was trying to download from parse an array of posts with an asynctask class, and after it gets the posts, it suppose to set the posts array in my page, and perform the setAdapter function in order to set my new posts array.
the problem is, after I've initialized listView and listAdapter in my home fragment,and then I perform the postArray taking from parse function, after it finishes taking the posts array from parse, it cannot update listAdapter because it says the listAdapter and my listView "haven't initialized yet", even though they have.
p.s.
sorry for not posting my code in a convenient way, I don't tend to post my code problems that often.
here's my code:
my home fragment:
public class HomeFragment extends Fragment {
View root;
ArrayList<PostClass> postsArrayList = new ArrayList<>();
static boolean isPostsArrayUpdated = false;
ListAdapter listAdapter;
PullToRefreshListView listView;
public void updatePostsArrayList(ArrayList<PostClass> postsArrayList){
if(!isPostsArrayUpdated){
// First time updating posts array list
listAdapter = new ListAdapter(getActivity(), root);
listView = (PullToRefreshListView) root.findViewById(R.id.list_container);
this.postsArrayList = postsArrayList;
listView.setAdapter(listAdapter);
isPostsArrayUpdated = true;
root.findViewById(R.id.homeFragmentLoadingPanel).setVisibility(View.GONE);
}else{
// Have updated posts before
this.postsArrayList = postsArrayList;
listAdapter.notifyDataSetChanged();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.fragment_home, container, false);
listView = (PullToRefreshListView) root.findViewById(R.id.list_container);
listAdapter = new ListAdapter(getActivity(), root);
Home_Model.getInstance().setPostsArrayList();
return root;
}
public class ListAdapter extends BaseAdapter implements View.OnClickListener{//....}
my home model:
public class Home_Model {
Home_Model(){}
static final Home_Model instance = new Home_Model();
public static Home_Model getInstance() {
return instance;
}
public void setPostsArrayList(){
new setHomePostsArray().execute();
}
public class setHomePostsArray extends AsyncTask<Void, ArrayList<PostClass>, Void>{
ArrayList<String> followersList;
ArrayList<PostClass> postsArrayList;
#Override
protected Void doInBackground(Void... params) {
// Getting posts from parse
String userName = Parse_model.getInstance().getUserClass().get_userName();
followersList = Parse_model.getInstance().getFollowersByUserNameToString(userName);
followersList.add(userName);
postsArrayList = Parse_model.getInstance().getAllUsersPostsByFollowings(followersList);
for (PostClass currPost : postsArrayList) {
for (PostClass currLocalDBPost : LocalDBPostsArray) {
if (currPost.getObjectID().equals(currLocalDBPost.getObjectID())) {
currPost.set_postPicture(currLocalDBPost.get_postPicture());
}
}
}
//Updating home page
onProgressUpdate(postsArrayList);
// Updating local data base in new posts
//checking in local DB if there are any new posts from parse and update them
for (PostClass currPost : postsArrayList) {
boolean isPostExists = false;
for (PostClass currLocalPost : LocalDBPostsArray) {
if (currPost.getObjectID().equals(currLocalPost.getObjectID())) {
isPostExists = true;
}
}
if (!isPostExists) {
ModelSql.getInstance().addPost(currPost);
Log.e("post not exist", "adding local DB");
}
}
//updating followers list in local DB
Parse_model.getInstance().getUserClass().setFollowersArray(followersList);
ModelSql.getInstance().updateFollowersArray(currUser);
return null;
}
#Override
protected void onProgressUpdate(ArrayList<PostClass>... values) {
//pass the updated postsArrayList to home fragment
if(setPostsInHomePageDelegate!= null){
setPostsInHomePageDelegate.setPosts(values[0]);
}
}
}
public interface SetPostsInHomePage {
public void setPosts(ArrayList<PostClass> postsArrayList);
}
SetPostsInHomePage setPostsInHomePageDelegate;
public void setSetPostsInHomePageDelegate(SetPostsInHomePage setPostsInHomePageDelegate) {
this.setPostsInHomePageDelegate = setPostsInHomePageDelegate;
}
main activity:
public class MainActivity extends Activity {
static HomeFragment homeFragment = new HomeFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// the home fragment has already been opened during the app opening
//...
setPostsImHomePage();
}
//...
public void setPostsImHomePage(){
Home_Model.getInstance().setSetPostsInHomePageDelegate(new Home_Model.SetPostsInHomePage() {
#Override
public void setPosts(ArrayList<PostClass> postsArrayList) {
homeFragment.updatePostsArrayList(postsArrayList);
}
});
}
}
Try to move your method setPostsImHomePage(...) from MainActivity to HomeFragmentand call it in OnCreateView before return root;.
Try initializing homeFragment in onCreate before your method call. It's also helpful to know which line(s) are giving you errors.
Obviously your fragment has no View when the result arrives.
You should properly add the fragment to the Activity using the FragmentManager, then in the Fragment's onActivityCreated() callback (which is called by the system after the Fragment has its view properly set), start your AsyncTask.

Categories