Android How to dynamically update a listview? - android

I have an app that loads the traffic report from a server and shows it in a timeline (like twitter), the app is configured to load the data from the server every 10 seconds using this code:
#Override
public void onResume() {
super.onResume();
autoUpdate = new Timer();
autoUpdate.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
new DownloadJSON2().execute(); // this is the class that downloads the data from the server.
}
});
}
}, 0, 10000); // updates each 10 secs
}
#Override
public void onPause() {
autoUpdate.cancel();
super.onPause();
}
The problem is that if I scroll down the list and I'm reading the older posts, the list refreshes and send me to the top of it. I want to download that data like ajax and append it to the top. Or just to tell me that is X new reports and a button to show it.
How can I acomplish this?
BTW I'm extremely new to android programming.
Thanks in advance.
EDIT: Thanks to Vasily Sochinsky i've added the following:
public class DownloadJSON extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
mProgressDialog = new ProgressDialog(MainActivity.this);
// Set progressdialog title
mProgressDialog.setTitle("Cargando reportes en tiempo real");
// Set progressdialog message
mProgressDialog.setMessage("Por favor espere");
mProgressDialog.setIndeterminate(false);
// Show progressdialog
mProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
// Create an array
arraylist = new ArrayList<HashMap<String, String>>();
// Retrieve JSON Objects from the given URL address
jsonobject = JSONfunctions
.getJSONfromURL("http://server.com/timeline.php");
try {
// Locate the array name in JSON
jsonarray = jsonobject.getJSONArray("datos");
for (int i = 0; i < jsonarray.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
jsonobject = jsonarray.getJSONObject(i);
// Retrive JSON Objects
// jsonobject1 = jsonobject.getJSONObject("contenido");
map.put("imagen", jsonobject.getString("imagen"));
map.put("quien", jsonobject.getString("quien"));
map.put("fecha", jsonobject.getString("fecha"));
map.put("reporte", jsonobject.getString("reporte"));
// map.put("imgs", jsonobject1.getString("imgs"));
// map.put("video", jsonobject1.getString("video"));
// Set the JSON Objects into the array
arraylist.add(map);
}
} catch (JSONException e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void args) {
// Locate the listview in listview_main.xml
listview = (ListView) findViewById(R.id.listview);
// Pass the results into ListViewAdapter.java
adapter = new ListViewAdapter(MainActivity.this, arraylist);
// Set the adapter to the ListView
listview.setAdapter(adapter);
adapter.notifyDataSetChanged();
// Close the progressdialog
mProgressDialog.dismiss();
}
}
But the listview is not updating with the new data, how can i achieve this?
EDIT 2: Thanks to cogentapps that gave me a solution, but i still can not add it to the code, where should i add it?
I've tried this but eclipse shows many errors:
protected void onPostExecute(Void args) {
// Locate the listview in listview_main.xml
listview = (ListView) findViewById(R.id.listview);
// Pass the results into ListViewAdapter.java
adapter = new ListViewAdapter(MainActivity.this, arraylist);
// Set the adapter to the ListView
adapter.addAll();
listview.notifyDataSetChanged();
// Close the progressdialog
mProgressDialog.dismiss();
}
This is the code from my ListViewAdapter, where should i add the adapter.add()?
public class ListViewAdapter extends BaseAdapter {
// Declare Variables
Context context;
LayoutInflater inflater;
ArrayList<HashMap<String, String>> data;
ImageLoader imageLoader;
HashMap<String, String> resultp = new HashMap<String, String>();
String coment;
public String img;
public int imga;
public ListViewAdapter(Context context,
ArrayList<HashMap<String, String>> arraylist) {
this.context = context;
data = arraylist;
imageLoader = new ImageLoader(context);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
public View getView(final int position, View convertView, ViewGroup parent) {
// Declare Variables
TextView quien;
ImageView imagen;
TextView reporte;
TextView fecha;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View itemView = inflater.inflate(R.layout.listview_item, parent, false);
// Get the position
resultp = data.get(position);
// Locate the TextViews in listview_item.xml
// Locate the ImageView in listview_item.xml
imagen = (ImageView) itemView.findViewById(R.id.imagen);
fecha = (TextView) itemView.findViewById(R.id.fecha);
quien = (TextView) itemView.findViewById(R.id.quien);
reporte = (TextView) itemView.findViewById(R.id.reporte);
// Capture position and set results to the TextViews
// Capture position and set results to the ImageView
// Passes flag images URL into ImageLoader.class
imageLoader.DisplayImage(resultp.get(MainActivity.IMAGEN), imagen);
fecha.setText(resultp.get(MainActivity.FECHA));
reporte.setText(resultp.get(MainActivity.REPORTE));
quien.setText(resultp.get(MainActivity.QUIEN));
// Capture ListView item click
/*
itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Get the position
resultp = data.get(position);
Intent intent = new Intent(context, SingleItemView.class);
// Pass all data rank
intent.putExtra("imagen", resultp.get(MainActivity.IMAGEN));
intent.putExtra("quien", resultp.get(MainActivity.QUIEN));
intent.putExtra("fecha", resultp.get(MainActivity.FECHA));
// Start SingleItemView Class
context.startActivity(intent);
}
});
*/
return itemView;
}
}

Take a look at the answer to this question for an explanation / example of how to maintain scroll position after adding items to a list: Retaining position in ListView after calling notifyDataSetChanged
Basically, you make a note of the position and scroll offset of the first visible item in the list before adding new data. Then afterwards, you restore the previous position and scroll offset.
However, because you're adding new items at the top of the list, the position returned by getFirstVisiblePosition() may refer to a different item after refreshing. The item that was at position 0 before refreshing may now be position 10. To fix that, you need to determine the number of new items returned by timeline.php and add it to index, like this:
mList.setSelectionFromTop(index + newItemCount, top);
You could probably determine which items are new by comparing the date field.
(By the way, if timeline.php only returns the most recent set of items, you could run into trouble if the user has scrolled to an older item which is no longer returned by timeline.php. After setting the new data, the old item will no longer be present, so you won't be able to scroll to it.
To fix that, you could keep the old ArrayList around and only add new items to it in doInBackground(). And call notifyDataSetChanged() in doInBackground(). That way, the adapter will still have access to older items.)

Related

Auto pagination fails on fast scroll listView

I am creating a ListView using Holder
when I scroll slowly everything works perfectly fine and Endless ListView works great but when I open the page and scroll fast to end of the List ListViewfail to scroll further without any error at Logcat.Here is my Adapter class getView method
#Override
public View getView(final int i, View view, ViewGroup viewGroup) {
View row=view;
Holder holder=null;
if(row==null){
LayoutInflater inflater= (LayoutInflater)mContext.getSystemService(mContext.LAYOUT_INFLATER_SERVICE);
row= inflater.inflate(R.layout.half_movie,viewGroup,false);
holder=new Holder(row);
row.setTag(holder);
}else{
holder= (Holder) row.getTag();
}
//here setting all holers
Picasso.with(mContext).load("https://image.tmdb.org/t/p/w185"+temp.getImageUrl()).into(holder.poster);
if(reachedEndOfList(i)) loadMoreData();
return row;
}
private boolean reachedEndOfList(int position) {
// can check if close or exactly at the end
return position == list.size() - 4;
}
private void loadMoreData() {
if(isNetworkAvailable()) {
new MyAdapter.AsyncTaskParseJson().execute(url);
}else{
Toast.makeText(mContext, "Sorry No internet Connection Found!", Toast.LENGTH_SHORT).show();
}
}
public class AsyncTaskParseJson extends AsyncTask<String,String ,void> {
JSONArray dataJsonArr = null;
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
progressDialog = ProgressDialog.show(mContext,
"Movie Pal!",
"Loading Movies List..");
}
#Override
protected void doInBackground(String... arg0) {
String yourJsonStringUrl = arg0[0];
yourJsonStringUrl=yourJsonStringUrl+"&page="+pageNmber;
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(yourJsonStringUrl.replace(" ","%20"));
System.out.println(json);
try {
JSONArray jsonArray = json.getJSONArray("results");
for (int i=0; i<jsonArray.length(); i++) {
Movie newMovie = new Movie();
//setting to class object
list.add(newMovie);
}
pageNmber++;} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
#Override
protected void onPostExecute() {
progressDialog.dismiss();
}
}
I don't know what i am missing here please help!
You need to call notifyDataSetChanged (or similar function like notifyDataSetInsert) when the new data is loaded so it knows that more data exists and it should allow more scrolling.
Also, you may not be adding enough padding (just 4 items) between the end of the list and when you fetch more data. That may result in stuttering scrolling- you'll reach the end and stop until more data is downloaded, then you can scroll again. As an example- I start fetching new data 10 items before the end, and I'm just hitting a local db, not a remote server.

Load more option in list view did not show previous list in android

i have parsed Json data from the server. On which im showing all the data in listview and i have Load more option below the ListView. Now when i click load more option, this application reload whole list and did not show previous list data. Please help me find out the solution. Here is footer view click listener :
lFooter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
page += 1;
new ParseIssues().execute();
listView.removeFooterView(v);
}
});
in above code ParseIssues class parse json values and displays all the data in ListView Here is code for onPostExecute of AsynkTask class :
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if(page < totalPage){
listView.addFooterView(v);
}
listAdapter = new ListAdapterForSearch(activity, mainList);
listView.setAdapter(listAdapter);
// get listview current position - used to maintain scroll position
int currentPosition = listView.getFirstVisiblePosition();
listView.setSelection(currentPosition);
}
Here is BaseAdapter class:
public class ListAdapterForSearch extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater = null;
public ListAdapterForSearch(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data = d;
inflater = LayoutInflater.from(activity);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View vi = convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.list_row_item, null);
}
TextView title = (TextView)vi.findViewById(R.id.title);
HashMap<String, String> hash = new HashMap<String, String>();
hash = data.get(position);
title.setText(hash.get("title"));
return vi;
}
}
The answer to your question lies with the variable "mainList", which the adapter uses. You need to add the new data to it, basically this list needs to contain all the data you want to show in your ListView.
You should set adapter on create, after that first add loaded data to mainlist(add new loaded data) & then after loading notify adapter like listadapter.notifydatachange()
Edit: Because every time you are creating adapter that's why you are facing this problem, instead after loading just notify your adapter..
Check in your code you may have clear your mainList.

Change text colour in individual list view based on variable

I followed this tutorial about parsing JSON. All is working as it should have have edited it to more my needs. I am getting information about 'servers' and one of the fields is 'status' (either UP or DOWN).
EDIT: forgot to post tutorial link http://www.androidhive.info/2012/01/android-json-parsing-tutorial/
It currently looks like this: http://puu.sh/8Ky0B.jpg
The above is what happens then the app is loaded. the on click is when a single item is clicked it starts a new activity and shows that information individually.
You can see the second server status is 'DOWN'. Based on this I want to change the text colour to RED for down and keep it green for up.
How can I do this when it goes through and adds each listview?
Here is the code which (currently) is basically the same as the tutorial:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serverList = new ArrayList<HashMap<String, String>>();
ListView lv = getListView();
// Listview on item click listener
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// getting values from selected ListItem
String name = ((TextView) view.findViewById(R.id.name))
.getText().toString();
String ip = ((TextView) view.findViewById(R.id.ipAddress))
.getText().toString();
String status = ((TextView) view.findViewById(R.id.serverStatus))
.getText().toString();
// Starting single server activity
Intent in = new Intent(getApplicationContext(),
SingleContactActivity.class);
in.putExtra(TAG_NAME, name);
in.putExtra(TAG_IP, ip);
in.putExtra(TAG_STATUS, status);
startActivity(in);
}
});
// Calling async task to get json
new GetContacts().execute();
}
/**
* Async task class to get json by making HTTP call
* */
private class GetContacts extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Showing progress dialog
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setMessage("Please wait...");
pDialog.setCancelable(false);
pDialog.show();
}
#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 {
JSONArray jArray = new JSONArray(jsonStr);
// looping through All Servers
for (int i = 0; i < jArray.length(); i++) {
JSONObject c = jArray.getJSONObject(i);
String id = c.getString(TAG_ID);
String name = c.getString(TAG_NAME);
String ip = c.getString(TAG_IP);
String status = c.getString(TAG_STATUS);
// tmp hashmap for single server
HashMap<String, String> contact = new HashMap<String, String>();
contact.put(TAG_ID, id);
contact.put(TAG_NAME, name);
contact.put(TAG_IP, ip);
contact.put(TAG_STATUS, status);
// adding server to server list
serverList.add(contact);
}
} 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);
// Dismiss the progress dialog
if (pDialog.isShowing())
pDialog.dismiss();
/**
* Updating parsed JSON data into ListView
* */
ListAdapter adapter = new SimpleAdapter(
MainActivity.this, serverList,
R.layout.list_item, new String[] { TAG_NAME, TAG_IP,
TAG_STATUS }, new int[] { R.id.name,
R.id.ipAddress, R.id.serverStatus });
setListAdapter(adapter);
}
}
You need to make a custom adapter and in the getView() you should check if the status of the server is down then set the color of corresponding textview to red else set it to green.
your getView() should like as following: (This is just a blueprint for your code)
getView(){
String serverstatus = server.getStatus();
// get status should be method in method in model class for server.
if(serverstatus.equals("DOWN")){
tv.setTextColor(Color.RED);
}else{
tv.setTextColor(Color.GREEN);
}
}
EDIT
Make a model class.
class Server{
String serverName, serverIp, serverStatus;
// getter and setter.
}
Make array adapter of Server type.
In Adapter's getView() inflate the row item, and set the details. For, red color font blueprint is already added.
In the definition of list Adapter, in the getView() method, find the textview and change the text color.
TextView tv = (TextView) listItem.findViewById(R.id.server_status);
tv.setTextColor(android.R.color.primary_text_dark);
Take the custom Adapter (a BaseAdapter) instead of simple adapter,
and there you perform your operation in getView() method.
You've done most of the hard work already :)
First create an object to store server details rather than a HashMap (which are slow and heavy) plus an object is more adaptable and fits your purpose better.
I've created a super fast example (not complete as to your details, but should be easy to expand).
package com.example.adaptertest;
public class HolderServer {
String serverName;
boolean isServerUp;
public HolderServer(String serverName, boolean isServerUp) {
this.serverName = serverName;
this.isServerUp = isServerUp;
}
public String getServerName() {
return serverName;
}
public void setServerName(String serverName) {
this.serverName = serverName;
}
public boolean isServerUp() {
return isServerUp;
}
public void setServerUp(boolean isServerUp) {
this.isServerUp = isServerUp;
}
}
Next you'll need to create a custom adapter. In your example you're actually using a simple adapter (ListAdapter adapter = new SimpleAdapter() which is a great first step, but we can improve on that a little by extending it. This will allow us to change what happens to each individual element in the listview. i.e. change the color etc.
Here's a quick example:
package com.example.adaptertest;
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class AdapterServers extends ArrayAdapter<HolderServer>{
ArrayList<HolderServer> mServers = new ArrayList<HolderServer>();
private LayoutInflater mInflater;
Context mContext;
public AdapterServers(Context context, int resource, ArrayList<HolderServer> servers) {
super(context, resource, servers);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mContext = context;
mServers = servers;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//Inflate view for each element in list.
convertView = mInflater.inflate(R.layout.server_list_item, null);
//Get details for current server
HolderServer server = mServers.get(position);
//Set server name
((TextView) convertView.findViewById(R.id.server_list_item_txt_servername)).setText(server.getServerName());
//Now we set the status text and color
TextView status = (TextView) convertView.findViewById(R.id.server_list_item_txt_serverstatus);
if(server.isServerUp){
status.setText(mContext.getResources().getString(R.string.up));
status.setTextColor(mContext.getResources().getColor(R.color.green));
}else{
status.setText(mContext.getResources().getString(R.string.down));
status.setTextColor(mContext.getResources().getColor(R.color.red));
}
return convertView;
}
}
Now back in your code, first in onCreate create a new list of objects:
ArrayList<HolderServer> mServerList = new ArrayList<HolderServer>();
then instead of this:
// tmp hashmap for single server
HashMap<String, String> contact = new HashMap<String, String>();
contact.put(TAG_ID, id);
contact.put(TAG_NAME, name);
contact.put(TAG_IP, ip);
contact.put(TAG_STATUS, status);
You'll create your new object & add it to the list. Obviously update it with your variables once your HolderServer object is updated:
HolderServer server = new HolderServer("Server1", true);
serverList.add(server);
Then apply that list to the adapter and apply the adapter to the listview:
AdapterServers adapter = new AdapterServers(this, 0, serverList);
((ListView) findViewById(R.id.fragment_main_listview)).setAdapter(adapter);
Good luck!

Navigate to different pages when a certain LISTVIEW is clicked

I have an android project that gets the values from a remote database. I'm using a listview in eclipse and loops whatever values that my JSON have. Here is my code:
Newsfeed.java
public class NewsFeed extends ListActivity {
// Progress Dialog
private ProgressDialog pDialog;
private static final String READ_COMMENTS_URL = "http://10.0.2.2/PMR_Drupal/newsfeed.php";
private static final String TAG_TITLE = "trans_name";
private static final String TAG_FOR_A = "sub_trans_name";
private static final String TAG_ACCESS_LEVEL = "ACCESS_LEVEL";
private JSONArray mComments = null;
//manages all of our comments in a list.
private ArrayList<HashMap<String, String>> mCommentList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newsfeed);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity_actions, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//loading the comments via AsyncTask
new LoadComments().execute();
}
public void addComment(View v)
{
Intent i = new Intent("com.pallet.pts.ADDNEWSFEED");
startActivity(i);
}
public void updateJSONdata() {
mCommentList = new ArrayList<HashMap<String, String>>();
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(READ_COMMENTS_URL);
try {
mComments = json.getJSONArray(TAG_POSTS);
for (int i = 0; i < mComments.length(); i++) {
JSONObject c = mComments.getJSONObject(i);
String trans_name = c.getString(TAG_TITLE);
String sub_trans_name = c.getString(TAG_FOR_A);
String ACCESS_LEVEL = c.getString(TAG_ACCESS_LEVEL);
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_TITLE, trans_name);
map.put(TAG_FOR_A, sub_trans_name);
map.put(TAG_ACCESS_LEVEL, ACCESS_LEVEL);
mCommentList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
private void updateList() {
ListAdapter adapter = new SimpleAdapter(this, mCommentList,
R.layout.single_post, new String[] { TAG_TITLE, TAG_FOR_A, TAG_ACCESS_LEVEL}, new int[] { R.id.title, R.id.forApproval, R.id.count});
setListAdapter(adapter);
ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent intent = new Intent("com.pallet.pts.NEWSFEED_CLICKED");
intent.putExtra("position", position);
startActivity(intent);
}
});
}
public class LoadComments extends AsyncTask<Void, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(NewsFeed.this);
pDialog.setMessage("Checking for Updates...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
#Override
protected Boolean doInBackground(Void... arg0) {
//we will develop this method in version 2
updateJSONdata();
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
pDialog.dismiss();
//we will develop this method in version 2
updateList();
}
}
}
Now my problem is, since the listview is being looped in, How do I create a listview screen with different content for each row?
Thank you in advance! :D
You need to make an activity which should be blue print for all the activity that will be invoked by ListView .You need to append some values to Intent that you'll be passed to the activity and based on this remaining component can be created dynamically .The way you are doing you will get stuck because the data are coming remote database which may vary time to time.But what I am saying to make a basic skeleton of Activity because most the component will remain same only some of the component may only change which you can add dynamically based on intent valuse
Hello based on the #Shakeeb Shaheen comment here I am trying to write a pseudo-code for you. At first create a xml layout and name it common_layout.xml which will use to show trans and subtrans name. Here is the code of this layout:
<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:id="#+id/tv_trans_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/tv_subtrans_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Create an activity for holding this layout.
Now from the NewsFeed activity you have to pass the trans name and subtrans name value when user click on the each list item. You can do this
Intent intent = new Intent(NewsFeed.this, CommonActivity.class);
intent.putExtra("TRANS_NAME", trans_name);
intent.putExtra("SUBTRANS_NAME", subtrans_name);
startActivity(intent);
And then you have to grab these value in your common activity class. This post also can help you how to pass value between two activity.

AsyncTask isn't working with BaseAdapter

I am building song list application. I want to display splash screen while loading data. For that use I set an AsyncTask combined with ViewSwitcher to switch xml layout beetween splash screen (just logo and circle progressbar) and main screen. The problem is when it comes to puting data in ListView, I am using BaseAdapter which is in separate class, and it throws error "The Constructor LazyAdapter(Home.LoadViewTask, ArrayList<HashMap<String,String>>) is undefined".
This is source of Home Class which has AsyncTask:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
mBtnNaslovnica = (Button) findViewById(R.id.mBtnNaslovnica);
mBtnNaslovnica.setSelected(true);
new LoadViewTask().execute();
}
//To use the AsyncTask, it must be subclassed
public class LoadViewTask extends AsyncTask<Void, Integer, Void>
{
//A TextView object and a ProgressBar object
private TextView tv_progress;
private ProgressBar pb_progressBar;
//Before running code in the separate thread
#Override
protected void onPreExecute()
{
//Initialize the ViewSwitcher object
viewSwitcher = new ViewSwitcher(Home.this);
/* Initialize the loading screen with data from the 'loadingscreen.xml' layout xml file.
* Add the initialized View to the viewSwitcher.*/
viewSwitcher.addView(ViewSwitcher.inflate(Home.this, R.layout.init, null));
//Set ViewSwitcher instance as the current View.
setContentView(viewSwitcher);
}
//The code to be executed in a background thread.
#Override
protected Void doInBackground(Void... params)
{
ArrayList<HashMap<String, String>> songsList = new ArrayList<HashMap<String, String>>();
XMLParser parser = new XMLParser();
String xml = parser.getXmlFromUrl(URL); // getting XML from URL
Document doc = parser.getDomElement(xml); // getting DOM element
NodeList nl = doc.getElementsByTagName(KEY_SONG);
// looping through all song nodes <song>
for (int i = 0; i < nl.getLength(); i++) {
// creating new HashMap
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) nl.item(i);
// adding each child node to HashMap key => value
map.put(KEY_ID, parser.getValue(e, KEY_ID));
map.put(KEY_TITLE, parser.getValue(e, KEY_TITLE));
map.put(KEY_ARTIST, parser.getValue(e, KEY_ARTIST));
map.put(KEY_DURATION, parser.getValue(e, KEY_DURATION));
map.put(KEY_THUMB_URL, parser.getValue(e, KEY_THUMB_URL));
// adding HashList to ArrayList
songsList.add(map);
}
list=(ListView)findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(this, songsList);
list.setAdapter(adapter);
// Click event for single list row
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
}
});
return null;
}
//After executing the code in the thread
#Override
protected void onPostExecute(Void result)
{
/* Initialize the application's main interface from the 'main.xml' layout xml file.
* Add the initialized View to the viewSwitcher.*/
viewSwitcher.addView(ViewSwitcher.inflate(Home.this, R.layout.main, null));
//Switch the Views
viewSwitcher.showNext();
}
}
//Override the default back key behavior
#Override
public void onBackPressed()
{
//Emulate the progressDialog.setCancelable(false) behavior
//If the first view is being shown
if(viewSwitcher.getDisplayedChild() == 0)
{
//Do nothing
return;
}
else
{
//Finishes the current Activity
super.onBackPressed();
}
}
And this is the source of LazyAdapter class:
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
public LazyAdapter(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data=d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(activity.getApplicationContext());
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.list_row, null);
TextView title = (TextView)vi.findViewById(R.id.title); // title
TextView artist = (TextView)vi.findViewById(R.id.artist); // artist name
TextView duration = (TextView)vi.findViewById(R.id.duration); // duration
ImageView thumb_image=(ImageView)vi.findViewById(R.id.list_image); // thumb image
HashMap<String, String> song = new HashMap<String, String>();
song = data.get(position);
// Setting all values in listview
title.setText(song.get(Home.KEY_TITLE));
artist.setText(song.get(Home.KEY_ARTIST));
duration.setText(song.get(Home.KEY_DURATION));
imageLoader.DisplayImage(song.get(Home.KEY_THUMB_URL), thumb_image);
return vi;
}
`
You cannot do any UI modification.. such as setting a label text, modifying list inside a AsyncTask.doInBackground.. because it is a separate thread...
list=(ListView)findViewById(R.id.list);
// Getting adapter by passing xml data ArrayList
adapter=new LazyAdapter(this, songsList);
list.setAdapter(adapter);
// Click event for single list row
list.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
}
});
you should put that part of the code before you call
new LoadViewTask().execute();
and inside the doInBackground()... as the last line..
put this line..
adapter.notifyDataSetChanged();
Your constructor in first parameter get Activity and you pass instance of LoadViewTask (this referrs to the current instance of LoadViewTask),
instead of this use:
adapter=new LazyAdapter(Home.this, songsList);
Where Home should be name of your activity
The problem is that, for whatever reason, you're requiring an Activity as the first parameter of your constructor. By passing this to the constructor of your adapater you're passing an object of type AsyncTask which is not activity and doesn't have a context. So you should pass an Activity as the an argument in the overridden constructor for LoadViewTask and then use it as the correct argument for your constructor.
Nonetheless be careful when binding a context to an AsyncTask since it may lead to unexpected behaviours (the Activity may not exist anymore when AsyncTask tries to update it). AsyncTask is a very dangerous class to use since it has many synchronization-related flaws.
I hope this might be help,
onPostExecute include (Inside AsyncTask)
ExampleAdapter sectionedAdapter = new EfficientAdapter(ClassInfoThread.this,getBaseContext());
listView.setAdapter(sectionedAdapter);
and in your adapter class add this constructor
public ExampleAdapter(ExampleThread exampleThread,Context context) {
// TODO Auto-generated constructor stub`enter code here`
mInflater = LayoutInflater.from(context);
}

Categories

Resources