Before this post I have not found a post for my issue to be helpful for me.
First, I'm building a very simple android application that should connect to database (MySQL) to load foods data (food name) into ListView with count of food listed.
DB : db_food_resto
Table :
#id_row : int autoincrement primary key.
food_name : varchar 255 not null
food_country : varchar 255 not null //till now i don't need this column maybe in the future this way i added this.
I'm using eclipse with Genymontion emulator all things are great with no error compiler no exception thrown and work fine on emulator when I test it on cell phone the list of food not loaded however its loading on tablet!
I'm using asynctask to get the data I don't know why its not working on cell phone and working on tablet.
I have beat my head on this problem for days.
This is my code with some modifications to let it a little bit shorter.
public class HistoryActivity extends Activity
{
static ArrayList arr = new ArrayList<>(); // Info is a class contain a food name attribute and one constructor with one argument foodname
ListView historylistfood;
LayoutInflater mInflater;
TextView foodcount;
#TargetApi(Build.VERSION_CODES.HONEYCOMB)
#SuppressLint("NewApi")
#Override
protected void onCreate(Bundle savedInstanceState) {
...
...
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
new Tasklist().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,"load_all");
}
else {
new Tasklist().execute("load_all");
}
}
class Tasklist extends AsyncTask<String, String, String>
{
#Override
protected String doInBackground(String... params)
{
StringBuffer sb = null;
try
{
String link="mydomain.com/file.php?type="+params[0];
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(link);
HttpResponse response = httpclient.execute(httppost);
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null)
{
sb.append(line);
//sb is a list of foods gotten from PHP file seperated with |
//something like that: food name 1|food name 2|food name 3|ABC|
//then i break the loop
break;
}
in.close();
getlistfood(sb.toString());
} catch(Exception e){
e.printStackTrace() ;
}
return null;
}
#Override
protected void onPostExecute(String result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
if(arr.size()>0)
{
ArrayAdapter<Info> adapter = new HArrayAdapter();
historylistfood.setAdapter(adapter);
Toast.makeText(getApplicationContext(), "On post exectue", Toast.LENGTH_LONG).show();
foodcount.setVisibility(View.VISIBLE);
foodcount.setText(""+arr.size());
foodcount.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.movecount));
}
else
{
Toast.makeText(getApplicationContext(), "Intenet issue.", Toast.LENGTH_LONG).show(); // this is what cell phones showed
}
}
}
public void getlistfood(String st) {
arr = new ArrayList<>();
String[] spl = st.toString().split("|");
for(int i=0;i<spl.length;i++)
{ Info i = new Info(spl[i]);
arr.add(i);
}
}
public class HArrayAdapter extends ArrayAdapter<Info>
{
public HArrayAdapter() {
super(HistoryActivity.this,R.layout.activity_item,arr);
}
public View getView(int position, View convertView, ViewGroup parent)
{
View itemv = convertView;
Info poo = arr.get(position);
if(itemv== null)
{
itemv = mInflater.inflate(R.layout.activity_item, parent,false);
}
TextView foodname = (TextView)itemv.findViewById(R.id.food);
foodname.setText(poo.getFoodname());
return itemv;
}
}
}
Related
I am seeking help so that I may get an ArrayList<String> in an alternate class. As you can see in the following code I have inner and outer classes. Both work as expected and I am both able to insert values and fetch details from my online database using php scripts (I have commented out these details for code clarity as it was taking up a lot of space).
public class ServerRequests {
ProgressDialog progressDialog;
public static final int CONNECTION_TIMEOUT = 15000;
public static final String SERVER_ADDRESS = "// my url domain";
public ArrayList<String> list1 = new ArrayList<>();
public ServerRequests(Context context)
{
progressDialog = new ProgressDialog(context);
progressDialog.setCancelable(false);
progressDialog.setTitle("Processing");
progressDialog.setMessage("Please wait..");
}
public void storeDataInBackground(MultiChallenge multiChallenge)
{
progressDialog.show();
new StoreDataAsyncTask(multiChallenge).execute();
}
public class StoreDataAsyncTask extends AsyncTask<Void , Void , Void>
{
MultiChallenge multiChallenge;
public StoreDataAsyncTask(MultiChallenge multiChallenge)
{
this.multiChallenge = multiChallenge;
}
#Override
protected Void doInBackground(Void... voids) {
// where I insert values...
#Override
protected void onPostExecute(Void aVoid) {
progressDialog.dismiss();
super.onPostExecute(aVoid);
Log.d("ServerRequests", "Post execute");
}
}
public ArrayList<String> fetchDataInBackground() {
progressDialog.show();
new FetchDataAsyncTask().execute();
return list1;
}
public class FetchDataAsyncTask extends AsyncTask<Void, Void, ArrayList<String>>
{
public FetchDataAsyncTask()
{
}
String text = "";
#Override
protected ArrayList<String> doInBackground(Void... params) {
InputStream is1;
HttpParams httpRequestParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpRequestParams, CONNECTION_TIMEOUT);
HttpConnectionParams.setSoTimeout(httpRequestParams, CONNECTION_TIMEOUT);
HttpClient client = new DefaultHttpClient(httpRequestParams);
HttpPost post = new HttpPost(// my url domain+ "// php script");
try {
HttpResponse httpResponse = client.execute(post);
is1 = httpResponse.getEntity().getContent();
BufferedReader reader;
reader = new BufferedReader(new InputStreamReader(is1, "iso-8859-1"), 8);
String line = null;
while ((line = reader.readLine()) != null) {
text += line + "\n";
}
is1.close();
JSONArray data = new JSONArray(text);
for (int i = 0; i < data.length(); i++) {
Log.d("GetNames", data.getString(i));
JSONObject jsonData = data.getJSONObject(i);
list1.add( // I successfully add details to list1 here, I have commented it out for code clarity);
}
for (int iterate = 0; iterate < list1.size(); iterate++) {
Log.d("list1", list1.get(iterate));
}
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
// catch (JSONException e) {e.printStackTrace();}
return list1;
}
#Override
protected void onPostExecute(ArrayList<String> myList) {
progressDialog.dismiss();
super.onPostExecute(myList);
}
}
}
Now that I successfully add to the list1 (I can tell values are added to it because of the for loop with the int iterate), I now need to send it to another class whereby I will put items in a listview. This is my code in the class in which I want to display the details of the ArrayList I get from ServerRequests:
ServerRequests serverRequests = new ServerRequests(DisplayInfo.this);
ArrayList<String> myList = new ArrayList<>();
myList = serverRequests.fetchDataInBackground();
for (int iterate = 0; iterate < myList.size(); iterate++) {
Log.d("Display", myList.get(iterate));
However the above for loop is never called, indicating that myList is never given the details that list1 manages to get in the doInBackground method of class FetchDataAsync.
Please note I did spend a number of hours attempting a variety of my own ideas and answers derived from SO before asking this question. Thank you all in advance of your help.
In the onPostExecute method call a function in the calling class
#Override
protected void onPostExecute(ArrayList<String> myList) {
progressDialog.dismiss();
super.onPostExecute(myList);
MainActivity.sendStrings(myList);
}
In the calling function implement a method:
public static void sendStrings(ArrayList<String> strings)
{
//Add for loop here
}
Alternatively you can also use interfaces. Call the interface in onPostExecute and implement the interface in the calling class
I need to delete a list item from listview on clicking a delete button in android eclipse. The list values are populated from mysql database(JSON), so on deleting, I need to delete the same from database also.
Here is my main Activity; I need to delete a listitem from a listview on clicking a delete button on each item in the listview:
public class MainActivity extends Activity implements AsyncResponse2 {
private ProgressDialog dialog;
ListView l1;
//for getting count
TextView count;
private static final String TAG_COUNT = "cnt";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //to hide title bar
setContentView(R.layout.activity_main);
l1=(ListView)findViewById(R.id.listView1);
/** Reference to the delete button of the layout main.xml */
Button btnDel = (Button) findViewById(R.id.deleteid);
initView();
//str for getting count
count=(TextView)findViewById(R.id.countid);
//to display count while loading(so outside buttonclick)
String key1 = "saasvaap123";
String signupid1 = "8";
String url2 = "http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?";
//http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?key=saasvaap123&signup_id=8
//put the below lines outside button onclick since we load the values into edittext when opening the app
CustomHttpClient2 task2 = new CustomHttpClient2();
task2.execute(url2,key1,signupid1);
task2.delegate = MainActivity.this;
//end
}
//str getting count
//str customhttp2
private class CustomHttpClient2 extends AsyncTask<String, String, String>{
public AsyncResponse2 delegate=null;
private String msg;
#Override
protected void onPostExecute(String result2) {
// TODO Auto-generated method stub
super.onPostExecute(result2);
delegate.processFinish2(result2);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
if(params == null) return null;
// get url from params
String url2 = params[0];
String key1 = params[1];
String signupid1 = params[2];
ArrayList<NameValuePair> postParameters;
postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("key",key1));
postParameters.add(new BasicNameValuePair("signup_id",signupid1));
try {
// create http connection
HttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url2);
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// connect
HttpResponse response = client.execute(httppost);
// get response
HttpEntity entity = response.getEntity();
if(entity != null){
return EntityUtils.toString(entity);
}
else{
return "No string.";
}
}
catch(Exception e){
return "Network problem";
}
}
}
public void processFinish2 (String output2){
Toast.makeText(MainActivity.this,output2, Toast.LENGTH_SHORT).show();
try{
//str
JSONObject jsonResponse = new JSONObject(output2);
JSONArray aJson = jsonResponse.getJSONArray("gen_off");
// create apps list
for(int i=0; i<aJson.length(); i++) {
JSONObject json = aJson.getJSONObject(i);
//end
//str
String strCount = json.getString(TAG_COUNT);
count.setText(strCount);//setting name to original name text
//end
}
}catch (JSONException e) {
Toast.makeText(MainActivity.this,"Exception caught!", Toast.LENGTH_SHORT).show();
}
}
//end getting count
private void initView() {
// show progress dialog
// dialog = ProgressDialog.show(this, "", "Loading...");
String key="saasvaap123";
String signup_id="8";
String url = "http://gooffers.in/omowebservices/index.php/webservice/Public_User/saved_offers_list?";
FetchDataTask task = new FetchDataTask();
task.execute(url,key,signup_id);
}
public class FetchDataTask extends AsyncTask<String, Void, String>{
// private final FetchDataListener listener;
private String msg;
#Override
protected String doInBackground(String... params) {
if(params == null) return null;
// get url from params
String url = params[0];
String key1 = params[1];
String signupid1 = params[2];
ArrayList<NameValuePair> postParameters;
postParameters = new ArrayList<NameValuePair>();
postParameters.add(new BasicNameValuePair("key",key1));
postParameters.add(new BasicNameValuePair("signup_id",signupid1));
//str
try {
// create http connection
HttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
httppost.setEntity(new UrlEncodedFormEntity(postParameters));
// connect
HttpResponse response = client.execute(httppost);
// get response
HttpEntity entity = response.getEntity();
if(entity != null){
return EntityUtils.toString(entity);
}
else{
return "No string.";
}
}
catch(Exception e){
return "Network problem";
}
}
//end
//
#Override
protected void onPostExecute(String sJson) {
try {
JSONObject jsonResponse = new JSONObject(sJson);
JSONArray aJson = jsonResponse.getJSONArray("gen_off");
Toast.makeText(MainActivity.this, aJson.toString(),Toast.LENGTH_SHORT).show();
// create apps list
List<SavedOffers> apps = new ArrayList<SavedOffers>();
for(int i=0; i<aJson.length(); i++) {
JSONObject json = aJson.getJSONObject(i);
SavedOffers app = new SavedOffers();
app.setTitle(json.getString("title"));
app.setOriginalRate(json.getString("price"));
app.setOfferRate(json.getString("off_price"));
app.setPercentage(json.getString("percent"));
app.setSavings(json.getString("savings"));
app.setUrl(json.getString("image"));
// add the app to apps list
apps.add(app);
}
SavedOffersAdapter adapter = new SavedOffersAdapter(MainActivity.this, apps);
// set the adapter to list
l1.setAdapter(adapter);
//for delete
// adapter.notifyDataSetChanged();
/** Defining a click event listener for the button "Delete" */
Button btnDel = (Button) findViewById(R.id.deleteid);
OnClickListener listenerDel = new OnClickListener() {
#Override
public void onClick(View v) {
/** Getting the checked items from the listview */
SparseBooleanArray checkedItemPositions = l1.getCheckedItemPositions();
int itemCount = l1.getCount();
for(int i=itemCount-1; i >= 0; i--){
if(checkedItemPositions.get(i)){
adapter.remove(l1.get(i));
}
}
checkedItemPositions.clear();
adapter.notifyDataSetChanged();
}
};
/** Setting the event listener for the delete button */
btnDel.setOnClickListener(listenerDel);
/** Setting the adapter to the ListView */
l1.setAdapter(adapter); //end delete
//notify the activity that fetch data has been complete
// if(listener != null) listener.onFetchComplete(apps);
} catch (JSONException e) {
// msg = "Invalid response";
// if(listener != null) listener.onFetchFailure(msg);
// return;
}
}
/**
* This function will convert response stream into json string
* #param is respons string
* #return json string
* #throws IOException
*/
public String streamToString(final InputStream is) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
}
catch (IOException e) {
throw e;
}
finally {
try {
is.close();
}
catch (IOException e) {
throw e;
}
}
return sb.toString();
}
}
}
// this is my adapter class , I think change is only needed in main activity
// , I need to delete a specific list item from listview on clicking the delete button
public class SavedOffersAdapter extends ArrayAdapter<SavedOffers>{
private List<SavedOffers> items;
Bitmap bitmap;
ImageView image;
public SavedOffersAdapter(Context context, List<SavedOffers> items) {
super(context, R.layout.app_custom_list, items);
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
private class ViewHolder {
//TextView laptopTxt;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// ViewHolder holder;//added
View v = convertView;
if(v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.app_custom_list, null);
}
SavedOffers app = items.get(position);
if(app != null) {
TextView productName = (TextView)v.findViewById(R.id.nameid);
TextView originalRate = (TextView)v.findViewById(R.id.originalid);
originalRate.setPaintFlags(originalRate.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
TextView offerRate = (TextView)v.findViewById(R.id.offerid);
TextView percentage = (TextView)v.findViewById(R.id.discountid);
TextView savings = (TextView)v.findViewById(R.id.savingsid);
image =(ImageView)v.findViewById(R.id.prctimgid);
if(productName != null) productName.setText(app.getTitle());
if(originalRate != null) originalRate.setText(app.getOriginalRate());
if(offerRate != null) offerRate.setText(app. getOfferRate());
if(percentage != null) percentage.setText(app. getPercentage());
if(savings != null) savings.setText(app. getSavings());
if(image!=null){
new DownloadImageTask(image).execute(app.getUrl());
}
}
return v;
}
In your listviews adapter's getView method you link to the button on the layout your inflating and just attach a setOnClickListener... to the button and have it remove that item from your list or array that your adapter uses and then notifyDataHasChanged.
Delete that item from items in that position.
So 1. you want to delete the item from the ListView
2. you want to delete the item from the SQL DB.
The first one is very easy, but you kind of need to know the underlining adapter and how it serves data to your ListView. When you instantiate a BaseAdapter for the ListView you pass in a List or an array. This array will be the data your BaseAdapter serves to your ListView, each view in the listview will be showing an element from the array (done in getView()). If you dynamically delete one of those items, then adjust your array (or just use a List and it's .remove(), and finally notifyDataSetChanged(); your BaseAdapter will refresh your list without that View (or rather that View will be replaced with the new one). So for instance below I pass in a List<WeatherLocation> (WeatherLocation is a containing class that has weather stuff for a particular area (city, zipcode, degree"Biddeford", 04005, 72) to my BaseAdapter.
// Instantiate ListView
ListView lvLocations = (ListView) findViewById(R.id.lvLocations);
// Instantiate our BaseAdapter (pass in the List<WeatherLocation>)
WeatherLocationAdapter mWeatherLocationAdapter = new WeatherLocationAdapter(savedList, this, R.layout.view_weather_location);
lvLocations.setAdapter(mWeatherLocationAdapter);
This is an example of a regular ListView setting an Adapter to a custom BaseAdapter.
The BaseAdapter is so simple, that really the only method you care about (majorly) is the getView() method.
R.layout.view_weather_location is just a `LinearLayout` I made, it has 3 TextViews in it that I tie (show) my data with, by attaching data to those TextViews in the `getView()` method of the `BaseAdapter`. You would put a `Button there and tie it to what you want (to delete the data item)`.
public class WeatherLocationAdapter extends BaseAdapter{
private List <WeatherLocation> mLocations;
private Context mContext;
private int rowForLocationToInflate;
private LayoutInflater inflater;
public WeatherLocationAdapter(List<WeatherLocation> mLocations, Context mContext, int rowForLocationToInflate) {
this.mLocations = mLocations;
this.mContext = mContext;
this.rowForLocationToInflate = rowForLocationToInflate;
inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
//TODO just built up layout now must tie to it.
private void addLocation(WeatherLocation newLocation){
mLocations.add(newLocation);
//TODO maybe invalidate after adding new item.
}
#Override
public int getCount() {
return mLocations.size();
}
#Override
public WeatherLocation getItem(int position) {
return mLocations.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//TODO build a viewholder
View rowView = inflater.inflate(rowForLocationToInflate, parent, false);
TextView tvZipcode = (TextView) rowView.findViewById(R.id.tvZipCode);
TextView tvCity = (TextView) rowView.findViewById(R.id.tvCity);
TextView tvTemp = (TextView) rowView.findViewById(R.id.tvDegree);
tvZipcode.setText(mLocations.get(position).getZipcode());
tvCity.setText(mLocations.get(position).getCity());
tvTemp.setText(String.valueOf(mLocations.get(position).getTemperature()));
// If you had a Button in your LinearLayout you were attaching to you that you wanted to delete that view/item with, it would look something like this in my case.
Button bDel = (Button) row.findViewById(R.id.bDel);
bDel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mLocations.remove(position);
}
});
return rowView;
}
}
In the onClick you would also remove the item from the SQL db. I can show that too, but I feel you have some coding to do as it stands.
I'm using the AsyncTask to open a URL, access the server, fetch the content and display them in a list view in the main activity. The content extracted consists of a title of the newspaper and a URL to the website, which will be displayed on a WebView in a second activity, if a "read" button is clicked. I coded out the program straight away and it works, but when I looked back at it, I found something that seems unreasonable, so mainly I want to make clear how the code works. Here is the code for the main activity:
package com.example.newsapp;
public class MainActivity extends Activity {
static final private String LOG_TAG = "main";
private ArrayList<Content> aList;
private class Content{
Content() {};
public String title;
public String url;
}
private class MyAdapter extends ArrayAdapter<Content>{
int resource;
public MyAdapter(Context _context, int _resource, List<Content> titles) {
super(_context, _resource, titles);
resource = _resource;
// this.context = _context;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LinearLayout newView;
final Content content = getItem(position);
// Inflate a new view if necessary.
if (convertView == null) {
newView = new LinearLayout(getContext());
String inflater = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater vi = (LayoutInflater) getContext().getSystemService(inflater);
vi.inflate(resource, newView, true);
} else {
newView = (LinearLayout) convertView;
}
// Fills in the view.
TextView tv = (TextView) newView.findViewById(R.id.listText);
ImageButton b = (ImageButton) newView.findViewById(R.id.listButton);
b.setBackgroundResource(0);
tv.setText(content.title);
Typeface type = Typeface.createFromAsset(getAssets(),"LiberationSerif-BoldItalic.ttf");
tv.setTypeface(type);
// Sets a listener for the button, and a tag for the button as well.
b.setTag(Integer.toString(position));
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Reacts to a button press.
Intent intent = new Intent(MainActivity.this, WebPage.class);
Bundle bundle = new Bundle();
bundle.putString("URL", content.url);
intent.putExtras(bundle);
startActivity(intent);
}
});
return newView;
}
}
class MyAsyncTask extends AsyncTask<String, String, String> {
private ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
InputStream inputStream = null;
String result = "";
Content content;
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setMessage("Downloading the news...");
progressDialog.show();
progressDialog.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface arg0) {
MyAsyncTask.this.cancel(true);
}
});
}
#Override
protected String doInBackground(String... params) {
String url_select = params[0];
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
try {
// Set up HTTP post
// HttpClient is more then less deprecated. Need to change to URLConnection
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// Read content & Log
inputStream = httpEntity.getContent();
} catch (UnsupportedEncodingException e1) {
Log.e("UnsupportedEncodingException", e1.toString());
e1.printStackTrace();
} catch (ClientProtocolException e2) {
Log.e("ClientProtocolException", e2.toString());
e2.printStackTrace();
} catch (IllegalStateException e3) {
Log.e("IllegalStateException", e3.toString());
e3.printStackTrace();
} catch (IOException e4) {
Log.e("IOException", e4.toString());
e4.printStackTrace();
}
// Convert response to string using String Builder
try {
BufferedReader bReader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sBuilder = new StringBuilder();
String line = null;
while ((line = bReader.readLine()) != null) {
sBuilder.append(line + "\n");
}
inputStream.close();
result = sBuilder.toString();
} catch (Exception e) {
Log.e("StringBuilding & BufferedReader", "Error converting result " + e.toString());
}
return result;
} // protected Void doInBackground(String... params)
protected void onPostExecute(String result) {
//parse JSON data
try {
super.onPostExecute(result);
Log.i(LOG_TAG, result);
JSONObject object = new JSONObject(result);
JSONArray jArray = object.getJSONArray("sites");
for(int i=0; i < jArray.length(); i++) {
JSONObject jObject = jArray.getJSONObject(i);
content = new Content();
if (jObject.has("title") && jObject.has("url")){
content.title = jObject.getString("title");
content.url = jObject.getString("url");
aList.add(content);
aa.notifyDataSetChanged();
}
} // End Loop
progressDialog.dismiss();
} catch (JSONException e) {
// progressDialog.dismiss();
Log.e("JSONException", "Error: " + e.toString());
}
} // protected void onPostExecute(String result)
}
private MyAdapter aa;
private MyAsyncTask loadTask;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
loadTask = new MyAsyncTask();
loadTask.execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
ListView myListView = (ListView) findViewById(R.id.listView1);
myListView.setAdapter(aa);
aa.notifyDataSetChanged();
}
public void refresh(View v){
if (loadTask.getStatus() == AsyncTask.Status.FINISHED){
aList.clear();
aa.notifyDataSetChanged();
new MyAsyncTask().execute("http://luca-ucsc.appspot.com/jsonnews/default/news_sources.json");
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
So you can see that only after loadTask.execute() in onCreate(), do I create the object for alist and aa, but I'm already using them in onPostExecute() in the AsyncTaks class, so I'm not very clear what happens here, because onPostExecute() and the UI are on the same thread, so the code in onPostExecute() should be executed first.
I thought I should put
aList = new ArrayList<Content>();
aa = new MyAdapter(this, R.layout.list_element, aList);
into onPostExecute(), which is more logical to me, but the app crashes this way. Also I think deleting aa.notifyDataSetChanged(); in onPostExecute() shouldn't be a problem because it's also in the onCreate() method, but this actually causes the list view to be blank, without any content. Actually, putting any of the codes after loadTask.execute() into the if block of the onPostExecute() method causes some problem, or crashes the app. That would be great if somebody can give some insight or hint. Thanks for reading.
onPostExecute is called on the UI thread after the background task completes its work. You cannot guarantee the timing of this call in relation to other calls on the UI thread.
Since you are already implementing getView yourself, I recommend you extend BaseAdapter instead of ArrayAdapter and implement the other few required methods. It's not hard and you can use whatever data structure you want to back the adapter. Assuming you use a List<Content> to back the adapter, you can write a method to swap the list in place like so:
public void swapList(List<Content> newList) {
this.list = newList;
notifyDataSetChanged();
}
In your AsyncTask, you have complete control of the Params, Progress, and Result parameterized types. They don't all have to be String. You can do this instead:
private class myAsyncTask extends AsyncTask<String, Void, List<Content>> {
/* ... */
}
The String for Params is the URL (same as you do now). Void for Progress because you don't publish progress anyway. List<Content> for Result because that's the thing you actually want to end up with after doing your task.
You should do ALL of your work in doInBackground. There is no reason to deserialize a String into a JSONArray and mess around with that in onPostExecute, particularly since that is happening on the main thread. Rewrite doInBackground to return a List<Content>, and all you need in onPostExecute is this:
public void onPostExecute(List<Content> result) {
adapter.swapList(result);
}
Now you can create the adapter once (in onCreate()) and just swap the list whenever it's appropriate.
I tried the code below and also tried the AsyncTaskLoader approach. The app crashes when I instantiate the AsyncTask. Pleas advise me on the best approach to load JSON in a list fragment inside tab host.
The code below is the tab fragment (I use action bar tabs in main activity):
public class TabTop extends ListFragment {
Context context = getActivity().getBaseContext();
String API_URL = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
ArrayList<Deal> deals;
DealsListAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
#SuppressWarnings("unused")
int a = 0;
return super.onCreateView(inflater, container, savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
GetTopDeals getTopDeals = new GetTopDeals(context);
getTopDeals.execute(API_URL);
super.onActivityCreated(savedInstanceState);
}
class GetTopDeals extends AsyncTask<String, Void, ArrayList<Deal>>{
ProgressDialog progressDialog;
public GetTopDeals(Context activity) {
this.progressDialog = new ProgressDialog(activity);
}
#Override
protected void onPostExecute(ArrayList<Deal> result) {
adapter = new DealsListAdapter(context, result);
setListAdapter(adapter);
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
progressDialog.setCancelable(true);
progressDialog.setProgress(0);
progressDialog.setMessage("loading Top deals...");
progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
super.onPreExecute();
}
#Override
protected ArrayList<Deal> doInBackground(String... urls) {
String response = sendRequest(urls[0]); // make request for json
return processResponse(response); // parse the Json and return ArrayList to postExecute
}
private String sendRequest(String apiUrl) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL url = new URL(apiUrl);
httpCon = (HttpURLConnection) url.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
}
public ArrayList<Deal> processResponse(String response) {
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new ArrayList<Deal>();
for (int i = 0; i < results.length(); i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
int api_id = jMovie.getInt("id");
String name = jMovie.getString("title");
String content = jMovie.getString("synopsis");
JSONObject posters = jMovie.getJSONObject("posters");
String image_url = posters.getString("profile");
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
#Override
public void onStart() {
super.onStart();
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = new Intent(getActivity().getBaseContext(), DealInformation.class);
startActivity(intent);
super.onListItemClick(l, v, position, id);
}
}
Make your asynctask in his own file.
And when your asynctask is finish, implement OnPostExecute which is automatically call. Notify your adapter by a notifyDataSetChanged like that :
#Override
protected void onPostExecute(List<NewItem> list) {
Adapter.getListe().clear();
Adapter.getListe().addAll(list);
Adapter.notifyDataSetChanged();
}
thank you guys,
i want to post my answer. after some research i decided to go with AsyncTaskLoader.
this is my code
public class TabOurPicks extends ListFragment implements LoaderCallbacks<String[]> {
// when activity loads- onActivityCreated() calls the initLoader() who activate onCreateLoader()
#Override
public void onActivityCreated(Bundle savedInstance) {
super.onActivityCreated(savedInstance);
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, new String[]{}));
getLoaderManager().initLoader(0, null,this).forceLoad();
}
// onCreateLoader instantiate the asynctaskloaser who work in bg
#Override
public RSSLoader onCreateLoader(int arg0, Bundle arg1) {
return new RSSLoader(getActivity()); //
}
// after bg process invoke onLoadFinished() who work in ui thread
#Override
public void onLoadFinished(Loader<String[]> loader, String[] data) {
setListAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, data
) );
}
#Override
public void onLoaderReset(Loader<String[]> arg0) {
// TODO Auto-generated method stub
}
and this is the inner class for the loader:
static public class RSSLoader extends AsyncTaskLoader<String[]>
{
public RSSLoader(Context context) {
super(context);
}
#Override
public String[] loadInBackground() {
String url = "http://api.rottentomatoes.com/api/public/v1.0/movies/770672122/similar.json?apikey=crhhxb4accwwa6cy6fxrm8vj&limit=1";
String response = sendRequest(url);
return processResponse(response);
}
private String sendRequest(String url) {
BufferedReader input = null; // get the json
HttpURLConnection httpCon = null; // the http connection object
StringBuilder response = new StringBuilder(); // hold all the data from the jason in string separated with "\n"
try {
URL apiUrl = new URL(url);
httpCon = (HttpURLConnection) apiUrl.openConnection();
if (httpCon.getResponseCode() != HttpURLConnection.HTTP_OK) { // check for connectivity with server
return null;
}
input = new BufferedReader(new InputStreamReader(httpCon.getInputStream())); // pull all the json from the site
String line;
while ((line = input.readLine()) != null) {
response.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpCon != null) {
httpCon.disconnect();
}
}
return response.toString();
}
private String[] processResponse(String response) {
String[] deals = null;
try {
JSONObject responseObject = new JSONObject(response); // Creates a new JSONObject with name/value mappings from the JSON string.
JSONArray results = responseObject.getJSONArray("movies"); // Returns the value mapped by name if it exists and is a JSONArray.
deals = new String[10];
for (int i = 0; i < 9; i++) { // in this loop i copy the json array to movies arraylist in order to display listView
JSONObject jMovie = results.getJSONObject(i);
String name = jMovie.getString("title");
deals[i] = name;
}
}catch (JSONException e) {
e.printStackTrace();
}
return deals;
}
}
}
It doesn't matter if your asynctask has its own file. You just don't want your activity to extends asynctask as this would make your activity asynchronous - but this is impossible to do anyways due to java's double inheritance rule.
Based on the architecture of your app and your programming style the asyntask can be an inner class in the activity. on the PostExecute method make sure you have given data to your adapter and that the adapter is set to the list, then just run notifyDataSetChanged().
Assuming your asynctask is loading data from cache or the network you are on the right track with your approach to this.
I'm trying to put some custom list adapters into their own classes to make my app have less redundant code and to make it more manageable.
I call on the different adapter classes thru a conditional statement within a ListFragment. I originally had the adapters in the ListFragment class and this all worked as planed. Now to clean up everything and to get all that code out of the ListFragment, I moved the Adapters out and into their own classes. Since that was done, these methods have to be static so I can call on them but these new classes now containa lot of:
Cannot make a static reference to the non-static method
setListAdapter(ListAdapter) from the type ListFragment
Specifically the setListAdapter, setListAdapter, getFragmentManager, and getFragmentManager methods. I don't want a ton of ListView Fragment classes and since a lot of code would be reused, It makes more since to only have one ListFragment and use conditionals to get the correct adapter but I don't know how to fix these new classes so I can use them.
Sorry for the long explanation. I'll try to only post the relevant code to get the idea to what I am trying to accomplish and for you to guide me.
Can this be done the way I am doing this and how do I correct it?
If there is a better way, please post some code with your explination or code in what needs to be changed within my Adapter Class.
In my fragment's onActivityCreated:
. . .
// Get the string to query from last Fragment and pass it to this
// Fragment
Bundle args = this.getArguments();
boolean rawRes = args.getBoolean(KEY_IS_RAW_RES);
String url = args.getString(KEY_URL);
int fileName = args.getInt(KEY_RES_FILE);
this.getJsonFile(url, rawRes, fileName);
}
public void getJsonFile(String url, boolean rawRes, int fileName) {
if (rawRes == true) {
getFromRawRes(fileName);
} else {
getFromURL(url);
}
}
public void getFromRawRes(int fileName) {
InputStream file = getResources().openRawResource(fileName);
JSONParser jParser = new JSONParser();
JSONArray json = jParser.getJSONFromRes(file);
ListAdapter_SevenItem.callback(json, context);//<--THIS IS A CALL TO THE ADAPTER!!
}
One of the Adapters:
public class ListAdapter_SevenItem extends ListViewFragment {
. . .
public static void callback(JSONArray json, Context c) {
if (json != null) {
// Hashmap for ListView
. . .
// create the list item mapping
String[] from = new String[]{TAG_LABEL, TAG_TITLE, TAG_DISCR, TAG_RES_FILE, TAG_IS_RAW_RES, TAG_CONT_ID};
int[] to = new int[]{R.id.listLabel, R.id.listTitle, R.id.listDiscription, R.id.listResFile, R.id.listIsRawRes, R.id.listContID};
// Updating parsed JSON data into ListView
SimpleAdapter adapter = new SimpleAdapter(c, mList, R.layout.list_item, from, to);
setListAdapter(adapter);
// selecting single ListView item
final ListView lv = setListAdapter();
// Launching new screen on Selecting Single ListItem
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
MainActivity.mLayout.toggleSidebar();
setHasOptionsMenu(true);
FragmentManager fm = getFragmentManager();
final FragmentTransaction lcFT = fm.beginTransaction();
lcFT.setCustomAnimations(R.anim.slide_in, R.anim.hyperspace_out, R.anim.hyperspace_in, R.anim.slide_out);
final Bundle args = new Bundle();
String resFile = ((TextView) view.findViewById(R.id.listResFile)).getText().toString();
int passResFile = getFragmentManager().getIdentifier(resFile, "raw", "com.andaero.app");
args.putInt("KEY_RES_FILE", passResFile);
boolean isRawRes = true;
args.putBoolean("KEY_IS_RAW_RES", isRawRes);
// Delayed to improve animations
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
ListViewFragment lvf = new ListViewFragment();
lcFT.replace(R.id.listContainer, lvf).commit();
lvf.setArguments(args);
}
}, 300);
}
});
}
}
}
You're overcomplicating things.
There should not be static method/calls like the one you use. It should be very simple. Within the list fragment's onActivityCreated(Bundle savedInstanceState) you create an instance of your list adapter, and set it as the adapter using the setListAdapter().
Check for TitlesFragment sample in the tutorial on fragments.
A ListView Fragment Class that can be reused thru-out an application.
I use jgilfelt's universal JasonArrayAdapter class that can be downloaded on GitHub. The class here below can be used over and over thru-out the application so its the only ListView class needed - Which means a reduction in redundant code/classes. Esp., if you have list views that require different attributes and/or layouts.
If your loading this ListViewFragment from another Fragment:
String uri = "http://www.xxxx/myjsonfile.json";//EXAMPLE IF FROM A URL
String uri = "json/myjsonfile.json";//EXAMPLE GETTING FROM YOUR ASSETS FOLDER
args.putString("KEY_URI", uri);
String adptrID = "#";//USED TO DETERMINE WHICH LAYOUT TO USE
args.putString("KEY_ADPTR_ID", adptrID);
ListViewFragment lvf = new ListViewFragment();
lcFT.replace(R.id.myContainer, lvf).commit();
lvf.setArguments(args);
If If your loading this ListViewFragment from within it's self, just add the appropriate items in your JSON files and get them into your setArguments(args) Bundle.
If you have any improvements/etc to the methods, feel free to add it to your comment/answer. I'm new to Android and learning as I go... Thnx
ListViewFragment Class:
public class ListViewFragment extends ListFragment implements OnItemClickListener {
. . .
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle getArgs = this.getArguments();
String URI = getArgs.getString(KEY_URI);
. . .
new GetJSONTask().execute(URI);
}
class GetJSONTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String... arg0) {
String uri = arg0[0];
InputStream is = null;
if (uri.contains("http") == true) {// Get JSON from URL
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(uri);
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
BufferedReader rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
while ((line = rd.readLine()) != null) {
json += line;
}
rd.close();
return json;
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {//Get JSON from Assets
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try {
InputStream jsonFile = getActivity().getAssets().open(uri);
Reader reader = new BufferedReader(new InputStreamReader(jsonFile, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
jsonFile.close();
} catch (IOException e) {
e.printStackTrace();
}
json = writer.toString();
// return JSON String
return json;
}
}
#Override
protected void onPostExecute(String result) {
try {
showData(result);
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(getActivity(), "something went wrong", Toast.LENGTH_SHORT).show();
}
}
}
private void showData(String json) throws JSONException {
JSONObject o = new JSONObject(json);
JSONArray data = o.getJSONArray("results");
Bundle getArgs = this.getArguments();
String adptrID = getArgs.getString(KEY_ADPTR_ID);
if (adptrID == "3") {//Adapter for 3 items
String[] from = new String[]{"label", "title", "description", "uri", "adapterID", "containerID"};
int[] to = new int[]{R.id.listLabel, R.id.listTitle, R.id.listDiscription, R.id.listURI, R.id.listAdapterID, R.id.listContID};
ListAdapter adapter = new JSONArrayAdapter(getActivity(), data, R.layout.list_item, from, to, null);
getListView().setOnItemClickListener(this);
getListView().setAdapter(adapter);
}
if (adptrID == "4") {//Adapter for 4 items - Get the idea?
. . .
} . . .//Additional Adapter can be added....
}
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final Bundle args = new Bundle();
Bundle getArgs = this.getArguments();
String uri = ((TextView) view.findViewById(R.id.listURI)).getText().toString();
args.putString("KEY_URI", uri);
String adptrID = ((TextView) view.findViewById(R.id.listAdapterID)).getText().toString();
args.putString("KEY_ADPTR_ID", adptrID);
String contID = ((TextView) view.findViewById(R.id.listContID)).getText().toString();
args.putString("KEY_CONTAINER_ID", contID);
//Conditional to determine witch container to load the ListViewFragment(this)
if (containerID == "listContainer") {
lcFT.replace(R.id.listContainer, lvf).commit();
lvf.setArguments(args);
}
if (containerID == "someOtherContainer") {
lcFT.replace(R.id.discriptionListContainer, lvf).commit();
lvf.setArguments(args);
}. . .
}