Mark Barton Mark Barton - 9 months ago 28
Java Question

Integrated News feed not displaying (ANDROID KITKAT)

SO I'm creating an application for dog lovers (University project) and I'm trying to create an integrated news feed that shows dog related news and when clicked takes the user to the website. I made a dummy application to test the system and it worked perfectly. as soon as I switched it over to my current Dog app it completely stopped working. The problem is that the Activity I use to display the list of articles shows absolutely nothing.

There are 2 activities here, a Links Activity and a newsItem Activity. The Links Activity is the main activity the page uses and displays the text in a certain way on the page. The newsItem Activity acts as a getter and works through a JSON file to find certain words in an array and parse them back to the application. I also use a localHost to host the JSON file.

If you guys can help me out here that would be incredible! I've hit a complete brick wall.

The Links_Activity Class is connected to the activity_links.xml file

The newsItem Class is connected to the Article.xml file

Links_Activity Class

package uk.ac.napier.doggo;

import android.content.Intent;
import android.net.Uri;
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.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;


import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.squareup.picasso.Picasso;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class Links_Activity extends AppCompatActivity {

private List<newsItem> newsFeed = new ArrayList<>();

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

engine();
addClickListener();

}

private void engine() {
RequestQueue queue = Volley.newRequestQueue(this);

JsonObjectRequest myReq = new JsonObjectRequest(Request.Method.GET,
"http://10.0.2.2/news.json",
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
JSONArray newsItems = response.getJSONArray("newsItems");

for (int i = 0; i < newsItems.length(); i++) {
JSONObject temp = newsItems.getJSONObject(i);

String image = temp.getString("image");
String title = temp.getString("title");
String time = temp.getString("time");
String date = temp.getString("date");
String content = temp.getString("content");
String link = temp.getString("link");


newsFeed.add(new newsItem(title, content, date, time, link, image));

}
} catch(JSONException e){
Log.i("myTag", e.toString());
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.i("myTag", error.toString());
}
});



myReq.setRetryPolicy(new DefaultRetryPolicy(
30*1000,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
queue.add(myReq);



ArrayAdapter<newsItem> adapter = new customAdapter();

ListView newsItems = (ListView) (findViewById(R.id.newsItems));
newsItems.setAdapter(adapter);

}

private void addClickListener() {
ListView newsItems = (ListView) (findViewById(R.id.newsItems));
newsItems.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
newsItem currentItem = newsFeed.get(position);
Intent i = new Intent (Intent.ACTION_VIEW);
i.setData(Uri.parse(currentItem.getUrl()));
startActivity(i);
}
});
}



private class customAdapter extends ArrayAdapter<newsItem> {
public customAdapter() {
super(Links_Activity.this, R.layout.article, newsFeed);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {

if(convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.article, parent, false);
}

newsItem currentItem = newsFeed.get(position);

ImageView newsImage = (ImageView) convertView.findViewById(R.id.leftIco);
TextView heading = (TextView) convertView.findViewById(R.id.heading);
TextView desc = (TextView) convertView.findViewById(R.id.desc);

heading.setText(currentItem.getNewsHeading());
desc.setText(currentItem.getNewsDesc());

Picasso.with(Links_Activity.this).load(currentItem.getImageURL()).into(newsImage);


return convertView;
}

}

public void Back(View view) {
Intent startBackActivity = new Intent(this, Menu_Activity.class);
startActivity(startBackActivity);
}
}


activity_links.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="News Feed"
android:textSize="25sp"
android:textAlignment="center"
android:id="@+id/logo"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>

<TextView
android:text="Articles Courtesy of Dogster.com"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true" />

<ListView
android:layout_width="wrap_content"
android:layout_height="400dp"
android:id="@+id/newsItems"
android:layout_centerVertical="true"
android:layout_alignParentStart="true" />

</RelativeLayout>


newsItem Class

package uk.ac.napier.doggo;

import java.util.PriorityQueue;

/**
* Created by MarkB on 10/03/2017.
*/

public class newsItem {

private String newsHeading;
private String newsDesc;
private String newsDescSmall;
private String time;
private String date;
private String url;
private String imageURL;

public newsItem(String newsHeading, String newsDesc, String date, String time, String url, String imageURL) {
this.newsHeading = newsHeading;
this.newsDesc = newsDesc;
this.time = time;
this.date = date;
this.url = url;
this.imageURL = imageURL;

this.newsDescSmall = this.newsDesc.substring(0, 50) + "...";
}

public String getNewsHeading() {
return newsHeading;
}

public String getNewsDesc() {
return newsDesc;
}

public String getTime() {
return time;
}

public String getDate() {
return date;
}

public String getUrl() {
return url;
}

public String getImageURL() {
return imageURL;
}
}


article.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">

<ImageView
android:layout_width="80dp"
android:layout_height="100dp"
android:id="@+id/leftIco"
android:src="@mipmap/ic_launcher"
android:maxHeight="100dp"
android:maxWidth="100dp"
android:adjustViewBounds="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="Heading Text"
android:id="@+id/heading"
android:scrollHorizontally="false"
android:maxLines="100"
android:ellipsize="none"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/leftIco"
android:layout_toEndOf="@+id/leftIco"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Description"
android:id="@+id/desc"
android:lineSpacingExtra="-3dp"
android:layout_marginBottom="26dp"
android:layout_alignBottom="@+id/leftIco"
android:layout_alignLeft="@+id/heading"
android:layout_alignStart="@+id/heading"/>




</RelativeLayout>


AndroidManifest.xml for reference

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="uk.ac.napier.doggo">

<uses-permission android:name="android.permission.INTERNET">
</uses-permission>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".Home_Screen_Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name=".Details_Activity" />
<activity android:name=".Menu_Activity" />
<activity android:name=".Reminders_Activity" />
<activity android:name=".Health_Tracker_Activity" />
<activity android:name=".Routes_Activity" />
<activity android:name=".Route_Complete_Activity" />
<activity android:name=".History_Activity" />
<activity android:name=".Links_Activity" >

</activity>

<activity android:name=".TimePopUp_Activity"
android:theme="@style/AppTheme.CustomTheme" >
</activity>

</application>

</manifest>


Finally the news.JSON file

{"newsItems":[
{
"image": "http://www.dogster.com/wp-content/uploads/2017/03/16806949_152063731974308_6992949846293798966_n-Cropped.jpg",
"title": "Artist Arien Smith Imagines Disney Princesses With Service Dogs",
"time": "10:00am ",
"date": "22 Jun ",
"content": "So far, the artist has drawn Cinderella and Snow White with service dogs, with the hope of raising awareness and money for his own helper.",
"link": "http://www.dogster.com/lifestyle/artist-arien-smith-imagines-disney-princesses-with-service-dogs"
},
{
"image": "http://www.dogster.com/wp-content/uploads/2016/06/Stalking-predatory-hero.png",
"title": "Is Your Dog a Bully?",
"time":"12:00am ",
"date":"Jun 12",
"content": "Dogs who bully not only start fights, but they can turn timid dogs into bullies themselves. Let's look at the signs of bullying and how to help your dog stop this behavior.",
"link": "http://www.dogster.com/lifestyle/is-your-dog-a-bully"
}
]
}

Answer Source

You never called adapter.notifyDataSetChanged()

        newsFeed.add(new newsItem(title, content, date, time, link, image));
    }  // end loop
    // notify the adapter to display the new data 
    adapter.notifyDataSetChanged()
} catch(JSONException e){
    Log.i("myTag", e.toString());
}

However, you have an ArrayAdapter, so just add to that, not the Arraylist then you don't need to notify

        // See here
        adapter.add(new newsItem(title, content, date, time, link, image));
    }  // end loop
} catch(JSONException e){
    Log.i("myTag", e.toString());
}

Some re-arrangement of your code that should work.

public class LinksActivity extends AppCompatActivity 
  implements AdapterView.OnItemClickListener, Response.ErrorListener {

    private List<NewsItem> newsFeed = new ArrayList<>();
    private ArrayAdapter<NewsItem>  adapter;

    // Moved the Volley response to top-level
    private Response.Listener<JSONObject>  newsListener = new Response.Listener<JSONObject>()  {        

        @Override
        public void onResponse(JSONObject response) {
            try {
                JSONArray newsItems = response.getJSONArray("newsItems");

                for (int i = 0; i < newsItems.length(); i++) {
                    JSONObject temp = newsItems.getJSONObject(i);

                    String image = temp.getString("image");
                    String title = temp.getString("title");
                    String time = temp.getString("time");
                    String date = temp.getString("date");
                    String content = temp.getString("content");
                    String link = temp.getString("link");


                    newsFeed.add(new newsItem(title, content, date, time, link, image));
                }

                // Important!
                adapter.notifyDataSetChanged();

            } catch(JSONException e){
                Log.i("myTag", e.toString());
            }
        }
    };

    // This is Volley's error listener over the entire Activity
    @Override
    public void onErrorResponse(VolleyError error) {
        Log.i("myTag", error.toString());
    }

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

        // Set and define the List and Adapter here
        ListView  newsItems = (ListView) findViewById(R.id.newsItems);
        newsItems.setOnItemClickListener(this);

        adapter = new CustomAdapter();
        newsItems.setAdapter(adapter);

        engine();
    }

    private void engine() {
        RequestQueue queue = Volley.newRequestQueue(this);

        // Now this method is much 'cleaner'
        JsonObjectRequest myReq = new JsonObjectRequest(Request.Method.GET,
                "http://10.0.2.2/news.json",
                null, 
                newsListener, this);

        myReq.setRetryPolicy(new DefaultRetryPolicy(
                30*1000,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        queue.add(myReq);
    }

    // The Activity itself handles the clicking
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        NewsItem currentItem = newsFeed.get(position);
        Intent i = new Intent (Intent.ACTION_VIEW);
        i.setData(Uri.parse(currentItem.getUrl()));
        startActivity(i);
    }
}