When I ran my code I always get a log about Skipped 303 frames! The application may be doing too much work on its main thread. How to implement AsyncTask in this code below, and how to show a progressbar, while fetching data from one of my Parse.com's database. I would appreciate any help.
Here is my Activity's code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_doctors_name_list);
Bundle extras = getIntent().getExtras();
final String key = extras.getString("KEY");
ListView lvDoctorsName = (ListView) findViewById(R.id.lvDoctorsName);
ParseQueryAdapter.QueryFactory<ParseObject> factory = new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("doctors");
query.whereContains("name", key);
return query;
}
};
CustomLayout urgentAdapter = new CustomLayout(this, factory);
lvDoctorsName.setAdapter(urgentAdapter);
TextView empty = (TextView) findViewById(R.id.empty_list_item);
lvDoctorsName.setEmptyView(empty);
itemClickListener();
}
public void itemClickListener() {
ListView lvDoctorsName = (ListView) findViewById(R.id.lvDoctorsName);
lvDoctorsName.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ParseObject item = (ParseObject) parent.getAdapter().getItem(position);
String objectID = item.getObjectId().toString();
Intent i = new Intent();
i.setClass(getApplicationContext(), DoctorPage.class);
//i.putExtra("new_variable_name",value);
i.putExtra("objectID", objectID);
startActivity(i);
}
});
}
And here my custom layout:
public class CustomLayout extends ParseQueryAdapter<ParseObject> {
public CustomLayout(Context context, QueryFactory<ParseObject> queryFactory) {
super(context, queryFactory);
}
#Override
public View getItemView(ParseObject object, View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(), R.layout.row, null);
}
super.getItemView(object, v, parent);
TextView titleTextView = (TextView) v.findViewById(R.id.text1);
titleTextView.setText(object.getString("name"));
TextView titleTextView2 = (TextView) v.findViewById(R.id.text2);
titleTextView2.setText(object.getString("city"));
return v;
}
One problem I see is that you are calling findViewById() every time getItemView() is called; findViewById() is an expensive operation. You should implement something like the ViewHolder pattern to avoid this.
By the looks of the Parse documentation they take care of the AsyncTask for you. So that's not the problem.
Depending on the size of your data set, Emmanuel's answer with findViewById is correct.
To answer how to show a progress bar you can read the documentation on the ParseQueryAdapter, which lets you hook into loading / done loading triggers.
https://parse.com/docs/android/api/com/parse/ParseQueryAdapter.html
// Perhaps set a callback to be fired upon successful loading of a new set of ParseObjects.
adapter.addOnQueryLoadListener(new OnQueryLoadListener<ParseObject>() {
public void onLoading() {
// Trigger any "loading" UI
}
public void onLoaded(List<ParseObject> objects, ParseException e) {
// Execute any post-loading logic, hide "loading" UI
}
});
Related
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.
I am struggling with a very weird Parse (Parse.com) problem:
When I use the usual list.setAdapter(Adapter);, I get the Error: "This query has an outstanding network connection. You have to wait until it's done."
Here is my code:
private ParseQueryAdapter<ParseObject> Adapter;
private CommentListAdapter CommentListAdapter;
Adapter = new ParseQueryAdapter<ParseObject>(this, "Activity");
Adapter.setTextKey("title");
// Initialize the subclass of ParseQueryAdapter
CommentListAdapter = new CommentListAdapter(this);
// Initialize ListView and set initial view to Adapter
CommentList.setAdapter(Adapter);
Adapter.loadObjects();
if (CommentList.getAdapter() == Adapter) {
CommentList.setAdapter(CommentListAdapter);
CommentListAdapter.loadObjects();
}else{
CommentList.setAdapter(Adapter);
Adapter.loadObjects();
}
I get the error at "CommentList.setAdapter(Adapter);"
Here is my Adapter:
public class CommentListAdapter extends ParseQueryAdapter<ParseObject> {
private List<String> itemList;
private Context context;
public ParseImageView thumbnailFile;
public TextView UsernameView;
public TextView Comments;
public CommentListAdapter(Context context) {
// Use the QueryFactory to construct a PQA that will only show
// Todos marked as high-pri
super(context, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("Activity");
query.whereEqualTo("photoId", CommentActivity.getPhoto());
query.whereEqualTo("type", "comment");
query.orderByAscending("created_at");
Log.e("Log", "Query: " + query.countInBackground().toString());
return query;
}
});
}
// Customize the layout by overriding getItemView
#Override
public View getItemView(ParseObject object, View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(), R.layout.comment_list_items, null);
}
super.getItemView(object, v, parent);
Log.e("Log", "Comment: " + object.toString());
thumbnailFile = (ParseImageView) v.findViewById(R.id.user_thumbnail);
UsernameView = (TextView) v.findViewById(R.id.user_name);
Comments = (TextView) v.findViewById(R.id.comment);
String Content = object.toString();
Comments.setText(Content);
return v;
}
}
Please help me, this kind of error should occur in such a case, I don't know what to do..
If you need more of my code, just tell me.
Updated code; however I am still getting no results when running the app.
I am using ParseQueryAdapter; I am querying the user, so am using ParseUser; it seems the first part is a query for all users of type midwife, then getting specific types of data I want, setting them to the TextViews
public class CustomMidwifeAdapter extends ParseQueryAdapter<ParseUser> {
public CustomMidwifeAdapter(Context context) {
// Use the QueryFactory to construct a PQA that will only show
// Todos marked as high-pri
super(context, new ParseQueryAdapter.QueryFactory<ParseUser>() {
public ParseQuery create() {
ParseQuery<ParseUser> query = new ParseQuery<ParseUser>("userType");
query.whereEqualTo("userType", "midwife");
query.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> parseUsers, ParseException e) {
if (e == null ) {
//query was successful
}
else {
//Something went wrong
}
}
});
return query;
}
});
}
public View getItemView(ParseUser object, View view, ViewGroup parent) {
if (view == null) {
view = View.inflate(getContext(), R.layout.activity_midwife_result_list, null);
}
super.getItemView(object, view, parent);
// Add the practicename view
TextView titleTextView = (TextView) view.findViewById(R.id.practicename);
titleTextView.setText(object.getString("practicename"));
// Add education view
TextView EducationView = (TextView) view.findViewById(R.id.education);
EducationView.setText(object.getString("education"));
// Add yearsexperience view
TextView ExperienceView = (TextView) view.findViewById(R.id.yearsinpractice);
ExperienceView.setText(object.getString("yearsinpractice"));
//Add practice philosophy view
TextView PracticePhilosophyView = (TextView) view.findViewById(R.id.practicephilosophy);
PracticePhilosophyView.setText(object.getString("practicephilosophy"));
return view;
}
}
Here is the activity
public class MidwifeResultList extends Activity {
private ParseQueryAdapter<ParseObject> mainAdapter;
private CustomMidwifeAdapter midwifeListAdapter;
private ListView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_list)
//initialize main ParseQueryAdapter
mainAdapter = new ParseQueryAdapter<ParseObject>(this, "userType");
mainAdapter.setTextKey("practicename");
mainAdapter.setTextKey("education");
mainAdapter.setTextKey("yearsinpractice");
mainAdapter.setTextKey("practicephilosophy");
// Initialize the subclass of ParseQueryAdapter
midwifeListAdapter = new CustomMidwifeAdapter(this);
// Initialize ListView and set initial view to mainAdapter
listView = (ListView) findViewById(R.id.lvMidwives);
listView.setAdapter(mainAdapter);
mainAdapter.loadObjects();
}
I've checked my listview, and the id's seem to be correct. This is based on this example: https://parse.com/tutorials/parse-query-adapter
With the following code I'm correctly receiving a dynamic list from mysql db and putting the elements in a listview.
public class MenuActivity extends ListActivity implements FetchDataListener {
private ProgressDialog dialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
initView();
}
private void initView() {
// show progress dialog
dialog = ProgressDialog.show(this, "", "Loading..");
String url = "http://www.*********.php";
FetchDataTask task = new FetchDataTask(this);
task.execute(url);
}
#Override
public void onFetchComplete(List<Application> data) {
// dismiss the progress dialog
if(dialog != null) dialog.dismiss();
// create new adapter
ApplicationAdapter adapter = new ApplicationAdapter(this, data);
// set the adapter to list
setListAdapter(adapter);
}
#Override
public void onFetchFailure(String msg) {
// dismiss the progress dialog
if(dialog != null) dialog.dismiss();
// show failure message
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
This is my array adapter:
public class ApplicationAdapter extends ArrayAdapter<Application>{
private List<Application> items;
public ApplicationAdapter(Context context, List<Application> items) {
super(context, R.layout.app_cat_list, items);
this.items = items;
}
#Override
public int getCount() {
return items.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if(v == null) {
LayoutInflater li = LayoutInflater.from(getContext());
v = li.inflate(R.layout.app_cat_list, null);
}
Application app = items.get(position);
if(app != null) {
TextView titleText = (TextView)v.findViewById(R.id.titleTxt);
if(titleText != null) titleText.setText(app.getTitle());
}
return v;
}
Now I want to click on single row and open another activity passing some values via intent extra.
Where should I implement click listener?
I'm pretty sure it should be inserted in the "getView" but how I pass the app.getTitle() via intent? I know how pass intent extra in general, tried but no click happens.
Any help would be appreciated, thanks
Now I want to click on single row and open another activity passing
some values via intent extra. Where should I implement click listener?
No need to add OnItemClickListener because extending ListActivity in MenuActivity so just override onListItemClick method for handing ListView row click:
#Override
public void onListItemClick(ListView l, View view, int position, long id) {
// your code here...
}
how I pass the app.getTitle() via intent?
Get selected row TextView value in onListItemClick using view parameter:
TextView txtView=(TextView)v.findViewById(R.id.titleTxt);
String selectedText=txtView.getText().toString();
Use selectedText for sending value with Intent in Next Activity
Put this in your getView()
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent =new Intent(context, YourActivity.class);
context.startActivity(intent);
}
});
There can be multiple ways and following is one of them:
Set onItemClickListner on your listview in your activity and it will give you a callback i.e onListItemClick. But as you said you want the title their you have to set tag on the convertView in the getView method like covertView.setTag("itemTitle"); and in your onListItemClick get the tag from view and convert it to the title like this v.getTag().toString(); and set it any where you want.
follwoing is the full code:
#Override
public void onListItemClick(ListView l, View view, int position, long id) {
String title = view.getTag().toString();
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("title", title);
startActivity(intent);
// your code here... }
Please post if got stuck anywhere.
I'm trying to display the username and a photo in a a list view using the ParseQueryAdapter. I have the classes: User and Post.
I set it up here:
String[] postsObjectIds = some_string_array
ParseQueryAdapter<Post> adapter = new ParseQueryAdapter<Post>(getActivity(), new ParseQueryAdapter.QueryFactory<Post>() {
public ParseQuery<Post> create() {
ParseQuery<Post> query = Post.getQuery();
query.include("User");
query.whereContainedIn("objectId", Arrays.asList(postsObjectIds));
return query;
}
});
adapter.setTextKey("username");
adapter.setImageKey("photo");
adapter.setPlaceholder(getResources().getDrawable(R.drawable.some_drawable));
ListView listView = (ListView) rootView.findViewById(R.id.post_list_view);
listView.setAdapter(adapter);
The Post class has a column called photo and the User class has a column called username. The list view isn't displaying the username.
Do I have to implement a custom adapter?
Is there a quick fix?
I found an answer on the Parse Help Forum:
ParseQueryAdapter setTextKey for relational object
The accepted answer says to use a custom ParseQueryAdapter<T> and Override the getItemView.
For example, in my Fragment's onCreateView method, I initialized the adapter and set it (postsObjectIds is some String[]):
PostViewListViewAdapter adapter = new PostViewListViewAdapter(getActivity(), postsObjectIds);
ListView listView = (ListView) rootView.findViewById(R.id.post_list_view);
listView.setAdapter(adapter);
Here's my adapter (PostViewListViewAdapter):
public class PostViewListViewAdapter extends ParseQueryAdapter<Post> {
private final String[] mPostsObjectIds;
public PostViewListViewAdapter(Context context, final String[] postsObjectIds) {
super(context, new ParseQueryAdapter.QueryFactory<Post>(){
public ParseQuery<Post> create() {
ParseQuery<Post> query = Post.getQuery();
query.include("User");
query.whereContainedIn("objectId", Arrays.asList(postsObjectIds));
return query;
}
});
this.mPostsObjectIds = postsObjectIds;
}
#Override
public View getItemView(Post post, View v, ViewGroup parent) {
if(v == null) {
v = View.inflate(getContext(), R.layout.list_item_post_view, null);
}
super.getItemView(post, v, parent);
final TextView usernameTextView = (TextView) v.findViewById(R.id.username_text_view);
post.getCreator().fetchIfNeededInBackground(new GetCallback<ParseUser>() {
#Override
public void done(ParseUser user, ParseException e) {
usernameTextView.setText(user.getUsername());
}
});
return v;
}
}