Reputation: 1233
Trying to make a simple app that will fetch JSON data from a server and show them in a custom List, pretty simple stuff.
But when I'm running the app, it is showing white blank screen but no data. It doesn't show any error either, I assume if there were any error it wouldn't be running in my phone. But doesn't show the fetched data.
Here is the MainActivity
class
package com.example.root.employeedata;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import org.json.JSONArray;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
List list = new ArrayList<String>();
String[] employees = new String[list.size()];
String data = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try{
URL url = new URL("http://anontech.info/courses/cse491/employees.json");
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while(line != null){
line = bufferedReader.readLine();
data = data + line;
}
JSONArray array = new JSONArray(data);
for(int i=0; i<array.length(); i++){
String employeeName = array.getJSONObject(i).getString("name");
list.add(employeeName);
}
for(int i=0; i<employees.length; i++){
employees[i] = list.get(i).toString();
}
}
catch (Exception e){
e.printStackTrace();
}
for(int i=0; i<employees.length; i++){
System.out.println(employees[i]);
}
ListView listView = (ListView) findViewById(R.id.listView);
CustomAdapter customAdapter = new CustomAdapter();
listView.setAdapter(customAdapter);
}
class CustomAdapter extends BaseAdapter{
@Override
public int getCount() {
return employees.length;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
view = getLayoutInflater().inflate(R.layout.customlayout,null);
TextView textView = (TextView)view.findViewById(R.id.employeeName);
textView.setText(employees[i]);
return view;
}
}
}
Here is the activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.root.employeedata.MainActivity">
<ListView
android:id="@+id/listView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
Here is the customlayout.xml
for custom list,
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/employeeName"
android:layout_width="wrap_content"
android:layout_height="69dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_weight="1"
android:text="TextView" />
</RelativeLayout>
Here is the AndroidManifest.xml
,
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.root.employeedata">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
</application>
</manifest>
This is what it is showing when running the app,
The other questions that I have found did not match with my problem, otherwise would not be adding this question.
Upvotes: 4
Views: 787
Reputation: 8139
1- Make sure your server connection logic away from UI thread, You can use something like AsyncTask.
// Make server logic inside Async Task.
new AsyncTaskHandler(new OnFinishCallback() {
@Override
public void onSuccess(List<String> result) {
CustomAdapter customAdapter = new CustomAdapter(result);
listView.setAdapter(customAdapter);
}
}).execute("http://anontech.info/courses/cse491/employees.json");
2. Avoid anonymous AsyncTask memory leak static inner AsyncTask
/**
* Static inner class to handle memory leak with inner class.
*/
public static class AsyncTaskHandler extends AsyncTask<String, Void, List<String>> {
private final OnFinishCallback callback;
public AsyncTaskHandler(OnFinishCallback callback) {
this.callback = callback;
}
.....
}
3- Update UI component ListView
inside UI thread, AsyncTask
method onPostExecute
executed under UI thread, You can use OnFinishCallback
to update list adapter after onPostExecute
get called.
@Override
protected void onPostExecute(List<String> result) {
// Executed under UI thread to update UI component.
callback.onSuccess(result);
}
4- Use RecyclerView insteadOf ListView
or at least use ViewHolder
pattern Making ListView Scrolling Smooth
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
.....
}
5- Complete example.
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import org.json.JSONArray;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ListView listView = (ListView) findViewById(R.id.listView);
// Make server logic inside Async Task.
new AsyncTaskHandler(new OnFinishCallback() {
@Override
public void onSuccess(List<String> result) {
CustomAdapter customAdapter = new CustomAdapter(result);
listView.setAdapter(customAdapter);
}
}).execute("http://anontech.info/courses/cse491/employees.json");
}
class CustomAdapter extends BaseAdapter {
private final List<String> employees;
public CustomAdapter(List<String> result) {
this.employees = result;
}
@Override
public int getCount() {
return employees.size();
}
@Override
public String getItem(int position) {
return employees.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
// Use ViewHolder pattern.
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
final ViewHolder viewHolder;
if (view !=null){
viewHolder = (ViewHolder) view.getTag();
}else {
view = getLayoutInflater().inflate(R.layout.customlayout, null);
viewHolder = new ViewHolder();
viewHolder.textView = (TextView) view.findViewById(R.id.employeeName);
view.setTag(viewHolder);
}
viewHolder.textView.setText(getItem(i));
return view;
}
// Should use View Holder pattern
public class ViewHolder{
TextView textView;
}
}
/**
* Static inner class to handle memory leak with inner class.
*/
public static class AsyncTaskHandler extends AsyncTask<String, Void, List<String>> {
private final OnFinishCallback callback;
public AsyncTaskHandler(OnFinishCallback callback) {
this.callback = callback;
}
@Override
protected List<String> doInBackground(String... args) {
List<String> result = new ArrayList<>();
try {
URL url = new URL(args[0]);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
String data = "";
while (line != null) {
line = bufferedReader.readLine();
data = data + line;
}
JSONArray array = new JSONArray(data);
for (int i = 0; i < array.length(); i++) {
String employeeName = array.getJSONObject(i).getString("name");
result.add(employeeName);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@Override
protected void onPostExecute(List<String> result) {
callback.onSuccess(result);
}
}
public interface OnFinishCallback{
void onSuccess(List<String> result);
}
}
Upvotes: 0
Reputation: 12005
You're doing a network request on the MainThread
. You're probably getting an exception but it's getting masked by the catch block.
catch (Exception e){
e.printStackTrace();
}
You need to use an AsyncTask to make your network requests.
Something like this. Create an inner class:
private class GetJsonTask extends AsyncTask<URL, Void, String> {
protected String doInBackground(URL... urls) {
try{
HttpURLConnection httpURLConnection = (HttpURLConnection) urls[0].openConnection();
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String line = "";
while(line != null){
line = bufferedReader.readLine();
data = data + line;
}
return data;
}
catch (Exception e){
e.printStackTrace();
}
return null;
}
protected void onPostExecute(String result) {
if(result!=null){
JSONArray array = new JSONArray(result);
for(int i=0; i<array.length(); i++){
String employeeName = array.getJSONObject(i).getString("name");
list.add(employeeName);
}
}
}
}
Upvotes: 2
Reputation: 4121
This is because your employees String array size is 0.
List list = new ArrayList<String>();//initially it has 0 size
String[] employees = new String[list.size()];//list.size()==0
convert employees String[] to Arraylist will solve your problem.
ArrayList<String> employees = new ArrayList<String>();
Detail See this piece of code
for(int i=0; i<employees.length; i++){
employees[i] = list.get(i).toString();
}
because employees.length is 0 so your loop is basically not working even for single item.
Upvotes: 1