Insert element in List with AsyncTask - android

I'm trying to load some JSON inside my Android App. On the MainActivity I have created one AsyncTask to download the JSON and to Parse it. Everything here works, but I have a problem to put everything inside a ListView.
I have created a Model (with 6 Strings) and the Adapter.
The problem is, I can't update the List with the new content inside the "doInBackground" function, and I don't know how to put everything inside the list.

If your Adapter is set up properly to listen to a List as its data source, then you will simply need to change the elements in the List and then notify the Adapter by calling one of the notify methods, such as adapter.notifyDataSetChanged().
However, since this is modifying UI elements, this will need to be run on the UI thread. The doInBackground() method of an AsyncTask is run on a separate thread than the UI thread so we need to do one of two things:
Wait until we're done in the separate thread and then notify the adapter
Tell the UI thread to notify the adapter
The first is easily done if we call adapter.notifyDataSetChanged() in the onPostExecuted method of an AsyncTask.
The second is easily done if we have a reference to an Activity object, by calling the runOnUiThread(Runnable) method.
Hope this helps.

doInBackground() method didn't have access to UI thread, so you can't do it. In your case you should update your ListView in onPostExecute method or you can use for this runOnUiThread() method directly in your doInBackground() method.

You can't update or put data in listview in doInBackground() method. You have to assign Adpter to Listview, onCreate() method of MainActivity and onPostExecute() Method update listview. I have posted below code snippet will be helpful.
public class MainActivity extends AppCompatActivity {
String json_string;
JSONObject jsonObject;
JSONArray jsonArray;
ContactAdapter contactAdapter;
ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new BackegroundTask().execute();
listView = (ListView)findViewById(R.id.listview);
contactAdapter = new ContactAdapter(this,R.layout.row_layout);
listView.setAdapter(contactAdapter);
}
class BackegroundTask extends AsyncTask<Void,Void,String>
{
String json_url;
String JSON_STRING;
#Override
protected void onPreExecute() {
json_url = "http://10.0.2.2/webapp/index.php";
}
#Override
protected String doInBackground(Void... voids) {
try {
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();
httpURLConnection.setDoOutput(true);
InputStream inputStream = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
while ((JSON_STRING = bufferedReader.readLine()) != null){
stringBuilder.append(JSON_STRING+"\n");
}
bufferedReader.close();
inputStream.close();
httpURLConnection.disconnect();
return stringBuilder.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
json_string = result;
try {
jsonObject = new JSONObject(json_string);
jsonArray = jsonObject.getJSONArray("server_response");
int count = 0;
String id,username;
while (count<jsonArray.length()){
JSONObject job = jsonArray.getJSONObject(count);
id = job.getString("id");
username = job.getString("username");
Contacts contacts = new Contacts(id,username);
contactAdapter.add(contacts);
contactAdapter.notifyDataSetChanged();
count++;
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}

Related

ProgressDialog is not getting displayed when i invoke a AsyncTask which returns values

In my Android app, i have an activity which displays 'ExpandableListView'. The values are retrieved from an API(AsyncTask). But due to network latency, i wanted to show ProgressDialog during retrieving these values. But that dialog is not at all displayed. Can someone help me?
Following is my activity:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#f4f4f4" >
<ExpandableListView
android:id="#+id/lvExp"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
</LinearLayout>
</RelativeLayout>
Here is how i am calling an AsyncTask
GetSubTopicData objSubTopics=new GetSubTopicData(Learning_Activity.this);
listChildTopics=objSubTopics.execute(getMainTopicURL).get();
processChildData(listChildTopics,index);
Here is how I designed my AsyncTask:
When I click on MainTopic(Menu Item, I need to get sub-menu items by invoking this below AsyncTask. I wanted to have a ProgressDialog here, till i get these childmenu items. So please help me here.
public class GetSubTopicData extends AsyncTask<String,Void,List<String>>
{
String strResponse;
private Context mContext=null;
private ProgressDialog mDialog=null;
public GetSubTopicData(Context context)
{
mContext=context;
}
#Override
protected void onPreExecute() {
//super.onPreExecute();
mDialog=new ProgressDialog(mContext);
mDialog.setMessage("Loading.....");
mDialog.setTitle("Fetching Data");
mDialog.show();
}
#Override
protected void onPostExecute(List<String> s) {
//super.onPostExecute(s);
mDialog.dismiss();
}
#Override
protected List<String> doInBackground(String... params) {
String strSubTopicURL=params[0];
List<String> strSTopics=new ArrayList<String>();
try {
//creating a URL
URL url = new URL(strSubTopicURL);
//Opening the URL using HttpURLConnection
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//StringBuilder object to read the string from the service
StringBuilder sb = new StringBuilder();
//We will use a buffered reader to read the string from service
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
//A simple string to read values from each line
String json;
//reading until we don't find null
while ((json = bufferedReader.readLine()) != null) {
//appending it to string builder
sb.append(json + "\n");
}
//finally returning the read string
strResponse= sb.toString().trim();
con.getInputStream().close();
con.disconnect();
} catch (Exception e) {
e.printStackTrace();
return null;
}
try
{
JSONArray ja=new JSONArray(strResponse);
JSONObject jo=null;
//listDataHeader=new String[ja.length()];
for(int i=0;i<ja.length();i++)
{
jo=ja.getJSONObject(i);
strSTopics.add(jo.getString("SubTopicName"));
//strClsSubjectNames[i]=jo.getString("SubjectName");
Log.d("SubTopicName",jo.getString("SubTopicName"));
}
Log.d("SubTopicName",""+strSTopics.size());
}catch (Exception e)
{
e.printStackTrace();
}
return strSTopics;
}
}
Find screenshot here:
You're using get() when calling AsyncTask, which executes the code in the current thread (!!!) instead of another thread. Also, it won't call onPreExecute() and onPostExecute().
If you want to run the code on another thread, use execute() instead. Then you can process the data in onPostExecute(). However, remember to cancel the AsyncTask when you leave the activity, and call isCancelled() inside doInBackground() often (in the while loop for instance), so that you can return early if the task is cancelled.

Finish procedure before starting a new one

I am beginner in Android and I need some help. So, I have a procedure with sub-procedures inside. How can I finish one before starting a new one. Here is a code to better understand:
public void onCellLocationChanged(CellLocation lokacija) {
super.onCellLocationChanged(lokacija);
location = (GsmCellLocation) Phone.getCellLocation();
textCellId.setText(String.valueOf(location.getCid() % 65536));
textCellLac.setText(String.valueOf(location.getLac()));
String JSON_URL_string=JSON_URL + "?cellid=" + String.valueOf(location.getCid()%65636);
getJSON(JSON_URL_string);
myJSONString = textCellNameSakriven.getText().toString();
ParseJSON(myJSONString);
}
Problem is that myJSONString is empty, cause textCEllNameSkriven is also empty. That textView textCellNameSkriven is made when getJSON(JSON_URL_string) is finished. If I run debugger and go step by step, app goes directly from getJSON(JSON_URL_string) row to the next one and the next etc
Edit: Maybe the problem is that onPostExecute is not finished before starting ParseJSON. Here is also a code for getJSON:
private void getJSON(String url) {
class GetJSON extends AsyncTask<String, Void, String> {
ProgressDialog loading;
#Override
protected void onPreExecute() {
super.onPreExecute();
loading = ProgressDialog.show(MainActivity.this, "Please Wait...", null, true, true);
}
#Override
protected String doInBackground(String... params) {
String uri = params[0];
BufferedReader bufferedReader = null;
try {
URL url = new URL(uri);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();
bufferedReader = new BufferedReader(new InputStreamReader(con.getInputStream()));
String json;
while ((json = bufferedReader.readLine()) != null) {
sb.append(json + "\n");
}
return sb.toString().trim();
} catch (Exception e) {
return null;
}
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
loading.dismiss();
textCellNameSakriven.setText(s);
}
}
GetJSON gj = new GetJSON();
gj.execute(url);
}
Since you are running a async task it practically runs on a different thread, so your getJson method need not wait for post execute and can return after starting the async task, so you can never be sure in this way that parseJson gets executed after textView is populated. You are running into classic race condition issue.
Your issue could be easily solved, if you have a callback which is called after postExecute is done, and you can handle parseJson there
So, something simple like , create interface MyCallback
public interface MyCallback {
public OnReadJsonDone();
}
Let your activity implement this MyCallback
public MainActivity implements MyCallback
{
...........
#Override
public OnReadJsonDone(){
parseJson();
}
Now change signature of getJson to
getJSON(string json, final MyCallback callback) {
Now in onpostexecute
//call OnReadJsonDone
callback.OnReadJsonDone()
So, all you now need is while calling getJSon pass this as second param
getJSON(JSON_URL_string,this);
Haven't tested this but you get the idea

create a non-stop android listview

I get some json data from server using AsyncTask and put it in a ListView using an ArrayAdapter. As I am getting a lot of data, please tell me how can I add an infinite scroll to my ListView. I mean to say, that when the ListView reaches its end, the data should be loaded automatically. I searched the web and tried a lot of things but can't do what I want to.
Here is my code
public class Main extends Activity {
ArrayList<ContentSetter> postList;
StringArrayAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
postList = new ArrayList<>();
new GetData().execute();
ListView lv = (ListView) findViewById(R.id.list);
Button btnLoadMore = new Button(this);
btnLoadMore.setText("Load More");
lv.addFooterView(btnLoadMore);
adapter = new StringArrayAdapter(getApplicationContext(), R.layout.row, postList);
lv.setAdapter(adapter);
}
class GetData extends AsyncTask<String, Void, Boolean> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(Main.this);
dialog.setMessage("Loading, please wait");
dialog.setTitle("Connecting server");
dialog.show();
dialog.setCancelable(false);
}
#Override
protected Boolean doInBackground(String... params) {
HttpURLConnection urlConnection;
int pageed;
String result = "";
try {
URL url = new URL("http://paradi3emusic.com/?json=get_posts&post_type=songs&count=15");
urlConnection = (HttpURLConnection) url.openConnection();
int code = urlConnection.getResponseCode();
if(code==200){
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = bufferedReader.readLine()) != null)
result += line;
JSONObject jsono = new JSONObject(result);
JSONArray jarray = jsono.getJSONArray("posts");
for (int i = 0; i < jarray.length(); i++) {
JSONObject object = jarray.getJSONObject(i);
ContentSetter content = new ContentSetter();
JSONObject customfield = object.getJSONObject("custom_fields");
JSONArray playlist = customfield.getJSONArray("mylyrics1");
content.setPostId(playlist.getString(0));
postList.add(content);
}
in.close();
return true;
}
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Connecting err.", Toast.LENGTH_LONG).show();
}
return false;
}
protected void onPostExecute(Boolean result) {
dialog.cancel();
adapter.notifyDataSetChanged();
//TextView mahd = (TextView)findViewById(R.id.mahdi);
if (!result)
Toast.makeText(getApplicationContext(), "Unable to fetch data from server.", Toast.LENGTH_LONG).show();
}
}
}
This concept is called lazy loading.
you need to do something like this:
listen for the event when user scrolls to the end of listview
make your webservice call and show user a progressbar at the footer of list.
update list with data once data is received from service call, remove progressbar.
here is an example
This feature is something similar to Pageing. What you need to do is :
1) Listen for event when user scroll to Bottom of Listview
2) Pull more data from server or any other source you want to.
3) When request is being made put some footer to your listview,example showing some progress dialog for user friendliness.
4) Update the data source with pulled information
5) Set and Update your adapter and remove the footer from the listview and You are done.
For Your Reference check this link:
https://chrisarriola.wordpress.com/2012/06/15/dynamic-data-with-listview-loading-footer/

android - AsyncTask not reaching onPostExecute() - "The application may be doing too much in its main thread"

I have a Fragment in which I want to parse a JSON and create an ArrayList with some of its attributes and then put the ArrayList's data to a Spinner. However, I do not know if I am doing the AsyncTask as it I should.
Everytime I try a new way to parse the JSON from a URL in my Fragment Activity either the app crashes with "Unfortunately, the app has stopped" message or the Spinner stays empty. I verified with Logs that I never reach the onPostExecute() method on the AsyncTask.
Questions:
- What am I doing wrong?
- Should I be using AsyncTask?
My code:
private class LoadResources extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.v(TAG, "pre-execute");
}
// Call after onPreExecute method
#Override
protected String doInBackground(String... urls) {
Log.v(TAG, "background");
Log.v(TAG, urls[0]);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.interrupted();
}
}
try {
URL u = new URL(urls[0]);
BufferedReader in = new BufferedReader(new InputStreamReader(u.openStream(), Charset.forName("UTF-8")));
StringBuilder sb = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
// the above parsing works, I've tested
JsonParser parser = new JsonParser();
JsonElement elem = parser.parse(sb.toString());
JsonArray array = elem.getAsJsonArray();
for (int i = 0; i < array.size(); i++) {
JsonElement elem1 = array.get(i);
JsonArray tmpArr = elem1.getAsJsonArray();
for (JsonElement elem2 : tmpArr) {
elem2.getAsJsonObject().getAsJsonPrimitive().getAsString());
myArrayList.add(elem2.getAsJsonObject().getAsJsonPrimitive("name").toString());
return urls[0];
}
protected void onPostExecute(String params) {
Log.v(TAG, params);
}
}
On the onCreateView:
LoadResources loader = new LoadResources();
loader.execute("http://localhost:5000/avalidpath);
text = (AutoCompleteTextView) rootView.findViewById(R.id.nomeAluno);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_spinner_dropdown_item, myArrayList);
text.setAdapter(adapter);
text.setThreshold(3);
Right now the app stops working when I swipe to this fragment.
Thanks in advance, guys.
Actually you should do the heavy work in doInBckground method.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter. Doc here
EDIT:
class LoadResources extends AsyncTask<String, Void, ArrayList<String>> {
Context context;
public LoadResources(Context context) {
this.context = context;
}
#Override
protected String doInBackground(String... urls) {
...
return myArrayList;
}
protected void onPostExecute(ArrayList<String> params) {
((YourActivity)context).setMyAdapter(params);
}
}
In your Activity (fragment or whatever) :
public void setMyAdapter(ArrayList<String> params) {
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_spinner_dropdown_item, myArrayList);
text.setAdapter(adapter);
}
onPostExecute is done on the UI thread. You have way too much work on it. Everything that isn't directly effecting a UI element should be done in doInBackground. Right now your doInBackground is doing nothing.
Move whole code from onPostExecute to doInBackground. You can use publishProgress(...); and onProgressUpdate to add items to list. Or create local list in AsyncTask and addAll items to your global List in onPostExecute

Sending/receiving an ArrayList to/from AsyncTask

Using JSON I have trimmed the URL of an online gallery and filled an array list with the image sources, or image URLs.
I now want to return the ArrayList back to the MainActivity so that I can then convert the ArrayList to an Array and use that Array of Image URLs to download the images and put them in a gridview.
My problem is that I am not returning the ArrayList from the AsyncTask to the MainActivity. Any pointers would be greatly appreciated.
Thanks for your time.
Main Activity:
public class MainActivity extends Activity {
public static ArrayList<String> list = new ArrayList<String>();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new myAsyncTask().execute(list);
Log.v("jknfsda: ",list.get(1));
//TextView line1 = (TextView) findViewById(R.id.line1);
//for(int i=0; i<list.size(); i++){
// line1.append(i+1 + ": " + list.get(i));
}
}
AsyncTask:
public class myAsyncTask extends AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
static String quellaGalleryInfo = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Fwww.quellabicycle.com%2Fgallery%22&format=json&callback=";
public static ArrayList<String> urlArr = new ArrayList<String>();
#Override
protected ArrayList<String> doInBackground(ArrayList<String>... list) {
DefaultHttpClient httpclient = new DefaultHttpClient(new BasicHttpParams());
HttpPost httppost = new HttpPost(quellaGalleryInfo);
httppost.setHeader("Content-type", "application/json");
InputStream inputStream = null;
String result = null; // Hold all of the data from the URL
try{
HttpResponse response = httpclient.execute(httppost); //Response from webservice (may or may not get)
HttpEntity entity = response.getEntity(); // all the content from the requested URL along with headers etc.
inputStream = entity.getContent(); // get maincontent from URL
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"),8);// Read all data from inputStream until buffer is full
StringBuilder theStringBuilder = new StringBuilder();//Store all the data
String line = null;
while((line = reader.readLine())!=null){
theStringBuilder.append(line + "\n");
}
//read all the data from the buffer until nothing is left
result = theStringBuilder.toString(); // everything now inside result
}
catch (Exception e){
e.printStackTrace();
}
finally { //close inputstream
try{
if(inputStream !=null) inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
JSONObject jsonObject;
try{
Log.v("JSONParser Result: ", result);
jsonObject = new JSONObject(result);//object of all the data
JSONObject queryJSONObject = jsonObject.getJSONObject("query");//get query objects
JSONObject resultsJSONObject = queryJSONObject.getJSONObject("results");//get results object inside of query object
JSONObject bodyJSONObject = resultsJSONObject.getJSONObject("body");
JSONArray divJSONArray = bodyJSONObject.getJSONArray("div");
JSONObject div_position_zero = divJSONArray.getJSONObject(0);
JSONArray ulJSONArray = div_position_zero.getJSONArray("ul");
JSONObject ul_position_two = ulJSONArray.getJSONObject(2);
JSONArray liJSONArray = ul_position_two.getJSONArray("li");
for(int i=0; i < liJSONArray.length(); i++){
JSONObject li_position = liJSONArray.getJSONObject(i);
JSONObject a_JSONObject = li_position.getJSONObject("a");
JSONObject imgJSONObject = a_JSONObject.getJSONObject("img");
urlArr.add(imgJSONObject.getString("src"));//final object where data resides
}
for(String item : urlArr){
Log.v("JSONParser list items: ", item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}
//protected void onPostExecute(ArrayList<String>... list){
// if(MainActivity.list.size()>0){
// MainActivity.list.clear();
//for(int i =0; i<urlArr.size();i++){
// Log.v("ope urlarr: ", urlArr.get(i));
//MainActivity.list.add(urlArr.get(i));
//}
}
}
}
It works up until here
Log.v("JSONParser list items: ", item);
and then my LogCat just goes blank.
Thanks again.
You can override the postexecute in the main activity as seen below.
new myAsyncTask({
#Override
void onPostExecute(ArrayList<String> Param){
//Should be able to do something here
}
}).execute();
reference
Returning an ArrayList in android AsyncTask class
As I can see, there are two mistakes:
The first is you are passing an instance of the list to the asynctask, but never filling it with result: instead you are creating and filling a new ArrayList called urlArr. You should fill the one retrieved in the doInBackground() parameters. Because of the varargs syntax, you can do it in this way:
ArrayList<String> myList = list[0];
This is because, in the vararg syntax, you can pass a variable number of arguments, and they will be represented as an array called, in your case, "list".
The second error is you cannot know when the asynctask execution will terminate. In the onCreate method you are going to read the result just after the call. But asynctask is basically a wrapper to a Java Thread, and is intended to execute code asyncronously. When you call
Log.v("jknfsda: ",list.get(1));
your array is probably still empty. You should use a callback to notify the activity the results are ready. A simple way to do it is to pass an activity instance to your asynctask class
new myAsyncTask(this).execute(list);
, retrieve it in the asynctask class and store it in a field
protected ArrayList<String> myAsyncTask(MainActivity context){...}
and, in the end, notify the activity in the onPostExecute calling a method in the activity. In example, if you created a method called myResultsAreReady() in the activity, you can call it as:
protected void onPostExecute(ArrayList<String>... list){
context.myResultsAreReady();
}
Obviously you can use that method for sending data to the activity, if you wish ;)
In your AsyncTask:
Return the correct value at the end of doInBackground, you are always returning null.
for(String item : urlArr){
Log.v("JSONParser list items: ", item);
}
return urlArr;
And you will have access to it in the onPostExecute, just uncomment yours and use the list parameter (you can can use a non static ArrayList too).

Categories

Resources