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.
Related
I have made an App that lists some links that I parse from a Html page using jsoup.
The list shows the title of the link and an arrow that should have the link. But when I select any item of them I only get the last link.
Here's my Controller:
public class Controller extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setTitle("");
toolbar.setSubtitle("");
linkList = new ArrayList<>();
http = this.getString(R.string.http);
url = this.getString(R.string.path1);
lv = (ListView) findViewById(R.id.list);
new GetLinks().execute();
}
private class GetLinks extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
Document doc;
Elements links;
try {
doc = Jsoup.connect(url).get();
links = doc.getElementsByClass("processlink");
linkList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
ListAdapter adapter = new SimpleAdapter(
Controller.this, linkList,
R.layout.list_item, new String[]{TITLE, LINK},
new int[]{R.id.title});
//Log.i(TAG, "onPostExecute: "+ getString(R.id.link));
lv.setAdapter(adapter);
}
}
private ArrayList<HashMap<String, String>> ParseHTML(Elements links) throws IOException {
if (links != null) {
ArrayList<HashMap<String, String>> linkList = new ArrayList<>();
for (Element link : links) {
final String linkhref = http + link.select("a").attr("href");
String linktext = link.text();
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(linkhref));
startActivity(browserIntent);
}
});
HashMap<String, String> student = new HashMap<>();
student.put(TITLE, linktext);
student.put(LINK, linkhref);
linkList.add(student);
}
return linkList;
}
else {
Log.e(TAG, "Couldn't get html from server.");
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),
"Couldn't get html from server. Check LogCat for possible errors!",
Toast.LENGTH_LONG)
.show();
}
});
}
return null;
}
}
Here's the main_view.xml
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/textView2" />
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:textSize="20sp"
android:textStyle="bold"
android:textColor="#color/colorPrimary"
android:text="#string/app_name"
android:gravity="center"
android:id="#+id/textView2"
android:layout_below="#+id/toolbar"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
And last but not least, list_item.xml
<TextView
android:id="#+id/title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:paddingBottom="2dip"
android:paddingTop="6dip"
android:textColor="#color/colorPrimaryDark"
android:textSize="16sp"
android:textStyle="bold"
android:text="Title"
android:layout_toLeftOf="#+id/link"
android:layout_toStartOf="#+id/link" />
<ImageView
android:id="#+id/link"
android:layout_width="35dp"
android:layout_height="wrap_content"
android:gravity="end"
android:src="#drawable/arrow"
android:autoLink="web"
android:padding="1dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignBottom="#+id/title" />
If I log the title and the link, I get all the links and the title but, not in the app.
So my question is how I get the links to work as a list and not just the last link?
The linkList is already declared in global I guess. So you're fine to go with this.
I would love to suggest you some edits in your code anyway. You might initialize your ListView fully in your onCreate function. Declare your Adapter as a global variable.
You might also consider setting the onClickListener of your ListView items here inside onCreate function too.
// Declare the adapter globally.
private ListAdapter adapter;
// Declare the linkList as an ArrayList of Student object
private ArrayList<Student> linkList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
// ... Setup toolbar
// ... Setup http and url string
// Setup ListView
linkList = new ArrayList<Student>();
lv = (ListView) findViewById(R.id.list);
// Initialize the adapter
adapter = new SimpleAdapter(
Controller.this, linkList,
R.layout.list_item, new String[]{TITLE, LINK},
new int[]{R.id.title});
// Set the adapter here
lv.setAdapter(adapter);
// Setup the ListView item click
setupListViewItemClick();
// Now execute the AsyncTask
new GetLinks().execute();
}
Here's the setupListViewItemClick function which might look like this.
private void setupListViewItemClick() {
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
// Get the student by the position of the adapter.
Student student = linkList.get(position);
String linkhref = student.getLink();
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(linkhref));
startActivity(browserIntent);
}
});
}
Hence, you need to modify your ParseHTML function.
private ArrayList<Student> ParseHTML(Elements links) throws IOException {
if (links != null) {
// Removed the initialization of HashMap
for (Element link : links) {
String linktext = link.text();
// ** Removed the onClickListener **
Student student = new Student();
student.setTitle(linktext);
student.setLink(link);
// Just add the items here
linkList.add(student);
}
return linkList;
} else {
// The else part goes here
}
return null;
}
Finally, in your AsyncTask you need to modify your onPostExecute a bit like this to notify your linkList has been populated with data so the adapter refreshes it.
private class GetLinks extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
Document doc;
Elements links;
try {
doc = Jsoup.connect(url).get();
links = doc.getElementsByClass("processlink");
linkList = ParseHTML(links);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
// Just call the notifyDatasetChanged to notify the adapter
// to reload the data from the linkList
adapter.notifyDatasetChanged();
}
}
Update
#PanveetSingh stated, student is not an object but a HashMap. Sorry I missed that part earlier. You might consider creating a class called Student like this.
public class Student {
public String title;
public String linkhref;
public Student() {}
public void setTitle(String title) {
this.title = title;
}
public void setLink(Element link) {
this.linkhref = "http://" + link.select("a").attr("href");
}
public String getTitle() {
return this.title;
}
public String getLink() {
return this.linkhref;
}
}
Your ParseHTML function and the other functions are modified accordingly.
In your ParseHTML(Elements links) method
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
String theRealLink = linkList.get(position);
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
Uri.parse(theRealLink));
startActivity(browserIntent);
}
});
The linkList also needs to be final.
(Also remember that in Java, methodNamesShouldBeInThisFormat())
My items in ListView are generated using PHP and stored in a MySQL database. How can I add an event handler function tied to the buttons? The process that I need is like this: when you click the button it will get the item and save it to other table, as well as get the current datetime also.
public class ViewBusFiveStudent extends AppCompatActivity implements ListView.OnItemClickListener {
private ListView listView;
private Button btntime;
private String JSON_STRING;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_busfour);
listView = (ListView) findViewById(R.id.listView);
listView.setOnItemClickListener(this);
getJSON();
}
private void showStudents(){
JSONObject jsonObject = null;
ArrayList<HashMap<String,String>> list = new ArrayList<HashMap<String, String>>();
try {
jsonObject = new JSONObject(JSON_STRING);
JSONArray result = jsonObject.getJSONArray(Config.TAG_JSON_ARRAY);
for(int i = 0; i<result.length(); i++){
JSONObject jo = result.getJSONObject(i);
String id = jo.getString(Config.TAG_ID);
String name = jo.getString(Config.TAG_NAME);
HashMap<String,String> student = new HashMap<>();
student.put(Config.TAG_ID,id);
student.put(Config.TAG_NAME,name);
list.add(student);
}
} catch (JSONException e) {
e.printStackTrace();
}
ListAdapter adapter = new SimpleAdapter(
ViewBusFiveStudent.this, list, R.layout.list_items,
new String[]{Config.TAG_ID,Config.TAG_NAME},
new int[]{R.id.id, R.id.name});
listView.setAdapter(adapter);
}
private void getJSON(){
class GetJSON extends AsyncTask<Void,Void,String>{
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(ViewBusFiveStudent.this,"Fetching Data","Wait...",false,false);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
JSON_STRING = s;
showStudents();
}
#Override
protected String doInBackground(Void... params) {
RequestHandler rh = new RequestHandler();
String s = rh.sendGetRequest(Config.URL_GET_BUS_FOUR);
return s;
}
}
GetJSON gj = new GetJSON();
gj.execute();
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(this, ViewBusFive.class);
HashMap<String,String> map =(HashMap)parent.getItemAtPosition(position);
String studId = map.get(Config.TAG_ID).toString();
intent.putExtra(Config.STUD_ID,studId);
startActivity(intent);
}
}
Here's my list_view:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="#+id/id"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/id"/>
<CheckBox
android:id="#+id/checkBoxPres"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:text=""
android:layout_alignBaseline="#+id/btnTime"
android:layout_alignBottom="#+id/btnTime"
android:layout_toLeftOf="#+id/btnTime"
android:layout_toStartOf="#+id/btnTime" />
<Button
android:text="TimeStamp"
android:layout_width="105dp"
android:layout_alignParentRight="true"
android:layout_height="wrap_content"
android:id="#+id/btnTime" />
</RelativeLayout>
I just want to know how to define the function called when the button is clicked and where can i place it.
I have change the code for onitemclick, i can click the button in the listview but only one button is working/clickable.
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final TextView name1 = (TextView) findViewById(R.id.name);
btnTime = (Button) findViewById(R.id.btnTime);
btnTime.setTag(position);
btnTime.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
BusArrived();
}
public void BusArrived() {
final String name = name1.getText().toString().trim();
class SendStudent extends AsyncTask<Void, Void, String> {
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(ViewBusFiveStudent.this, "Saving Dismissal Time...", "Wait...", false, false);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
Toast.makeText(ViewBusFiveStudent.this, s, Toast.LENGTH_LONG).show();
}
#Override
protected String doInBackground(Void... v) {
HashMap<String, String> params = new HashMap<>();
params.put(Config.KEY_STUD_NAME, name);
RequestHandler rh = new RequestHandler();
String res = rh.sendPostRequest(Config.URL_SAVING_TO_BUS_FIVE_TIME, params);
return res;
}
}
SendStudent ae = new SendStudent();
ae.execute();
}
});
}
Please Correct my mistake here. Thanks!
Normally you set click listeners on subviews in the row layout when you bind data to the row. This happens inside the adapter. Since you are using an adapter provided by the framework, it doesn't have logic to add click listeners to buttons in your row, it only knows how to do simple bindings (e.g. strings into a TextView, etc). You will have to subclass SimpleAdapter (or something else, like BaseAdapter) and add the necessary logic yourself.
While you're at it, I suggest you switch to using RecyclerView instead of ListView. This means using RecyclerView.Adapter instead of the one you are using now, which will force you to implement the data binding logic anyway so you can add click listeners to subviews of your row layout. Also, ListView has a lot of quirks and idiosyncrasies, including weird interactions when rows have subviews that are focusable (like a clickable Button). RecyclerView will be much better for you in that regard.
Hi in my application I am parse the json url and displaying the image and text Now I am going to adding the button. if i click the button i want to move to another activity.Now My problem is if i click the button nothing happened .can any one please help me.
ListViewAdapter class:
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>();
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 title;
ImageView thumb_url;
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
title = (TextView) itemView.findViewById(R.id.rank);
// Locate the ImageView in listview_item.xml
thumb_url = (ImageView) itemView.findViewById(R.id.flag);
// Capture position and set results to the TextViews
title.setText(resultp.get(MainActivity.TITLE));
// Capture position and set results to the ImageView
// Passes flag images URL into ImageLoader.class
imageLoader.DisplayImage(resultp.get(MainActivity.THUMB_URL), thumb_url);
// Capture ListView item click
Button Add = (Button) itemView.findViewById(R.id.add);
Add.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("title", resultp.get(MainActivity.TITLE));
// Pass all data country
/*intent.putExtra("country", resultp.get(MainActivity.COUNTRY));
// Pass all data population
intent.putExtra("population",resultp.get(MainActivity.POPULATION));
*/// Pass all data flag
intent.putExtra("thumb_url", resultp.get(MainActivity.THUMB_URL));
// Start SingleItemView Class
context.startActivity(intent);
Intent in = new Intent(getApplicationContext(), MainActivity.class);
startActivity(in);
}
private void startActivity(Intent in) {
// TODO Auto-generated method stub
}
private Context getApplicationContext() {
// TODO Auto-generated method stub
return context;
}
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
return itemView;
}
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
}
listview_item.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="fill_parent" >
<ImageView
android:id="#+id/flag"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_centerVertical="true"
android:layout_margin="5dp"
android:background="#444"
android:padding="3dp" />
<TextView
android:id="#+id/rank"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dip"
android:layout_toRightOf="#+id/flag"
android:maxLines="1"
android:textSize="15dip"
android:textStyle="bold" />
<!-- <TextView
android:id="#+id/ranklabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="#+id/rank"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
-->
<!-- <ImageView
android:id="#+id/flag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="#000000"
android:layout_toRightOf="#+id/flag"
android:padding="1dp" />
-->
<Button
android:id="#+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/rank"
android:text="Add" />
</RelativeLayout>
MainActivity class:
public class MainActivity extends Activity {
// Declare Variables
JSONObject jsonobject;
JSONArray jsonarray;
ListView listview;
ListViewAdapter adapter;
ProgressDialog mProgressDialog;
ArrayList<HashMap<String, String>> arraylist;
static String TITLE = "title";
/*static String COUNTRY = "country";
static String POPULATION = "population";*/
static String THUMB_URL = "thumb_url";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the view from listview_main.xml
setContentView(R.layout.listview_main);
// Execute DownloadJSON AsyncTask
new DownloadJSON().execute();
}
// DownloadJSON AsyncTask
private 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("Loading...");
// Set progressdialog message
mProgressDialog.setMessage("Loading...");
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 = JSONfunction
.getJSONfromURL("http://indianpoliticalleadersmap.com/android/DemoSchool/json/json_item.php");
try {
// Locate the array name in JSON
jsonarray = jsonobject.getJSONArray("veg_food");
for (int i = 0; i < jsonarray.length(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
jsonobject = jsonarray.getJSONObject(i);
// Retrive JSON Objects
map.put("title", jsonobject.getString("title"));
/*map.put("country", jsonobject.getString("country"));
map.put("population", jsonobject.getString("population"));*/
map.put("thumb_url", jsonobject.getString("thumb_url"));
// 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);
// Close the progressdialog
mProgressDialog.dismiss();
}
}
}
Store the hashMap in the view tag.
Button Add = (Button) itemView.findViewById(R.id.add);
Add.setTag(resultp);
Then access it inside onClick() like this
instead of trying to access it by position which may not refer to the current view, access it by its tag. In your code, replace the line
resultp = data.get(position);
with
resultp = (HashMap<String, String>) view.getTag();
EDIT: After adding resultp = data.get(position); as shown above
Replace your onClick() with the following
#Override
public void onClick(View arg0) {
resultp = (HashMap<String, String>) view.getTag();
Intent intent = new Intent(context, SingleItemView.class);
intent.putExtra("title", resultp.get(MainActivity.TITLE));
intent.putExtra("population",resultp.get(MainActivity.POPULATION));
intent.putExtra("thumb_url", resultp.get(MainActivity.THUMB_URL));
context.startActivity(intent);
}
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.)
I have serious problems with my ListActivity. When I open it and start scrolling, the app freezes for some seconds and after that it can be scrolled smoothly. I don't get an "application not responding" error. I made a *.hprof heap dump and put it into MAT. Here you can see my leaks:
Seems like something is fishy. Maybe I'm not using the cursor in the right way.
Here you can take a look at my code:
public class ListViewActivity extends ListActivity implements OnClickListener {
// Resources
static String like;
// Cursor
private SimpleCursorAdapter adapter;
private Cursor cursor;
String[] showColumns;
int[] showViews;
// Database
private DBAccess dbAccess;
#Override
public void onCreate(Bundle savedInstanceState) {
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
ListViewActivity.like = "";
Intent intent = getIntent(); // gets the previously created intent
ListViewActivity.like = intent.getStringExtra("like");
new DatabaseTask().execute(null, null, null);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor item = (Cursor) getListAdapter().getItem(position);
Intent intent = new Intent(ListViewActivity.this, ListClickActivity.class);
intent.putExtra("id", item.getString(0));
startActivity(intent);
}
private class DatabaseTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Log.v("doInBackground", "started!");
dbAccess = new DBAccess(ListViewActivity.this, 1, "FishingMatey.db");
dbAccess.initDownloadedDatabase();
cursor = dbAccess
.createBewirtschafterListViewCursor(ListViewActivity.like);
showColumns = new String[] { "gewName", "reviergrenzen" };
showViews = new int[] { R.id.datensatz_gewName,
R.id.datensatz_reviergrenzen };
Log.v("doInBackground", "finished!");
return null;
}
protected void onPostExecute(Void params) {
adapter = new SimpleCursorAdapter(ListViewActivity.this,
R.layout.datensatz, cursor, showColumns, showViews);
setListAdapter(adapter);
dbAccess.closeDatabase();
Log.v("onPostExecute", "finished!");
}
}
}
EDIT1:
The issue doesn't come from the database because I have the same leak with the following code:
public class ListViewActivity extends ListActivity {
// Activity
public static Activity forFinish;
// Resources
static String like;
// Cursor
private SimpleAdapter adapter;
String[] showColumns;
int[] showViews;
#Override
public void onCreate(Bundle savedInstanceState) {
// Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_listview);
forFinish = this;
ListViewActivity.like = "";
Intent intent = getIntent(); // gets the previously created intent
ListViewActivity.like = intent.getStringExtra("like");
// create the grid item mapping
showColumns = new String[] { "gewName", "reviergrenzen" };
showViews = new int[] { R.id.datensatz_gewName,
R.id.datensatz_reviergrenzen };
// prepare the list of all records
List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < 20; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("gewName", "See" + i);
map.put("reviergrenzen", "Revier" + i);
fillMaps.add(map);
}
// fill in the grid_item layout
SimpleAdapter adapter = new SimpleAdapter(this, fillMaps,
R.layout.datensatz, showColumns, showViews);
setListAdapter(adapter);
}
}
Would be awesome if someone can find the memory leak.
Greetings Mike!
If you are using images in your list items then move the image loading to a background task. You could have a look at smoothie, an asynchronous loading list that can be used with Android-BitmapCache for better performance.