How to set List Adapter in onPostExecute Asynctask? - android

Good Day everyone,
I have some problem here. I make a web service call in AsyncTask DoInBackground.
And I wanted to set list adapter, but I got error
java.lang.NullPointerException: Attempt to invoke interface method 'int java.util.List.size()' on a null object reference
Now how to set list adapter in post execute or something?
My code
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
progressBar = (ProgressBar)findViewById(R.id.prgLoading);
//Initialize the ListView
final ListView lvProf = (ListView)findViewById(R.id.lvProfile);
//call the asynctask cals and add item to the list.
new LoadDataForActivity().execute();
//Set adapter , but i got error here
lvProf.setAdapter(new ListProfileAdapter(this,mItems));
}
private class LoadDataForActivity extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(false);
progressBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
getAll();
getTotalLeaveBalance();
getMedicalBalance();
return null;
}
#Override
protected void onPostExecute(Void result) {
//here is I add the item to my list (mitems)
try{
ResponseServiceMedicalBalance = ResponseServiceMedicalBalance.replace("\\\"", "\"");
ResponseServiceMedicalBalance = ResponseServiceMedicalBalance.substring(1, ResponseServiceMedicalBalance.length() - 1);
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(ResponseServiceMedicalBalance);
String Status = jsonObject.get("Status").toString();
if (Status == "true") {
// JSONArray structure = (JSONArray) jsonObject.get("DataList");
String dataku = jsonObject.get("DataList").toString();
mItems = new ArrayList<ListProfileItem>();
try {
dataku = ANGGACRYYPT.decrypt(Enc_Pass, dataku);
}catch (GeneralSecurityException e){
//handle error - could be due to incorrect password or tampered encryptedMsg
}
JSONParser parser = new JSONParser();
JSONArray structure = (JSONArray) parser.parse(dataku);
for (int i = 0; i < structure.size(); i++) {
JSONObject data = (JSONObject) structure.get(i);
item = new ListProfileItem();
item.claimpostname = data.get("claim_post_name").toString();
String claimamount = data.get("max_limit_per_year").toString();
if (claimamount!=("0.0"))
{
Double amount = Double.parseDouble(claimamount);
DecimalFormat formatter = new DecimalFormat("#,###.00");
String AmountFormatted = formatter.format(amount);
item.claimpostamount = AmountFormatted;
}
else
{
item.claimpostamount = data.get("max_limit_per_year").toString();
}
mItems.add(item);
}
// initialize and set the list adapter
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}

There are several ways of solving this, One of the quick and dirtiest is:
Change your AsyncTaskActivity Like this:
private class LoadDataForActivity extends AsyncTask<Void, Void, Void> {
private ListView listView;
private Context context;
public LoadDataForActivity(ListView listView,Context context){
this. listView = listView;
this.context = context;
}
#Override
protected void onPreExecute() {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
progressBar.setVisibility(View.VISIBLE);
progressBar.setIndeterminate(false);
progressBar.setClickable(false);
}
#Override
protected Void doInBackground(Void... params) {
getAll();
getTotalLeaveBalance();
getMedicalBalance();
return null;
}
#Override
protected void onPostExecute(Void result) {
//here is I add the item to my list (mitems)
try{
ResponseServiceMedicalBalance = ResponseServiceMedicalBalance.replace("\\\"", "\"");
ResponseServiceMedicalBalance = ResponseServiceMedicalBalance.substring(1, ResponseServiceMedicalBalance.length() - 1);
JSONParser jsonParser = new JSONParser();
JSONObject jsonObject = (JSONObject) jsonParser.parse(ResponseServiceMedicalBalance);
String Status = jsonObject.get("Status").toString();
if (Status == "true") {
// JSONArray structure = (JSONArray) jsonObject.get("DataList");
String dataku = jsonObject.get("DataList").toString();
mItems = new ArrayList<ListProfileItem>();
try {
dataku = ANGGACRYYPT.decrypt(Enc_Pass, dataku);
}catch (GeneralSecurityException e){
//handle error - could be due to incorrect password or tampered encryptedMsg
}
JSONParser parser = new JSONParser();
JSONArray structure = (JSONArray) parser.parse(dataku);
for (int i = 0; i < structure.size(); i++) {
JSONObject data = (JSONObject) structure.get(i);
item = new ListProfileItem();
item.claimpostname = data.get("claim_post_name").toString();
String claimamount = data.get("max_limit_per_year").toString();
if (claimamount!=("0.0"))
{
Double amount = Double.parseDouble(claimamount);
DecimalFormat formatter = new DecimalFormat("#,###.00");
String AmountFormatted = formatter.format(amount);
item.claimpostamount = AmountFormatted;
}
else
{
item.claimpostamount = data.get("max_limit_per_year").toString();
}
mItems.add(item);
}
listView.setAdapter(new ListProfileAdapter(context,mItems));
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
And you can call the asyncTask like this:
new LoadDataForActivity(listView,this).execute();

Initialise mItems as
mItems = new ArrayList<>();
Create object for ListProfileAdapter
ListProfileAdapter adapter = new ListProfileAdapter(this,mItems);
lvProf.setAdapter(adapter);
Add items in mItems
mItems.add(item);
After all items added to the list notify the adapter
adapter.notifyDataSetChanged();

move it from onCreate to onPostExecute()
define instance of Adapter as global variable then add Items in doInBackground() & call setAdapter onPostExec.
//Set adapter , but i got error here >> move it to onPostExecute
lvProf.setAdapter(new ListProfileAdapter(this,mItems));

I think the following line should be before setting your adapter,
mItems = new ArrayList<ListProfileItem>();
adapter = new ListProfileAdapter(this,mItems)
lvProf.setAdapter(adapter);
Make the instance variable,
ListProfileAdapter adapter;
instead of putting in the Asynctask. After finishing the asynctask in onPostExecute you also need to run,
adapter.notifyDatasetChanged();

Related

Android application crashes if JSON is empty

I am developing an Application of JSON object Which Returns data into ListView.
if json have data then show data in listview..if dont have date then application is crashes.my application is crashes when json is empty.how to resolve this problem..thanx in advancce
here is android code..
public class EmployeePaymentHistory extends Fragment {
HttpParse httpParse = new HttpParse();
ProgressDialog pDialog;
ListView CategoryListView;
ProgressBar progressBar;
List<String> IdList = new ArrayList<>();
private String TAG = EmployeePaymentHistory.class.getSimpleName();
// Http Url For Filter Student Data from Id Sent from previous activity.
String finalResult ;
HashMap<String,String> hashMap = new HashMap<>();
String ParseResult ;
HashMap<String,String> ResultHash = new HashMap<>();
String FinalJSonObject ;
String TempItem;
ProgressDialog progressDialog2;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_employee_payment, container, false);
CategoryListView = (ListView)view.findViewById(R.id.listview1);
progressBar = (ProgressBar)view.findViewById(R.id.progressBar);
//Receiving the ListView Clicked item value send by previous activity.
TempItem = getActivity().getIntent().getExtras().getString("ListViewValue1");
//Calling method to filter Student Record and open selected record.
HttpWebCall(TempItem);
// Add Click listener on Delete button.
return view;
}
// Method to Delete Student Record
//Method to show current record Current Selected Record
public void HttpWebCall(final String PreviousListViewClickedItem){
class HttpWebCallFunction extends AsyncTask<String,Void,String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = ProgressDialog.show(getActivity(),"Loading Data",null,true,true);
}
#Override
protected void onPostExecute(String httpResponseMsg) {
super.onPostExecute(httpResponseMsg);
pDialog.dismiss();
//Storing Complete JSon Object into String Variable.
FinalJSonObject = httpResponseMsg ;
//Parsing the Stored JSOn String to GetHttpResponse Method.
new EmployeePaymentHistory.GetHttpResponse(getActivity()).execute();
}
#Override
protected String doInBackground(String... params) {
ResultHash.put("CustomerID",params[0]);
ParseResult = httpParse.postRequest(ResultHash, api.EmployeePayment);
return ParseResult;
}
}
HttpWebCallFunction httpWebCallFunction = new HttpWebCallFunction();
httpWebCallFunction.execute(PreviousListViewClickedItem);
}
// Parsing Complete JSON Object.
private class GetHttpResponse extends AsyncTask<Void, Void, Void>
{
public Context context;
List<Customer> CategoryList;
public GetHttpResponse(Context context)
{
this.context = context;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0)
{
try
{
if(FinalJSonObject != null)
{
JSONArray jsonArray = null;
try {
jsonArray = new JSONArray(FinalJSonObject);
JSONObject jsonObject;
Customer category;
CategoryList = new ArrayList<Customer>();
for(int i=0; i<jsonArray.length(); i++)
{
category = new Customer();
jsonObject = jsonArray.getJSONObject(i);
category.CustomerName = jsonObject.getString("date").toString();
category.Customertotal = jsonObject.getString("account").toString();
category.CustomerPaid = jsonObject.getString("total").toString();
category.CustomerUnPaid = jsonObject.getString("status").toString();
CategoryList.add(category);
}
}
catch (JSONException e) {
e.printStackTrace();
}
}
else
{
Toast.makeText(context, "abcc", Toast.LENGTH_SHORT).show();
}
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
progressBar.setVisibility(View.GONE);
CategoryListView.setVisibility(View.VISIBLE);
CustomerListAdapterClass adapter = new CustomerListAdapterClass(CategoryList, context);
CategoryListView.setAdapter(adapter);
}
}
}
here is php Api code:
<?php
if($_SERVER['REQUEST_METHOD']=='POST'){
include 'DatabaseConfig.php';
$CustomerID= $_POST['CustomerID'];
// Create connection
$conn = new mysqli($HostName, $HostUser, $HostPass, $DatabaseName);
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
$sql = "sELECT b.payerid,a.account as account,b.date as date,b.status as status,b.type as type,sum(b.amount) as total FROM crm_employees a left JOIN sys_transactions b ON a.id = b.payerid where payerid= '$CustomerID' group by b.date ORDER BY a.id desc" ;
$result = $conn->query($sql);
if ($result->num_rows >0) {
while($row[] = $result->fetch_assoc()) {
$tem = $row;
$json = json_encode($tem);
}
} else {
echo "No Results Found.";
}
echo $json;
$conn->close();
}
?>
You need to give the response output same as you are parsing in android side. If you are trying to find a Json object of key name which is not in response then it will crash.
In this scenario you need to handle manually, the values you think it will be null or empty then handle using normal if statements.
Suppose jsonObject.getString("date") object is not fount then using if statements you can handle.
if(jsonObject.getString("date") != null){
//code here
}

Hashmap size is not constant

I want to retrieve values from a Hash map. When i tried to display the size of a Hashmap in a TextView the size changes in my screen. Any ideas why?
Is there any other way instead of using Hashmap to store the JSONArray so it is more easy to retrieve values?
public void updateJSONdata() {
cafebartablesList = new ArrayList<HashMap<String, Integer>>();
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(READ_COMMENTS_URL);
try {
cafebartables = json.getJSONArray(TAG_POSTS);
for (int i = 0; i < cafebartables.length(); i++) {
LoadMap ld = new LoadMap();
ld.execute();
JSONObject c =cafebartables.getJSONObject(i);
int tableId = c.getInt(TAG_TABLE_ID);
int tableMarginLeft = c.getInt(TAG_MARGIN_LEFT);
int tableMarginTop = c.getInt(TAG_MARGIN_TOP);
int isFree = c.getInt(TAG_ISFREE);
map = new HashMap<String, Integer>();
map.put(TAG_TABLE_ID, tableId);
map.put(TAG_MARGIN_LEFT, tableMarginLeft);
map.put(TAG_MARGIN_TOP, tableMarginTop);
map.put(TAG_ISFREE, isFree);
cafebartablesList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void printMap() {
mapcounter ++;
length_txt =(TextView)findViewById(R.id.length_txt);
length_txt.setText("the size is " +cafebartablesList.size());
}
public class LoadMap extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... arg0) {
updateJSONdata();
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
printMap();
}
}
You're method is executing an asynctask that's recursively calling itself, which is probably causing some weird behavior.
Try something like this instead. have your print method call your asynctask. Your asynctask calls updateJSONdata, which iterates over the json object and constructs your map. At the end of your asynctask, update your textview with the size of your map.
public void updateJSONdata() {
cafebartablesList = new ArrayList<HashMap<String, Integer>>();
JSONParser jParser = new JSONParser();
JSONObject json = jParser.getJSONFromUrl(READ_COMMENTS_URL);
try {
cafebartables = json.getJSONArray(TAG_POSTS);
for (int i = 0; i < cafebartables.length(); i++) {
JSONObject c =cafebartables.getJSONObject(i);
int tableId = c.getInt(TAG_TABLE_ID);
int tableMarginLeft = c.getInt(TAG_MARGIN_LEFT);
int tableMarginTop = c.getInt(TAG_MARGIN_TOP);
int isFree = c.getInt(TAG_ISFREE);
map = new HashMap<String, Integer>();
map.put(TAG_TABLE_ID, tableId);
map.put(TAG_MARGIN_LEFT, tableMarginLeft);
map.put(TAG_MARGIN_TOP, tableMarginTop);
map.put(TAG_ISFREE, isFree);
cafebartablesList.add(map);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
public void printMap() {
LoadMap ld = new LoadMap();
ld.execute();
}
public class LoadMap extends AsyncTask<Void, Void, Boolean> {
#Override
protected Boolean doInBackground(Void... arg0) {
updateJSONdata();
return null;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
length_txt =(TextView)findViewById(R.id.length_txt);
length_txt.setText("the size is " +cafebartablesList.size());
}
}
}
Otherwise, you could use something like Gson, create a POJO for your cafebartablesList and call
Gson gson = new GsonBuilder()
.registerTypeAdapter(MyPojo.class, new MyDeserializer())
.build();
MyPojo mp = gson.fromJson(json, MyPojo.class);

Asynctask wont update array

I am having a problem accessing the arraylists populated by this asynctask from class file A. From Class file B I try to use A a method such as
inStream = new InboxLoader(MainInbox.this,1);
Log.e("JJJ",""+inStream.getMemId().size());
method from a different class file I get a crash in logcat saying indexoutofbounds error
I was looking for an alternative to having this AsyncTask in the same file as class B
public class InboxLoader {
Context ctx;
ArrayListmemName,memAvatar,msgBody,msgTime;
ArrayList msgId,memId;
InboxLoader(Context context,int id){
this.ctx = context;
this.msgBody = new ArrayList<String>();
this.memAvatar = new ArrayList<String>();
this.memId = new ArrayList<Integer>();
this.memName = new ArrayList<String>();
this.msgTime = new ArrayList<String>();
this.msgId = new ArrayList<Integer>();
new LoadStream().execute(id);
}
public ArrayList<String> getMsgBody(){
return msgBody;
}
public ArrayList<String> getMemAvatar(){
return memAvatar;
}
public ArrayList<Integer> getMemId(){
return memId;
}
public ArrayList<String> getMemName(){
return memName;
}
public ArrayList<Integer> getMsgId(){
return msgId;
}
public ArrayList<String> getMsgTime(){
return msgTime;
}
/*
* STARTS GRABBING DATA FOR THE LISTVIEW
*/
public class LoadStream extends AsyncTask<Integer, Integer, JSONObject> {
ProgressDialog progressBar;
#Override
protected void onPreExecute() {
progressBar = new ProgressDialog(ctx, ProgressDialog.STYLE_SPINNER);
progressBar.setMessage("Generating Inbox....");
progressBar.show();
super.onPreExecute();
}
#Override
protected JSONObject doInBackground(Integer... params) {
List<NameValuePair> params2 = new ArrayList<NameValuePair>();
params2.add(new BasicNameValuePair("memberId", String.valueOf(1)));
params2.add(new BasicNameValuePair("type", "get"));
JSONObject json = new jsonParser().makeRequest("url", params2);
return json;
}
#Override
protected void onPostExecute(JSONObject json) {
super.onPostExecute(json);
int success = 0;
JSONObject jData;
JSONArray jObj = null;
try{
// successfully received details
jObj = json.getJSONArray("details"); // JSON Array
success = json.getInt("success");
}catch(Exception e){
e.printStackTrace();
}
if(success == 1){
try{
for( int i = 0; i < jObj.length(); i++ ){
//GET OBJECT FROM JSON Array
jData = jObj.getJSONObject(i);
//ASSIGN VALUES
msgId.add(jData.getInt("msg_id"));
memAvatar.add(jData.getString("mem_avatar"));
memName.add(jData.getString("mem_name"));
memId.add(jData.getInt("mem_id"));
msgBody.add(jData.getString("msg_body"));
msgTime.add(jData.getString("msg_time"));
}
}catch(Exception e){
Log.e("STREAM FILE PROBLEM", e.getMessage());
}
}
progressBar.dismiss();
Log.e("STREAM FILE PROBLEM",""+memId.size());//prints 1
}
}
}
You are trying to read the ArrayList immediately after you start the AsyncTask, while the result will not be available until the doInBackground ends.
You should do what you want in onPostExecute to make sure the task executed all right.
Edited:
Define a listener like below:
public interface RequestListener {
public void onComplete(T response);
}
and the add a field requestListener in InboxLoader:
InboxLoader(Context context,int id, RequestListener li){
this.ctx = context;
this.msgBody = new ArrayList<String>();
this.memAvatar = new ArrayList<String>();
this.memId = new ArrayList<Integer>();
this.memName = new ArrayList<String>();
this.msgTime = new ArrayList<String>();
this.msgId = new ArrayList<Integer>();
this.requestListener = li;
new LoadStream().execute(id);
}
in the onPostExecute add this:
protected void onPostExecute(JSONObject json) {
super.onPostExecute(json);
int success = 0;
JSONObject jData;
JSONArray jObj = null;
try{
// successfully received details
jObj = json.getJSONArray("details"); // JSON Array
success = json.getInt("success");
if(requestListener!=null)
requestListener.onComplete();
}catch(Exception e){
e.printStackTrace();
}
Then you could process the result in onComplete define in your class B:
inStream = new InboxLoader(MainInbox.this,1, new RequestListener() {
public void onComplete(){
Log.e("JJJ",""+inStream.getMemId().size());
};
});

Why do I get a null pointer exception while issuing a HTTP request using AsyncTask in Android?

I'm trying to get scoreboards from FB, and to achieve this I issue a HTTP request to the API. It has to be done on a separate thread, here is my async task class:
public class AsyncBuildScoreboard extends AsyncTask<Void, Void,String> {
ProgressBar pb;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... voids) {
String token = Session.getActiveSession().getAccessToken();
try{
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("https://graph.facebook.com/"+GameStatic.app_id+"?fields=scores&access_token=" + token);
HttpResponse resp = client.execute(get);
HttpEntity responseEntity = resp.getEntity();
String response = EntityUtils.toString(responseEntity);
return response;
}
catch (IOException e)
{
}
return "";
}
protected void onPostExecute(String response) {
try{
JSONObject res = new JSONObject(response);
JSONObject scores = res.getJSONObject("scores");
JSONArray data = scores.getJSONArray("data");
int len = data.length();
String[] values = new String[len];
for(int i=0;i<len;i++)
{
JSONObject obj = data.getJSONObject(i);
JSONObject user = obj.getJSONObject("user");
String name = user.getString("name");
String score = obj.getString("score");
values[i] = name + " " + score;
GameStatic.scoreboard.add(values[i]);
}
}
catch (JSONException e)
{
}
}
}
GameStatic is an external variable to store what I get from thread. And yet, when doing this:
AsyncBuildScoreboard board = new AsyncBuildScoreboard ();
board.execute();
final ListView listview = (ListView) findViewById(R.id.scorelist);
final StableArrayAdapter adapter = new StableArrayAdapter(this,
android.R.layout.simple_list_item_1, GameStatic.scoreboard);
listview.setAdapter(adapter);
a null pointer exception occurs, which means, that the GameStatic.scoreboard has NOT been filled with the entries I wanted.
What am I doing wrong, any ideas?
I'd be obliged, since I am REALLY pressed on time...
public class AsyncBuildScoreboard extends AsyncTask<Void, Void, Void>
{
public ListView list;
public Context ctx;
public ArrayList<String> scoreboard = new ArrayList <String> ();
public AsyncBuildScoreboard(ListView list, Context context)
{
this.list = list;
this.ctx = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids)
{
Void nothing = null;
String token = Session.getActiveSession().getAccessToken();
try{
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("https://graph.facebook.com/"+GameStatic.app_id+"?fields=scores&access_token=" + token);
HttpResponse resp = client.execute(get);
HttpEntity responseEntity = resp.getEntity();
String response = EntityUtils.toString(responseEntity);
}
catch (IOException e)
{
}
return nothing;
}
protected void onPostExecute(String response) {
try{
JSONObject res = new JSONObject(response);
JSONObject scores = res.getJSONObject("scores");
JSONArray data = scores.getJSONArray("data");
int len = data.length();
String[] values = new String[len];
for(int i=0;i<len;i++)
{
JSONObject obj = data.getJSONObject(i);
JSONObject user = obj.getJSONObject("user");
String name = user.getString("name");
String score = obj.getString("score");
values[i] = name + " " + score;
scoreboard.add(values[i]);
}
}
catch (JSONException e)
{
}
final ArrayAdapter adapter = new ArrayAdapter(ctx,
android.R.layout.simple_list_item_1, scoreboard);
list.setAdapter(adapter);
}
}
you will need to use onPostExecute for showing the score when doInBackground execution complete instead of passing GameStatic.scoreboard just after AsyncTask.execute() because doInBackground always execute in separate thread so it.
you can use AsyncBuildScoreboard class constructor for passing ListView instance and Context from Activity as:
ListView listview;
Context context;
public AsyncBuildScoreboard(ListView listview,Context context){
this.context=context;
this.listview=listview;
}
....
protected void onPostExecute(String response) {
//...your code here..
StableArrayAdapter adapter = new StableArrayAdapter(context,
android.R.layout.simple_list_item_1, GameStatic.scoreboard);
listview.setAdapter(adapter);
}
and change your Activity code as for passing Context :
ListView listview = (ListView) findViewById(R.id.scorelist);
AsyncBuildScoreboard board = new AsyncBuildScoreboard (listview,
Your_Activity.this);
board.execute();
or you can also create callbacks methods using interface which fire when on UI Thread when doInBackground execution complete.see following post for more details:
android asynctask sending callbacks to ui

Android, synctask not showing the list after progressDialog

I was using AsyncTask to display data on a List, But the loading is visible, but it dosen't show the list..
public void getLocations(){
Connect client = new Connect(SERVICE_URI + "/GetLocations");
client.AddHeader("Accept", "application/json");
client.AddHeader("Content-Type", "application/json");
try {
client.Execute(RequestMethod.GET);
JSONObject rootJson = new JSONObject(client.getResponse());
JSONArray jsonArray = rootJson.getJSONArray("GetLocationsResult");
String[] names = null;
if (jsonArray != null) {
names = new String[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
names[i] = json.getString("Name");
}
}
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, names));
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public void getLocations(){
Connect client = new Connect(SERVICE_URI + "/GetLocations");
client.AddHeader("Accept", "application/json");
client.AddHeader("Content-Type", "application/json");
try {
client.Execute(RequestMethod.GET);
JSONObject rootJson = new JSONObject(client.getResponse());
JSONArray jsonArray = rootJson.getJSONArray("GetLocationsResult");
String[] names = null;
if (jsonArray != null) {
names = new String[jsonArray.length()];
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
names[i] = json.getString("Name");
}
}
setListAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, names));
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
If data for ListAdapter is collected in doInBackground() of AsyncTask, Activity onCreate() does not wait for AsyncTask to complete.
So what we have:
1. Activity Start
2. AsyncTask start
3. Activity trying to set ListAdapter - it's empty, because AsyncTask does not completed
4. AsyncTask completed - but ListAdapter filled with empty data
My solution: AsyncTask should notify ListAdapter of Activity after data loading completes:
Public class MyActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.myActivity);
ExpandableListView listView = (ExpandableListView) findViewById(R.id.expList);
//MyArrayList - data source for your list. For example, I use static ArrayList from other class. Replace with your data object.
final MyExpandableListAdapter adapter = new MyrExpandableListAdapter(getApplicationContext(), myArrayList);
listView.setAdapter(adapter);
int taskId=1; // type of task should be executed
MyAsyncTask myTask = new MyAsyncTask(taskId);
myTask.execute(adapter);
#Override
protected Dialog onCreateDialog(int id) {
ProgressDialog progress = null;
progress = new ProgressDialog(this);
//Should user work with app while data loading? In my case, no, so setCancelable=false
progress.setCancelable(false);
if (id==1) {
progress.setMessage("Getting locations, please wait...");
}
if (id==2) {
progress.setMessage("Task type #2 performing...");
}
return progress;
} // end onCreateDialog
class MyAsyncTask extends AsyncTask<Void, Void, Void> {
MyExpandableListAdapter adapter; //ExpandableListAdapter you wanna notify about data load completion
int taskId; //Type of tasks in your Activity. You have only one, however - getLocations().
MyAsyncTask(int taskId) {
//save task ID to use in doInBackground, showDialog and dismissDialog
this.taskId=taskId;
}
#Override
protected Void doInBackground(Void... params) {
if (taskId==1) {
// YOUR LONG-TIME TASK #1 THAT UPDATES DATA SOURCE FOR LIST ADAPTER GOES HERE;
}
if (taskId==2) {
// YOUR LONG-TIME TASK #2 THAT UPDATES DATA SOURCE FOR LIST ADAPTER GOES HERE;
// create more task types if needed
}
//this adapter will be used in onPostExecute() to notify Activity about data changes
adapter = (MyExpandableListAdapter) params[0];
return null;
}
#Override
protected void onPreExecute() {
//Show dialog for this task type. if need more than one - us switch here and in onCreateDialog,
// different dialog types for different tasks etc.
showDialog(taskId);
}
#Override
protected void onPostExecute(Void result) {
// IMPORTANT! Update data in Activity
adapter.notifyDataSetChanged();
dismissDialog(taskId);
}
} //end of AsyncTask
} //end of Activity class

Categories

Resources