Android progress dialog not showing in AsyncTask. Blocked UI? - android

I have an AsyncTask that I'm using to query the database and load a ListView using a custom cursor adapter. The task itself works, but I cannot get the progress dialog to show up.
The async task:
private class LoadListTaskByCursor extends AsyncTask<Void, Void, Cursor> {
private ProgressDialog progressDialog;
private String dictionary;
private Activity activity;
public LoadListTaskByCursor (Activity activity, String dictionary) {
progressDialog = new ProgressDialog(activity);
this.dictionary = dictionary;
this.activity = activity;
}
#Override
protected void onPreExecute() {
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
progressDialog.show();
}
#Override
protected void onPostExecute(Cursor result) {
ListView lv = (ListView) activity.findViewById(R.id.viewDictionaryList);
lv.setFastScrollEnabled(true);
lv.setAdapter(new CustomTermsCursorAdapter(activity,
R.layout.custom_term_item,
result,
new String[]{getString(R.string.KEY_ID), getString(R.string.KEY_TERM)},
new int[]{R.id.term_item}));
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Get the cursor, positioned to the corresponding row in the result set
Cursor cursor = (Cursor) parent.getItemAtPosition(position);
// Get the term id from this row in the database.
int termId = cursor.getInt(cursor.getColumnIndexOrThrow(getString(R.string.KEY_ID)));
Bundle bundle = new Bundle();
bundle.putInt("id", termId);
Fragment fragment = new ViewTermFragment();
fragment.setArguments(bundle);
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.add(R.id.container, fragment)
.addToBackStack(null)
.commit();
}
});
if(progressDialog.isShowing()) {
progressDialog.dismiss();
}
}
#Override
protected Cursor doInBackground(Void... params) {
Cursor cursor = null;
try {
// do the background process
cursor = db.getAllTermListItemsByDictionaryCursor(getString(R.string.TABLE_TERMS), dictionary);
} catch (Exception e) {
Log.e("tag", e.getMessage());
}
return cursor;
}
}
And I'm call the task from the fragment like this:
LoadListTaskByCursor loadListTaskByCursor = new LoadListTaskByCursor(getActivity(), dictionary);
loadListTaskByCursor.execute();
I've used a similar approach before with a custom array adapter instead of a cursor, and that worked fine. Can anyone tell me what I'm doing wrong? Thanks.

It turns out that my doInBackGround was actually running for a really short amount of time (since it is only returning a cursor) while my onPostExecute was taking really long (due to the setAdapter). The progress dialog was showing up and disappearing without me even noticing.
Thanks to everyone who commented, I appreciate it.

Related

Combine Activity and fragment into a class android

I want to ask,
I have 2 classes:
1. an activity class (to get data from json)
2. a fragment class (not to do something)
and I want to get data from json of activity via fragment class.
Can be combine Activity and Fragment in a class ? and how to do ?
I combined activity and fragment in a Fragment class, I have used a GridView to get data and display
JSON, execute the AsyncTask in the this Fragment
This is my code after updated 25/10:
public class FeedBackFragment extends Fragment {
ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();
MyAdapter adapter;
JSONArray manufacturers = null;
// manufacturers JSON url
private static final String URL_MANUFACTURERS ="MYURL";
public FeedBackFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.feedback_gridview_manufacturer, container, false);
GridView gridView = (GridView) view.findViewById(R.id.gridview);
gridView.setAdapter(new MyAdapter(getActivity(), manufacturersList));
gridView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
// on selecting a single manufacturer
// CategoryCarActivity will be launched to show category car inside the manufacturer
Intent i = new Intent(getActivity(), CategoryCarActivity.class);
// send manufacturer id to activity to get list of cars under that manufacturer
String manufacturer_id = ((TextView) view.findViewById(R.id.manufacturer_id)).getText().toString();
i.putExtra("manufacturer_id", manufacturer_id);
startActivity(i);
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
// manufacturersList = new ArrayList<>();
new LoadAllManufacturers().execute();
}
class LoadAllManufacturers extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* After completing background task Dismiss the progress dialog
* **/
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
adapter.notifyDataSetChanged();
// dismiss the dialog after getting all manufacturers
if (pDialog.isShowing())
pDialog.dismiss();
}
}
private class MyAdapter extends BaseAdapter
{
// List<POJOManufacturer> listData = null;
LayoutInflater inflater;
Context context;
public MyAdapter(Context context, ArrayList<HashMap<String, String>> arrayList)
{
// this.context = context;
this.manufacturersList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
if (manufacturersList != null)
return manufacturersList.size();
return 0;
}
#Override
public Object getItem(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i);
return null;
}
#Override
public long getItemId(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i).hashCode();
return 0;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup)
{
ViewHolder holder;
if (convertView == null)
{
convertView = inflater.inflate(R.layout.gridview_item, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.text);
holder.iconName = (ImageView) convertView.findViewById(R.id.picture);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(this.manufacturersList.get(i).getClass().getName());
// holder.iconName.setImageResource(this.manufacturersList.get(i).image);
return convertView;
}
public class ViewHolder
{
TextView name;
ImageView iconName;
}
}
}
I have updated and added: manufacturerList = new ArrayList<>. everything seem is better, and it happen some issues in getView() method,
I have try and it's only display with 7 empty items in gridview, and not display content and image
So How fill data from Adapter into Gridview?
constructor ManufacturerFragment in class ManufacturerFragment cannot be applied to given types;
gridView.setAdapter() takes an adapter, not a Fragment
And new ManufacturerFragment() doesn't accept an Context.
I am not really sure why you think you need to create a new ManufacturerFragment within the Fragment class you already are in. Did you mean to do gridView.setAdapter(new MyAdapter(getActivity()))?
Also, your manufacturersList needs to be loaded into that adapter, so you'll need to figure that out.
And you need to use getActivity() instead of getActivity().getApplicationContext() in most places.
Then, you should only call new LoadAllManufacturers().execute(); in either onCreateView or onActivityCreated, not both. Otherwise, you're running two AsyncTasks.
Then, onPostExecute already runs on the UI thread, no need to use getActivity().runOnUiThread(new Runnable() {...
Once you do figure out how to put that ArrayList into the Adapter class, you'll want to call adapter.notifyDataSetChanged() within onPostExecute to tell the adapter to refresh the data, thereby updating the GridView to display the data.

sqlite database and listview

Okay, I have searched threw here and did not find my answer at all. What my android app is suppose to be doing is get a list from my php & mysql server, then store it on the database on the phone. This all works, and I can even create a listview with the information from my sqlite db. Where I am stuck as a new coder is trying to figure out how to display the information when they click on the listview item that will take them to another page that will show all the details for that listview.
So in short what I want is have my listview, items 1,item 2, item 3 for example, then when they click item 2, it gets the information for item 2 and displays it. Can someone point me in the correct direction, i know i have to use setOnClickListener, but just unsure how to make it look for that certain item.
public class Events extends Activity
{
// Identifies a particular Loader being used in this component
String event_name, event_time, event_price, event_loc;
static JSONObject object =null;
DBAdapter myDb;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.events);
openDB();
new PrefetchData().execute();
// used to refresh my page.
Button button = (Button) findViewById(R.id.refresh);
button.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
openDB();
new PrefetchData().execute();
}
});
}
#Override
protected void onDestroy()
{
super.onDestroy();
closeDB();
}
private void openDB()
{
myDb = new DBAdapter(this);
myDb.open();
}
private void closeDB()
{
myDb.close();
}
private class PrefetchData extends AsyncTask<Void, Void, Void>
{
#Override
protected void onPreExecute()
{
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0)
{
myDb.deleteAll();
JsonParser jsonParser = new JsonParser();
String json = jsonParser.getJSONFromUrl("http://www.website.com/test.json");
Log.e("JSON Response: ", "> " + json);
if (json != null)
{
try
{
JSONObject parent = new JSONObject(json);
JSONArray eventDetails = parent.getJSONArray("event");
for(int i=0; i < eventDetails.length(); i++)
{
object = eventDetails.getJSONObject(i);
event_name = object.getString("event_name");
event_time = object.getString("event_time");
event_price = object.getString("event_price");
event_loc = object.getString("event_loc");
//event_pic = object.getString("event_pic");
myDb.insertRow(event_name,event_time,event_price,event_loc);
Log.e("JSON", "> " + event_name + event_time + event_price + event_loc );
}
} catch (JSONException e)
{
// TODO Auto-generated catch block
Log.e("Json Error", "Error: " + e.toString());
e.printStackTrace();
}
}
return null;
}
#Override
protected void onPostExecute(Void result)
{
super.onPostExecute(result);
populateListViewFromDB();
myDb.close();
// After completing http call
// will close this activity and lauch main activity
//Intent i = new Intent(MainActivity.this, Events.class);
//i.putExtra("event_name", event_name);
//i.putExtra("event_time", event_time);
//i.putExtra("event_price", event_price);
//startActivity(i);
// close this activity
//finish();
}
}
#SuppressWarnings("deprecation")
private void populateListViewFromDB()
{
Cursor cursor = myDb.getAllRows();
// Allow activity to manage lifetime of the cursor.
// DEPRECATED! Runs on the UI thread, OK for small/short queries.
startManagingCursor(cursor);
// Setup mapping from cursor to view fields:
String[] fromFieldNames = new String[]
{DBAdapter.KEY_NAME, DBAdapter.KEY_TIME, DBAdapter.KEY_PRICE, DBAdapter.KEY_LOC};
int[] toViewIDs = new int[]
{R.id.item_name};//, R.id.item_time};//, R.id.item_price, R.id.item_loc};
// Create adapter to may columns of the DB onto elemesnt in the UI.
SimpleCursorAdapter myCursorAdapter =
new SimpleCursorAdapter(
this, // Context
R.layout.item_layout, // Row layout template
cursor, // cursor (set of DB records to map)
fromFieldNames, // DB Column names
toViewIDs // View IDs to put information in
);
// Set the adapter for the list view
ListView myList = (ListView) findViewById(R.id.listViewfordb);
myList.setAdapter(myCursorAdapter);
}
}
Don't use the setOnClickListener.
Be sure to use a CursorAdapter and to specify an ID column inside your db.
when you set the protected void onListItemClick(ListView l, View v, int position, long id) automatically the id is the ID inside the db. this way you can pass it through an intent and use the id to get back the data from the db.
Hope it's clear enough. Sorry i wrote quite in a rush
from your code simply add
myList.setOnItemClickListener(
new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long id) {
//here the id value is what you need to take data from the db filtering by id
}
}
);
you should set listeners to your ListView something like this
private OnItemClickListener onListItemClickListener = new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position, long id) {
// TODO YOUR CODE
}
};
private OnItemLongClickListener onItemLongClickListener = new OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapter, View view, int position, long id) {
YOUR_CODE
}
};
those are two types, longClicj and just click, you can use it both or one, its depends on your needs
also on your onCreate method you should set the listeners to your listView
listView.setOnItemClickListener(onListItemClickListener);
listView.setOnItemLongClickListener(onItemLongClickListener);

Error in Listview update always stops

i have this listview update:
timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
display.elemek.clear();
em1.new AsyncEmBase().execute();
}
}, 0, 1000);
public class AsyncEmBase extends AsyncTask<Void, ListView, Void> {
protected void onPreExecute() {
// display.dataAdapter.clear();
}
#Override
protected Void doInBackground(Void... params) {
readInputRegisters(); /*this only makes display.elemek.add("SomeString")*/
return null;
}
protected void onPostExecute(Void unsed) {
if (display.dataAdapter == null) {
display.dataAdapter = new ArrayAdapter<String>(
display.activity, android.R.layout.simple_list_item_1,
display.elemek);
display.lv.setAdapter(display.dataAdapter);
} else {
display.dataAdapter.notifyDataSetChanged();
}
}
}
it runs smootly but after a while it stops and says:
11-27 15:21:05.769: E/AndroidRuntime(17991): java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296261, class android.widget.ListView) with Adapter(class android.widget.ArrayAdapter)]
i have tried everithing to update the listview but nothing is good.
Please help me!
edit1: new error: Invalid index 7, size is 0
But i clear the elemek arraylist before starting to insert the datas
display.java:
public class display extends Fragment {
public static TextView ain1, ain2, ain3, ain4, dout1, dout2, din1, din2,
din3, din4, cin1, cin2, cin3, cin4, k1, k2, k3, k4, k5, k6, k7, k8;
public static Activity activity;
public static ListView lv;
public static ArrayList<String> elemek;
public static ArrayAdapter<String> dataAdapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.display, container, false);
ain1 = (TextView) rootView.findViewById(R.id.textView2);
activity = getActivity();
lv = (ListView) rootView.findViewById(R.id.listView1);
elemek = new ArrayList<String>();
return rootView;
}
display.activity.runOnUiThread(...) is useless because onPostExecute() is already executed inside the UI thread
and I don't think you have to call notifyDataSetChanged() because you're setting the adapter just before.
Remove all your Thread because you dont need uiThread in onPostExecute() and add like this :
if ( display.dataAdapter == null) {
display.dataAdapter = new ArrayAdapter<String>(
display.activity,
android.R.layout.simple_list_item_1, display.elemek);
display.lv.setAdapter(display.dataAdapter);
}else{
display.dataAdapter.notifyDataSetChanged();
}

Navigate to different pages when a certain LISTVIEW is clicked

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

ArrayAdapter in Fragment

I'm beginner in Android Development!
I'm trying insert into Fragment parsing data
Trying to fix error but I have an error "
output cannot be resolved to a variable"
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
ProgressDialog mProgressDialog = new ProgressDialog(getActivity());
mProgressDialog.setCancelable(false);
mProgressDialog.setCanceledOnTouchOutside(false);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setMessage("Загрузка данных");
mProgressDialog.show();
new ParseSite().execute("http://www.babyblog.ru/magazine/");
View view = inflater.inflate(R.layout.magazine, container, false);
ListView listview = (ListView) view.findViewById(R.id.listViewData);
listview.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_1 , output));
return view;
}
private class ParseSite extends AsyncTask<String, Void, List<String>> {
protected List<String> doInBackground(String... arg) {
List<String> output = new ArrayList<String>();
try
{
HtmlHelper hh = new HtmlHelper(new URL(arg[0]));
List<TagNode> links = hh.getLinksByClass("razdel-name");
for (Iterator<TagNode> iterator = links.iterator(); iterator.hasNext();)
{
TagNode divElement = (TagNode) iterator.next();
output.add(divElement.getText().toString());
}
}
catch(Exception e)
{
e.printStackTrace();
}
return output;
}
}
}
The variable 'output' has not been defined.
i.e.
listview.setAdapter(new ArrayAdapter<String>(getActivity().getApplicationContext(),
android.R.layout.simple_list_item_1 , output));
That variable is not in scope.
You attemot to use it in onCreate of your fragment, but it is declared in the ASyncTask class.
You need to go and read about ASyncTasks and how you work with them.
http://developer.android.com/guide/components/processes-and-threads.html#WorkerThreads
as a shortcut, try this:
public class YourFragment extends Fragment {
ListView listview;
#Override
public View onCreateView(
// other stuff
listview = (ListView) view.findViewById(R.id.listViewData);
// remove the setAdapater line
}
private class ParseSite extends AsyncTask<String, Void, List<String>> {
// other stuff
protected void onPostExecute(List<String> result) {
listview.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1 , output));
}
}
Your output variable is still null. You have to implement onPostExecute(List result) in your AsyncTask.
This will give you the output you want.
this blogpost can explain how AsyncTask works. But be careful, AsyncTask has a couple of hidden pitfalls. Read all about that here

Categories

Resources