I have AsyncTask class called LoadXMLData, and as you can see I parse XML data in doInBackground() method.
public class LoadXMLData extends AsyncTask<String, RSSFeed, RSSFeed>{
public static final int DIALOG_DOWNLOAD_PROGRESS = 0;
private ProgressDialog mProgressDialog;
private Context context;
RSSFeed feed;
public LoadXMLData(Context context) {
this.context = context;
mProgressDialog = new ProgressDialog(context);
mProgressDialog.setMessage("Molimo Vas, sačekajte. Podaci se učitavaju.");
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.show();
Log.d("OVDE SAM:", "onPreExecute()");
}
#Override
protected RSSFeed doInBackground(String... urls) {
// Obtain feed
DOMParser myParser = new DOMParser();
feed = myParser.parseXml(urls[0]);
Log.d("OVDE SAM:", "PARSIRAM XML");
return feed;
}
#Override
protected void onPostExecute(RSSFeed result) {
mProgressDialog.dismiss();
super.onPostExecute(result);
}
}
And I have few fragments, where I need to get data from that AsyncTask. How I could do that?
Here is the code of an fragment called NajnovijeFragment.
public class NajnovijeFragment extends Fragment{
GridView lv;
RSSFeed feed;
CustomListAdapter adapter;
private String RSSFEEDURL = "http://balkanandroid.com/feed/";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_najnovije, container,
false);
lv = (GridView) view.findViewById(R.id.GridView1);
// Set an Adapter to the ListView
adapter = new CustomListAdapter();
lv.setAdapter(adapter);
// Set on item click listener to the ListView
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// actions to be performed when a list item clicked
int pos = arg2;
Bundle bundle = new Bundle();
bundle.putSerializable("feed", feed);
Intent intent = new Intent(getActivity(), DetailsActivity.class);
intent.putExtras(bundle);
intent.putExtra("pos", pos);
startActivity(intent);
}
});
return view;
}
#Override
public void onDestroy() {
super.onDestroy();
adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();
}
class CustomListAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
public ImageLoader imageLoader;
public CustomListAdapter() {
layoutInflater = (LayoutInflater) getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(getActivity().getApplicationContext());
}
public int getCount() {
// TODO Auto-generated method stub
// Set the total list item count
return feed.getItemCount();
}
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
// Inflate the item layout and set the views
View listItem = convertView;
int pos = position;
if (listItem == null) {
listItem = layoutInflater.inflate(R.layout.list_item, null);
}
// Initialize the views in the layout
ImageView iv = (ImageView) listItem.findViewById(R.id.thumb);
TextView tvTitle = (TextView) listItem.findViewById(R.id.title);
TextView tvDate = (TextView) listItem.findViewById(R.id.tvDate);
// Set the views in the layout
imageLoader.DisplayImage(feed.getItem(pos).getImage(), iv);
tvTitle.setText(feed.getItem(pos).getTitle());
tvDate.setText(feed.getItem(pos).getDate());
return listItem;
}
}
}
The easiest way to get data from an ASyncTask is by implementing a callback.
Create an Interface:
public interface OnXMLLoadFinishedListener {
public void onXMLDataReady(RSSFeed results);
}
In you LoadXMLData:
private OnXMLLoadFinishedListener listener;
public void setOnXMLLoadFinishedListener(OnXMLLoadFinishedListener listener){
this.listener = listener;
}
#Override
protected void onPostExecute(RSSFeed result) {
super.onPostExecute(result);
listener.onXMLDataReady(RSSFeed results);
}
In your Fragment:
public class NajnovijeFragment extends Fragment implements OnXMLLoadFinishedListener{
and override onXMLDataReady:
#override
public void onXMLDataReady(RSSFeed results){
//display your data.
}
Make sure that when you create your AsyncTask instance you set the listener otherwise this will not work:
LoadXMLData xmlLoader = new LoadXMLData();
xmlLoader.setOnXMLLoadFinishedListener(this);
Your AsyncTask already knows context, so you could call back into your activity (called ActivityMain for illustrative purposes) in onPostExecute. e.g.
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
((ActivityMain) context).loadCompleteHandler(param1,param2,...)
}
It's then up to you how you want to implement loadCompleteHandler in your activity. Now your activity might not exist, so you must be careful to cancel the AsyncTask when the activity is removed. Fragments belonging to an activity can also access the activity.
AsyncTask is a Class that is very related to the UI, if you need to update the UI with this XML parsing you should take this consideration:
Make the asynctask an inner class in your fragment or
Pass the fragment to your asynctask
Update the fragment's view in onPostExecute()
In any case you should check if your activity is null, if so... avoid updating views, something like that:
onPostExecute(Object xml) {
if(getActivity != null) {
// update Views like...
textViewLabel.setText(parsedXml.getTitle);
}
}
I would suggest you to use SafeAsyncTask, which is a java class from the Roboguice Project, only one file, and it is related to java.util.concurrent.Callable, just copy and paste the source:
SafeAsyncTask.java
How to use it!
Related
This question already has answers here:
how to refresh custom listview using baseadapter in android
(5 answers)
Closed 8 years ago.
I have application this application contain listview , Listview retrieve data from local database sqlite , by using adapter this is my Adapter class code :
public class CommandsListAdapter extends BaseAdapter {
public static String ID = null;
private List<String> data;
ArrayList<HashMap<String, String>> commandList = new ArrayList<HashMap<String, String>>();
private ArrayAdapter<String> listAdapter;
Context context;
public CommandsListAdapter(Context con,
ArrayList<HashMap<String, String>> list) {
commandList = list;
context = con;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return commandList.size();
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return commandList.get(arg0);
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
#Override
public View getView(final int index, View convertView, ViewGroup arg2) {
// TODO Auto-generated method stub
if (convertView == null) {
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
convertView = mInflater.inflate(R.layout.people_list, null);
}
TextView tvTime = (TextView) convertView.findViewById(R.id.timeOfBlock);
TextView tvName = (TextView) convertView.findViewById(R.id.name);
tvName.setText(commandList.get(index).get(MyDatabase.Number_Block));
tvTime.setText(commandList.get(index).get(MyDatabase.Time_Of_Block));
Typeface tf = Typeface.createFromAsset(context.getAssets(),
"segoeuil.ttf");
tvTime.setTypeface(tf);
tvName.setTypeface(tf);
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Message.message(context,
// commandList.get(index).get(MyDatabase.Block_Table_Id));
Intent i = new Intent(context, MessageDetail.class);
i.putExtra(ID,
commandList.get(index).get(MyDatabase.Block_Table_Id)
.toString());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(i);
}
});
convertView.setOnLongClickListener(new OnLongClickListener() {
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
ID=commandList.get(index).get(MyDatabase.Block_Table_Id);
removeListItem(v, index);
return false;
}
});
return convertView;
}
protected void removeListItem(View rowView, final int positon) {
final Animation animation = AnimationUtils.loadAnimation(
context, android.R.anim.slide_out_right);
rowView.startAnimation(animation);
Handler handle = new Handler();
handle.postDelayed(new Runnable() {
#Override
public void run() {
commandList.remove(positon);
MyDatabase db=new MyDatabase(context);
db.open();
// db.deleteBlock(ID);
db.close();
Message.message(context, ID);
}
}, 1000);
}
}
and this is my Activity Class code :
public class ListOfBlock extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_of_block);
ActionBar actionBar = getActionBar();
// for color
actionBar.setBackgroundDrawable(new ColorDrawable(Color
.parseColor("#a20000")));
if (actionBar != null) {
actionBar.setTitle(getResources().getString(
R.string.title_activity_list_of_block));
actionBar.setDisplayHomeAsUpEnabled(true);
// actionBar.setIcon(R.drawable.ic_launcher);
}
ListView lvCommands = (ListView) findViewById(R.id.ListOfBlockerListView);
lvCommands.setAdapter(new CommandsListAdapter(getApplicationContext(),
new MyDatabase(getApplicationContext()).getBlockers()));
}
}
now I want to refresh the listview within getview method , I don't know how to do this , and I found some answer but really this is not helped me , thanks for any help .
YourActivity.this.recreate();
This will recreate your list. Keep a variable say n=false in the actvity where you perfom those operations. Then when you call back the activity with list, just pass this as true.
In the activiy where you perfom those operations,
Intent i = new Intent(Operations.this,ListActivity.class);
ListActivity.n=true;
startActivity(i);
In onCreate of ListActivity create a class variable boolean n=false;
if(n){
ListActivity.this.recreate();
}
Hope it helps. Cheers!
I hope this is help you , within the class adapter do this :-
ArrayList<HashMap<String, String>> commandList = new ArrayList<HashMap<String, String>>();
private ArrayList<HashMap<String, String>> searchArrayList;
public CommandsListAdapter(Context con,
ArrayList<HashMap<String, String>> list) {
commandList = list;
context = con;
searchArrayList=list;
}
and create a function for update your listview like this , also within Adapter Class :-
public void updateResults(ArrayList<HashMap<String, String>> results) {
searchArrayList = results;
//Triggers the list update
notifyDataSetChanged();
}
and any where you want to update your listview call this function , and I did this for you Sister , like this :-
updateResults(commandList);
one thing for sure these codes above this is all your code but I made some modify , and the parameter of updateResults function commandList this is your ArrayAdapter you defined already .
I hope this is work
Simply calling notifyDataSetChanged() of BaseAdapter class refresh the list view items. Call it appropriately based upon your requirement.
Cheers.
I have a fragment and I am setting listview on fragment.
Following is the code:
public class AttachmentsFragment extends Fragment {
ListView lstView = null;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
}
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//retains fragment instance across Activity re-creation
setRetainInstance(true);
objects = new ArrayList<AttachModel>();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = null;
view = inflater.inflate(R.layout.tab_attachment, container, false);
lstView = (ListView) view.findViewById(R.id.listViewAttachment);
adapter = new AttachAdapter(getActivity(), 0, 0, objects);
lstView.setAdapter(adapter);
return view;
}
}
In the adapter I have a progress bar and a textview to show the progress of the progress bar. A button to start and stop the progress bar
public class AttachAdapter extends ArrayAdapter<AttachModel> implements OnClickListener {
Context context;
ArrayList<AttachModel> objects = new ArrayList<AttachModel>();
AttachModel info;
//Activity act;
AttachModel model;
public AttachmentsAdapter(Context context, int resource,
int textViewResourceId, ArrayList<AttachmentsModel> objects) {
super(context, textViewResourceId, textViewResourceId, objects);
this.context = context;
this.objects = objects;
}
// no. of attachments available
#Override
public int getCount() {
return objects.size();
}
#Override
public AttachmentsModel getItem(int position) {
return objects.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View row = convertView;
ViewHolder holder = null;
if(null == row) {
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.attachment_list_item, parent, false);
//textview for showing progress
holder.textViewProgress = (TextView) row.findViewById(R.id.txtViewPg);
//progress bar to show the progress
holder.progressBar = (ProgressBar) row.findViewById(R.id.pgBar);
holder.progressBar.setTag(position);
holder.textViewProgress.setVisibility(TextView.VISIBLE);
holder.img_view_fileIcon.setVisibility(ImageView.VISIBLE);
holder.progressBar.setVisibility(ProgressBar.VISIBLE);
//to start stop the progress bar
holder.button = (Button)row.findViewById(R.id.img_btn_download);
holder.button.setVisibility(Button.VISIBLE);
holder.button.setTag(position);
holder.button.setOnClickListener(this);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}
return row;
}
private class ViewHolder {
TextView textViewProgress;
ProgressBar progressBar;
Button button;
boolean downloadFlag = false;
}
#Override
public void onClick(View v) {
View vParent=(View) v.getParent();
ViewHolder tempHolder = null;
tempHolder=(ViewHolder) vParent.getTag();
//toggle button like functionality
if(!tempHolder.downloadFlag) {
tempHolder.downloadFlag = true;
tempHolder.progressBarStatus = 0;
async = new AsyncTaskAttachments(tempHolder, objects.get(Integer.parseInt(v.getTag().toString())).getFilePath());
tempHolder.async.execute();
objects.get((Integer)tempHolder.progressBar.getTag()).setAsyncTask(tempHolder.async);
}else {
tempHolder.downloadFlag = false;
tempHolder.progressBar.setProgress(0);
tempHolder.textViewProgress.setVisibility(TextView.GONE);
tempHolder.textViewProgress.setText("");
tempHolder.progressBarStatus = 0;
tempHolder.async.cancel(true);
}
}
public class AsyncTaskAttachments extends AsyncTask<Void, Void, Void> {
private ViewHolder holder;
public AsyncTaskAttachments(ViewHolder holder, String filePath) {
this.holder = holder;
this.filePath = filePath;
}
public void attach(Activity act) {
this.act = act;
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
holder.progressBarStatus = 0;
for(int i=0; i<=10; i++) {
try {
Thread.sleep(1000);
holder.progressBarStatus = i*10;
if(isCancelled()) {
break;
}
publishProgress();
}catch (Exception e) {
// TODO: handle exception
}
}
return null;
}
/* (non-Javadoc)
* #see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
/* (non-Javadoc)
* #see android.os.AsyncTask#onPreExecute()
*/
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
holder.progressBarStatus = 0;
holder.textViewProgress.setText("" + holder.progressBarStatus + "%");
holder.progressBar.setProgress(holder.progressBarStatus);
}
/* (non-Javadoc)
* #see android.os.AsyncTask#onProgressUpdate(Progress[])
*/
#Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
// TODO Auto-generated method stub
holder.progressBar.setProgress(holder.progressBarStatus);
holder.textViewProgress.setText("" + holder.progressBarStatus + "%");
}
}
}
Note: This is just to show the way I am doing it. This is just a glimpse. I need to know whether I am on the right track or not.
On Orientation change, the progress bar is not able to retain and start the progress from where the orientation change.
Thanks in advance
When orientation changes, your activity (and fragments in contains) are re-created. So You call your asyncTask again and it's setting progress to zero:
holder.progressBarStatus = 0;
Solution: save progress in fragment's onSaveInstanceState(), resotre in onCreateView() ans make asyncTask use this value for initial progress setting.
I know this question is old and it's been answered, so just for the record: you can keep the state of a progress bar after orientation change with a viewmodel. I had a progress bar in a fragment and the progress bar was activated upon pressing a button. The trick is setting a variable in the viewmodel when the progress bar is activated and reading this variable in the onCreatView method of the fragment. This way, the progress bar will continue doing the same thing it did before orientation change (spinning / not spinning). This can be applied to other situations with modifications.
Viewmodel:
// create livedata variable
private final MutableLiveData<Boolean> mIsProgressBarActive = new MutableLiveData<>();
// get status from viewmodel
public LiveData<Boolean> getProgressBarStatus() {return mIsProgressBarActive; }
// save status to viewmodel
public void setProgressBarStatus(boolean status) {
mIsProgressBarActive.postValue(status);
}
Fragment onCreate:
super.onCreate(savedInstanceState);
mViewModel = ViewModelProviders.of(getActivity()).get(yourViewModel.class);
Fragment onCreateview:
View content = inflater.inflate(R.layout.your_fragment, container, false);
ProgressBar progressBar = content.findViewById(R.id.progressbar);
// if it was spinning, keep progress bar spinning after orientation change
if(mViewModel.getProgressBarStatus().getValue()) {
progressBar.setIndeterminate(true);
}
// activate progress bar and save its state to viewmodel
mButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
progressBar.setIndeterminate(true);
mViewModel.setProgressBarStatus(true);
}
});
Xml layout:
<ProgressBar
android:id="#+id/progressbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"/>
Its done.. For all those who are facing this problem or will face this in the future.
Do not try to recreate the view.
Just inflate your listview once in the onCreate() method.
Because, the oncreate and ondestroy methods are called only once when the fragment is retained. So inorder to maintain the state of the progress bar, put the code in the oncreate method.
I am making some RSS reader for some website, so I wanted to implement actionbar and viewpager on lower versions of Androd that 4.0, so I am using ActionBarSherlock and ViewPagerIndicator from Jake Wharton, so I am working with fragments.
And I want to read some RSS feed from URL, and I have AsyncTask class for that called LoadXMLData, and here is code of that class.
LoadXMLData class:
public class LoadXMLData extends AsyncTask<String, RSSFeed, RSSFeed>{
private ProgressDialog mProgressDialog;
private Context context;
RSSFeed feed;
private String RSSFEEDURL = "http://balkanandroid.com/feed/";
public LoadXMLData(Context context) {
this.context = context;
mProgressDialog = new ProgressDialog(context);
mProgressDialog.setMessage("Molimo Vas, sačekajte. Podaci se učitavaju.");
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mProgressDialog.show();
Log.d("OVDE SAM:", "onPreExecute()");
}
#Override
protected RSSFeed doInBackground(String... urls) {
// Obtain feed
DOMParser myParser = new DOMParser();
feed = myParser.parseXml(urls[0]);
Log.d("OVDE SAM:", "PARSIRAM XML");
return feed;
}
#Override
protected void onPostExecute(RSSFeed result) {
mProgressDialog.dismiss();
super.onPostExecute(result);
}
}
Also I have class MainActivity, which extends SherlockFragmentActivity.
public class MainActivity extends SherlockFragmentActivity {
BAFragmentAdapter mAdapter;
RSSFeed feed;
Application myApp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("OVDE SAM:", "MAIN ACTIVITY");
myApp = getApplication();
mAdapter = new BAFragmentAdapter(getSupportFragmentManager());
ViewPager pager = (ViewPager) findViewById(R.id.pager);
pager.setAdapter(mAdapter);
TabPageIndicator indicator = (TabPageIndicator) findViewById(R.id.indicator);
indicator.setViewPager(pager);
}
public RSSFeed getFeed() {
return feed;
}
public void setFeed(RSSFeed feed) {
this.feed = feed;
}
And the most imporatnt I have few fragment classes (LatestFragments, PhonesFragments, TabletFragments, ApplicationFragments and so on), and on each fragments I have almost same code as shown below.
Here is the full code of LatestFragment:
public class LatestFragment extends Fragment {
GridView lv;
RSSFeed feed;
CustomListAdapter adapter;
private String RSSFEEDURL = "http://balkanandroid.com/feed/";
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_najnovije, container,
false);
AsyncTask<String, RSSFeed, RSSFeed> xml = new LoadXMLData(getActivity())
.execute(RSSFEEDURL);
// AsyncTask<String, RSSFeed, RSSFeed> load = new
// LoadXMLData(getActivity()).execute(RSSFEEDURL);
try {
feed = xml.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lv = (GridView) view.findViewById(R.id.GridView1);
// Set an Adapter to the ListView
adapter = new CustomListAdapter();
lv.setAdapter(adapter);
// Set on item click listener to the ListView
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// actions to be performed when a list item clicked
int pos = arg2;
Bundle bundle = new Bundle();
bundle.putSerializable("feed", feed);
Intent intent = new Intent(getActivity(), DetailsActivity.class);
intent.putExtras(bundle);
intent.putExtra("pos", pos);
startActivity(intent);
}
});
return view;
}
#Override
public void onDestroy() {
super.onDestroy();
adapter.imageLoader.clearCache();
adapter.notifyDataSetChanged();
}
class CustomListAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
public ImageLoader imageLoader;
public CustomListAdapter() {
layoutInflater = (LayoutInflater) getActivity().getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(getActivity().getApplicationContext());
}
public int getCount() {
// TODO Auto-generated method stub
// Set the total list item count
return feed.getItemCount();
}
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
// Inflate the item layout and set the views
View listItem = convertView;
int pos = position;
if (listItem == null) {
listItem = layoutInflater.inflate(R.layout.list_item, null);
}
// Initialize the views in the layout
ImageView iv = (ImageView) listItem.findViewById(R.id.thumb);
TextView tvTitle = (TextView) listItem.findViewById(R.id.title);
TextView tvDate = (TextView) listItem.findViewById(R.id.tvDate);
// Set the views in the layout
imageLoader.DisplayImage(feed.getItem(pos).getImage(), iv);
tvTitle.setText(feed.getItem(pos).getTitle());
tvDate.setText(feed.getItem(pos).getDate());
return listItem;
}
}
}
As you can see I use AsyncTask class LoadXMLData to read data in doInBackground() method, and then I call that AsyncTask class under all fragment classes with this code, because I need result of RSSFeed, because I need that data to show it to user.
AsyncTask<String, RSSFeed, RSSFeed> xml = new LoadXMLData(getActivity())
.execute(RSSFEEDURL);
try {
feed = xml.get();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And it works, but when I click to open other view from view pager its slow, almost freezes my app, and I get this message with Logcat.
07-10 00:22:40.598: I/Choreographer(623): Skipped 316 frames! The application may be doing too much work on its main thread.
That is because you are calling get() on your AsyncTask, which blocks. Do not do this.
Instead, use your feed in onPostExecute() of the AsyncTask.
I'm trying to implement a simple android REST Client and i having some problems understanding how to pass data between my activities.
I have this ListActivity (I'm using the Spring REST Template) :
public class MainActivity extends ListActivity
{
protected static final String TAG = MainActivity.class.getSimpleName();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
}
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
}
#Override
protected void onStart() {
super.onStart();
new DownloadClientesTask().execute();
}
private void refreshClientes(List<Cliente> clientes) {
if (clientes == null) {
return;
}
ClientesListAdapter adapter = new ClientesListAdapter(this, clientes);
setListAdapter(adapter);
}
private class DownloadClientesTask extends AsyncTask<Void, Void, List<Cliente>> {
#Override
protected List<Cliente> doInBackground(Void... params) {
final String url = "http://192.168.1.119/~henry/api_slim/index.php/customers";
try {
// Set the Accept header for "application/json"
HttpHeaders requestHeaders = new HttpHeaders();
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(acceptableMediaTypes);
// Populate the headers in an HttpEntity object to use for the request
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
// Perform the HTTP GET request
ResponseEntity<Cliente[]> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity,
Cliente[].class);
// convert the array to a list and return it
return Arrays.asList(responseEntity.getBody());
} catch (Exception e) {
// TODO Auto-generated catch block
Log.e(TAG, e.getMessage(), e);
}
return null;
}
#Override
protected void onPostExecute(List<Cliente> result) {
refreshClientes(result);
}
}
}
And this is My listAdapter :
public class ClientesListAdapter extends BaseAdapter{
private List<Cliente> clientes;
private final LayoutInflater layoutInflater;
public ClientesListAdapter(Context context, List<Cliente> clientes) {
this.clientes = clientes;
this.layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return this.clientes != null ? clientes.size() : 0;
}
#Override
public Cliente getItem(int position) {
return this.clientes.get(position);
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = this.layoutInflater.inflate(R.layout.cliente_list_item, parent, false);
}
Cliente cliente = getItem(position);
if (cliente != null) {
TextView t = (TextView) convertView.findViewById(R.id.name);
t.setText(cliente.getFirstname());
}
return convertView;
}
}
This the POJO class of the data iḿ getting :
public class Cliente {
private Integer id_customer;
private String firstname;
public Integer getId_customer() {
return id_customer;
}
public void setId_customer(Integer id_customer) {
this.id_customer = id_customer;
}
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
}
When i select an element from the listView i would like show details specific about this element on another activity or fragment, but i don't know how to obtain the customer_id of this element from the list, do i have to save it when i procesing the response? do I need to use content provider or database provide this behavior? i'm really confused, thanks in advance for any help!
There are good examples on how to pass data from one activity to another here, pass objects between activities. You may want to take a look first to the solutions on those links.
Please see below an example that can put you on the right track.
List adapter class:
public class ClientesListAdapter extends BaseAdapter{
//private members
private List<Cliente> clientes;
//adapter position - not used for this example
public int adapterPosition;
//context of app
private Context mContext;
//default constructor
public ClientesListAdapter(Context context, List<Cliente> clientes) {
//context pointer
this.mContext = context;
//alloc
this.clientes = new ArrayList<Cliente>(clientes.size());
this.clientes.addAll(clients);
}
//Holder for events and dates (memory management)
public static class ViewHolder{
TextView myTextView;//this is actually findViewById(R.id.name) #see getView() method
}
//generated method
#Override
public int getCount() {
// TODO Auto-generated method stub
return this.clientes != null ? clientes.size() : 0;
}
//generated method
#Override
public Cliente getItem(int position) {
return this.clientes.get(position);
}
//generated method
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
//get client's id
public int getClienteId(int position){
return this.clientes.get(position).getClienteId();
}
//get client's id without passing the position
public int getClienteId(){
return this.clientes.get(adapterPosition).getClienteId();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//row is actually convertView (the current view)
View row = convertView;
//holds our view elements
ViewHolder holder;
//if row is null
if(row == null){
//inflate layout to get our view elements
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(com.yourapp.R.layout.my_layout, parent, false);//your layout here, modify code
//set up the holder
holder = new ViewHolder();
holder.myTextView = (TextView) row.findViewById(com.yourapp.R.id.name);
//give the row a tag (holder)
row.setTag(holder);
}else{
//row is not null we can see it (no need to allocate memory)
holder = (ViewHolder) row.getTag();
}
//get your cliente object
Cliente cliente = this.clientes.get(position);
if (cliente != null) {
holder.myTextView.setText(cliente.getFirstname());
}
//copy position
adapterPostion = position;
return convertView;
}
}
You see that we used a ViewHolder class for memory management. This is a good practice for holding view elements inside your list adapter. You can find more info about list views, explained by Romain Guy - The World of ListViews.
From your MainActivity allocate the adapter and get your item on click:
//---- code --- //
ListView myListView = (ListView)findViewById(R.id.mylistview);//or you may use ListActivity
ClientesListAdapter adapter = new ClientesListAdapter(this, clientes);//"this" or "getApplicationContext()"
myListView.setAdapter(adapter);
adapter.notifyDataSetChanged();//notify
// ---- code --- //
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
Intent intent = new Intent(MyActivity.this, ActivityB.class);
intent.putInt("cliente_id",adapter.getClienteId());
startActivity(intent);
}
Another example is with implementing an interface in the adapter like this:
//--code//
//Interface method
private OnSaveEditsListener saveEditsListener = null;
public void setOnSaveEditsListener(OnSaveEditsListener l) {
saveEditsListener = l;
}
//--code//
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
//--code--//
//get clicked position of calendar (get clicked day)
convertView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
v.requestFocusFromTouch();
currentAgendaPosition = position;
try{
saveEditsListener.onSaveEdits();
}catch(Exception ex){
ex.printStackTrace();
}
}
});
//returns current row
return row;
}
//--code--//
And from your MainActivity start the second activity like this:
adapter.setOnSaveEditsListener(new OnSaveEditsListener() {
#Override
public void onSaveEdits() {
//Start activity from here
//--code--//
startActivity(intent);
}
});
get the position of the item clicked and get the object present at that position from the arraylist and use it to get the required details.
use
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Toast.makeText(this, "You have selected" + position + id ,
Toast.LENGTH_SHORT).show();
// use this.clientes.get(position) and pass it to the next activity or fragment using putextras to where you need to pass and display this in the destination end using the same object by getting it using getExtra()
}
Your list is in the adapter:
private List<Cliente> clientes;
In onListItemClick, you can get the Cliente from this list using the position parameter.
You pass information to another activity when you call startActivity, passing it an Intent. The Intent may have additional information, in your case you could set the customer_id as an int extra, something like:
intent.putExtra(EXTRA_CUSTOMER_ID, customer_id);
I want to use viewpager in my application.I'm tried to do this everyday in one month but i can't achieve the solution.I want to create pages with same listview concept but different datas.Here is my code:
public final class TestFragment extends ListFragment {
private static final String KEY_CONTENT = "TestFragment:Content";
ArrayList <HashMap<String, Object>> imageliste = new ArrayList<HashMap<String, Object>>();
public class MyCustomAdapter extends ArrayAdapter<HashMap<String, Object>> {
//Bitmap bm;
public MyCustomAdapter(Context context, int textViewResourceId,
ArrayList<HashMap<String,Object>> imageliste) {
super(context, textViewResourceId,imageliste);
// TODO Auto-generated constructor stub
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//return super.getView(position, convertView, parent);
View row = convertView;
if(row==null){
LayoutInflater inflater=LayoutInflater.from(getActivity());
row=inflater.inflate(R.layout.list, parent, false);
}
TextView label=(TextView)row.findViewById(R.id.text1);
label.setText((CharSequence) imageliste.get(position).get("Baslik"));
TextView label2=(TextView)row.findViewById(R.id.text2);
int boyut =imageliste.get(position).get("Desc").toString().length();
label2.setText((CharSequence) imageliste.get(position).get("Desc").toString().substring(0, (boyut/3)*2)+"...");
ImageView icon=(ImageView)row.findViewById(R.id.img);
icon.setImageDrawable((Drawable) imageliste.get(position).get("Resim"));
return row;
}
}
public String getURLContent(String url)
{
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
ResponseHandler<String> resHandler = new BasicResponseHandler();
String page = httpClient.execute(httpGet, resHandler);
return page;
} catch (ClientProtocolException e) {
return "";
} catch (IOException e) {
return "";
}
}
public ArrayList<HashMap<String, Object>> getImageLinks(String strng){
ArrayList<HashMap<String, Object>> myBooks2 = new ArrayList<HashMap<String, Object>>();
String html = getURLContent(strng);
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("postBox");
for (Element div : divs) {
Element masthead = div.select("img[src].attachment-post-thumbnail").first();
String linkHref = masthead.attr("src");
Element masthead2 = div.select("h1").first().select("a").first();
String baslik = masthead2.text();
Element masthead3 = div.select("div.textPreview").first().select("p").first();
String desc = masthead3.text();
//Drawable drawable = LoadImageFromWebOperations();
HashMap<String, Object> hm = new HashMap<String, Object>();
hm.put("Resim", LoadImageFromWebOperations(linkHref));
hm.put("Baslik", baslik);
hm.put("Desc", desc);
myBooks2.add(hm);
}
return myBooks2;
}
private Drawable LoadImageFromWebOperations(String url){
try{
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
return d;
}catch (Exception e) {
System.out.println("Exc="+e);
return null;
}
}
public class backgroundLoadListView extends AsyncTask<String, Void, Void> {
private ProgressDialog dialog = new ProgressDialog(getActivity());
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
// adapter = new MyCustomAdapter( getActivity().getApplicationContext(), R.layout.list, imageliste);
//adapter.notifyDataSetChanged();
dialog.dismiss();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
dialog.setMessage("Yükleniyor...");
dialog.show();
}
#Override
protected Void doInBackground(String... arg) {
// TODO Auto-generated method stub
imageliste=getImageLinks(arg[0]);
return null;
}
}
public class backgroundLoadListView2 extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
LayoutInflater inflater = LayoutInflater.from(getActivity());
View view = inflater.inflate(R.layout.customslidingtabhost, null);
ListView listView1=(ListView)view.findViewById(R.id.list);
//MyCustomAdapter adapter = new MyCustomAdapter(getActivity(), R.layout.list, imageliste);
//listView1.setAdapter(adapter);
int[] colors = {0xFFFFFFFF, 0xFF87CEEB, 0xFFFFFFFF}; // red for the example
listView1.setDivider(new GradientDrawable(Orientation.RIGHT_LEFT, colors));
listView1.setDividerHeight(2);
listView1.setBackgroundColor(Color.WHITE);
((PullToRefreshListView) listView1).onRefreshComplete();
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
imageliste=getImageLinks("http://www.teknoinfo.net/kategoriler/haberler/teknoloji-haberleri");
return null;
}
}
public static TestFragment newInstance(String content) {
TestFragment fragment = new TestFragment();
return fragment;
}
private String mContent = "???";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getString(KEY_CONTENT);
}
//new backgroundLoadListView().execute("http://www.teknoinfo.net/haberler");
MyCustomAdapter adapter = new MyCustomAdapter( getActivity().getApplicationContext(), R.layout.list, imageliste);
View view = inflater.inflate(R.layout.customslidingtabhost, null);
final ListView v=(ListView)view.findViewById(R.id.list);
/*((PullToRefreshListView) v).setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
// Do work to refresh the list here.
new backgroundLoadListView2().execute();
}
});*/
int[] colors = {0xFFFFFFFF, 0xFF87CEEB, 0xFFFFFFFF}; // red for the example
v.setDivider(new GradientDrawable(Orientation.RIGHT_LEFT, colors));
v.setDividerHeight(2);
v.setBackgroundColor(Color.WHITE);
v.setAdapter(adapter);
((PullToRefreshListView) v).setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
// Do work to refresh the list here.
//new backgroundLoadListView2().execute();
// new backgroundLoadListView().execute("http://www.teknoinfo.net/haberler");
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_CONTENT, mContent);
}
}
It is hard to work through all that code you posted (most of which has not to do with your question), but as far as I can tell you have not even set up a ViewPager from your code or it is hidden in some XML file that you didn't post.
What you need to do is create a ViewPager instance. For example in your fragment's XML layout file, like:
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
Now, in your Fragment you create an adapter that specifies the pages that you want (similarly to how a ListAdapter specifies items to a ListView). For that, create a class (you can do that inline in the Fragment code) that inherits from PagerAdapter. For example, something like:
private class MyPagerAdapter extends PagerAdapter implements TitleProvider {
private ListView pagerListView1;
private ListView pagerListView2;
public MyPagerAdapter() {
LayoutInflater inflater = getActivity().getLayoutInflater();
pagerListView1 = (ListView) inflater.inflate(R.layout.fragment_pagerlist, null);
pagerListView2 = (ListView) inflater.inflate(R.layout.fragment_pagerlist, null);
}
#Override
public int getCount() {
return 2;
}
#Override
public Object instantiateItem(View container, int position) {
switch (position) {
case 0:
((ViewPager) container).addView(pagerListView1, 0);
return pagerListView1;
case 1:
((ViewPager) container).addView(pagerListView2, 0);
return pagerListView2;
}
return null;
}
#Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == (View) object;
}
#Override
public void finishUpdate(View container) {
}
#Override
public Parcelable saveState() {
return null;
}
#Override
public void startUpdate(View container) {
}
#Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
}
Note that I hard-coded 2 pages/lists in this pager. You can fill those as you would with any other ListView. The layout of the pages is just a simple ListView that is inflated from the fragment_pagerlist XML file, which looks something like:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/list"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:cacheColorHint="#color/BackgroundLight" />
Finally, you bind the ViewPager's adapter somewhere in your onActivityCreated method:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ViewPager pager = (ViewPager) getView().findViewById(R.id.pager);
pager.setAdapter(new MyPagerAdapter());
}
Note that this does not yet give you a ViewPagerIndicator. Check Jake Wharton's excellent library for that.
If you want the code to a fully implemented and working version, with multiple lists (and other views) in a ViewPager and a ViewPagerIndicator, take a look at the open source RateBeer for Android project; specifically http://code.google.com/p/ratebeerforandroid/source/browse/RateBeerForAndroid/src/com/ratebeer/android/gui/fragments/SearchFragment.java#486 for a real-world PagerAdapter.