Tuesday, July 24, 2012
Monday, July 16, 2012
Android - Steps to run GCM Demo
I would insist to first go through Android Docs and then try to implement using below steps.
Make sure you have installed Apache Tomcat and Apache Ant.
Steps:-
1.) Make sure you have dowloaded support library from SDK Manager -> "Google Cloud Messaging for Android Library".
2.) This will add "gcm" folder with demo application in your SDK folder.
3.) So go to "your_sdk\extras\google\gcm\samples\gcm-demo-server\WebContent\WEB-INF\classes\api.key". And here enter your API-KEY that you got from registering to
Google Console.
4.)
- Now you have to set System variables for Ant upto its "bin". So, edit Path and append it at the end using a semi-colon - "your_path\apache-ant-1.8.4\bin".
- Now set the user variable for "JAVA_HOME" - "C:\Program Files\Java\jdk1.6.0_23"(without "bin") and Ant upto its "bin" folder. Go to cmd and type ant.
Buildfile: build.xml does not exist!
Build failed
If you get above error means your Ant is working fine.
5.) Now go to "your_sdk\extras\google\gcm\samples\gcm-demo-server" and type ant.
If successful you will see output like,
init:
[mkdir] Created dir: your_sdk\extras\google\gcm\samples\gcm-demo-
server\build\classes
[mkdir] Created dir: your_sdk\extras\google\gcm\samples\gcm-demo-
server\dist
compile:
[javac] Compiling 7 source files to your_sdk\extras\google\gcm\sa
mples\gcm-demo-server\build\classes
war:
[war] Building war: your_sdk\extras\google\gcm\samples\gcm-demo
-server\dist\gcm-demo.war
dist:
BUILD SUCCESSFUL
Total time: 0 seconds
Also you will see a "dist" folder created with "gcm-demo.war" file.
6.) Now start your apache tomcat server and check that its working fine by running it using "http://your_host_ip:8080/"
7.) If its working fine go to "C:\Program Files\Apache Software Foundation\Tomcat 7.0\webapps\copy gcm-demo.war" here.
8.) Restart your Server and open the gcm-demo in browser - "http://your_host_ip:8080/gcm-demo/"
You will see result as,
Unregistered device #0
No devices registered!
So, server side is completed now.
9.) Now, import "gcm-demo-client" Application from "your_sdk\extras\google\gcm\samples\gcm-demo-client"
10.) Open "CommonUtilities.java" - here you need to give
SERVER_URL="http://your_host_ip/gcm-demo/" and
SENDER_ID="sender id you got from google console url".
11.) Build "gcm-demo-client" into your Android Device to register to your Server
Succesfully sent message to device #0
1 device(s) registered!
You will see above output if successfully registered will a send button.
12.) Press Send Button to get Notification on your device.
You can find the sorce demo from github, it also include the gcm-demo.war file that you have to deploy. The things that are required to be change are,
1.) API Key,
2.) SENDER_ID
3.) SERVER_URL
Thanks :)
Monday, July 2, 2012
Section Adapter
I found an interested post about SectionAdapter by Jeff Sharkey. I will insist that it is the better way of creating SectionAdapter in the way that Jeff has opted here in his blog.
The blog just says to use seperate Adapter for every Header, so that we can customize it easily in the best possible way. The idea is very much clear and interesting. So, we can customize it and create as required by us. Below is how we can customize the SectionAdapter.
SectionedAdapter.java
abstract public class SectionedAdapter extends BaseAdapter {
String TAG = getClass().getSimpleName();
abstract protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent);
private List<Section> sections = new ArrayList<Section>();
private static int TYPE_SECTION_HEADER = 0;
public SectionedAdapter() {
super();
sections.clear();
}
public void addSection(String caption, Adapter adapter) {
sections.add(new Section(caption, adapter));
}
public void clear() {
sections.clear();
notifyDataSetChanged();
}
public Object getItem(int position) {
for (Section section : this.sections) {
if (position == 0) {
return (section);
}
int size = section.adapter.getCount() + 1;
if (position < size) {
return (section.adapter.getItem(position - 1));
}
position -= size;
}
return (null);
}
public int getCount() {
int total = 0;
for (Section section : this.sections) {
total += section.adapter.getCount() + 1; // add one for header
}
return (total);
}
public int getViewTypeCount() {
int total = 1; // one for the header, plus those from sections
for (Section section : this.sections) {
total += section.adapter.getViewTypeCount();
}
return (total);
}
public int getItemViewType(int position) {
int typeOffset = TYPE_SECTION_HEADER + 1; // start counting from here
for (Section section : this.sections) {
if (position == 0) {
return (TYPE_SECTION_HEADER);
}
int size = section.adapter.getCount() + 1;
if (position < size) {
int value = (typeOffset + section.adapter
.getItemViewType(position - 1));
return value;
}
position -= size;
typeOffset += section.adapter.getViewTypeCount();
}
return (-1);
}
public boolean areAllItemsSelectable() {
return (false);
}
public boolean isEnabled(int position) {
return (getItemViewType(position) != TYPE_SECTION_HEADER);
}
public View getView(int position, View convertView, ViewGroup parent) {
int sectionIndex = 0;
for (Section section : this.sections) {
if (position == 0) {
return (getHeaderView(section.caption, sectionIndex, convertView, parent));
}
int size = section.adapter.getCount() + 1;
if (position < size) {
return (section.adapter.getView(position - 1, convertView, parent));
}
position -= size;
sectionIndex++;
}
return (null);
}
public long getItemId(int position) {
return (position);
}
class Section {
String caption = null;
Adapter adapter = null;
Section(String caption, Adapter adapter) {
this.caption = caption;
this.adapter = adapter;
}
}
}
Above class is abstract and having an abstract method getHeaderView(String caption, int index, View convertView, ViewGroup parent) that is because we can easily customize the Header Section also dynamically from our Activity. In Above class we have an inner class Section that does the work of maintaining every Header having its own Adapter. So, the class is nicely set-up to be used.
So, now we will create an Activity having a ListView,
MainActivity.java
public class MainActivity extends Activity {
ListView mListView;
ArrayList<String> mArrayList = new ArrayList<String>();
SectionedAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
adapter = new SectionedAdapter() {
@Override
protected View getHeaderView(String caption, int index,
View convertView, ViewGroup parent) {
convertView = getLayoutInflater().inflate(R.layout.section_header, null);
TextView header = (TextView) convertView.findViewById(R.id.header);
header.setText(caption);
return convertView;
}
};
for (int i = 0; i < 5; i++) {
mArrayList.add("Item " + i);
MyAdapter myAdapter = new MyAdapter();
adapter.addSection("Header " + i, myAdapter);
}
mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Toast.makeText(getApplicationContext(), arg0.getAdapter().getItem(position).toString(), Toast.LENGTH_LONG).show();
}
});
mListView.setAdapter(adapter);
}
class MyAdapter extends BaseAdapter {
public int getCount() {
return mArrayList.size();
}
public Object getItem(int position) {
return mArrayList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
convertView = (TextView) getLayoutInflater().inflate(R.layout.section_item, null);
TextView item = (TextView) convertView.findViewById(R.id.item);
item.setText(mArrayList.get(position));
return convertView;
}
}
}
So, what we have in the Activity class is an instance of SectionedAdapter adapter; class with override method getHeaderView(String caption, int index, View convertView, ViewGroup parent) by which we can inflate any xml and create our own custom Header. Also I had created an inner class MyAdapter that extends BaseAdapter which will be used as an Adapter for each Header. To add an Seperator as Header we can use addSection(String Caption, Adapter adapter) method to add the Header caption and a seperate Adapter related to that Header. In this way you can create seperate Adapter for each Header and link to it. I am attaching Demo source code for the same. Enjoy!!!!
The blog just says to use seperate Adapter for every Header, so that we can customize it easily in the best possible way. The idea is very much clear and interesting. So, we can customize it and create as required by us. Below is how we can customize the SectionAdapter.
SectionedAdapter.java
abstract public class SectionedAdapter extends BaseAdapter {
String TAG = getClass().getSimpleName();
abstract protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent);
private List<Section> sections = new ArrayList<Section>();
private static int TYPE_SECTION_HEADER = 0;
public SectionedAdapter() {
super();
sections.clear();
}
public void addSection(String caption, Adapter adapter) {
sections.add(new Section(caption, adapter));
}
public void clear() {
sections.clear();
notifyDataSetChanged();
}
public Object getItem(int position) {
for (Section section : this.sections) {
if (position == 0) {
return (section);
}
int size = section.adapter.getCount() + 1;
if (position < size) {
return (section.adapter.getItem(position - 1));
}
position -= size;
}
return (null);
}
public int getCount() {
int total = 0;
for (Section section : this.sections) {
total += section.adapter.getCount() + 1; // add one for header
}
return (total);
}
public int getViewTypeCount() {
int total = 1; // one for the header, plus those from sections
for (Section section : this.sections) {
total += section.adapter.getViewTypeCount();
}
return (total);
}
public int getItemViewType(int position) {
int typeOffset = TYPE_SECTION_HEADER + 1; // start counting from here
for (Section section : this.sections) {
if (position == 0) {
return (TYPE_SECTION_HEADER);
}
int size = section.adapter.getCount() + 1;
if (position < size) {
int value = (typeOffset + section.adapter
.getItemViewType(position - 1));
return value;
}
position -= size;
typeOffset += section.adapter.getViewTypeCount();
}
return (-1);
}
public boolean areAllItemsSelectable() {
return (false);
}
public boolean isEnabled(int position) {
return (getItemViewType(position) != TYPE_SECTION_HEADER);
}
public View getView(int position, View convertView, ViewGroup parent) {
int sectionIndex = 0;
for (Section section : this.sections) {
if (position == 0) {
return (getHeaderView(section.caption, sectionIndex, convertView, parent));
}
int size = section.adapter.getCount() + 1;
if (position < size) {
return (section.adapter.getView(position - 1, convertView, parent));
}
position -= size;
sectionIndex++;
}
return (null);
}
public long getItemId(int position) {
return (position);
}
class Section {
String caption = null;
Adapter adapter = null;
Section(String caption, Adapter adapter) {
this.caption = caption;
this.adapter = adapter;
}
}
}
Above class is abstract and having an abstract method getHeaderView(String caption, int index, View convertView, ViewGroup parent) that is because we can easily customize the Header Section also dynamically from our Activity. In Above class we have an inner class Section that does the work of maintaining every Header having its own Adapter. So, the class is nicely set-up to be used.
So, now we will create an Activity having a ListView,
MainActivity.java
public class MainActivity extends Activity {
ListView mListView;
ArrayList<String> mArrayList = new ArrayList<String>();
SectionedAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.listview);
adapter = new SectionedAdapter() {
@Override
protected View getHeaderView(String caption, int index,
View convertView, ViewGroup parent) {
convertView = getLayoutInflater().inflate(R.layout.section_header, null);
TextView header = (TextView) convertView.findViewById(R.id.header);
header.setText(caption);
return convertView;
}
};
for (int i = 0; i < 5; i++) {
mArrayList.add("Item " + i);
MyAdapter myAdapter = new MyAdapter();
adapter.addSection("Header " + i, myAdapter);
}
mListView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
Toast.makeText(getApplicationContext(), arg0.getAdapter().getItem(position).toString(), Toast.LENGTH_LONG).show();
}
});
mListView.setAdapter(adapter);
}
class MyAdapter extends BaseAdapter {
public int getCount() {
return mArrayList.size();
}
public Object getItem(int position) {
return mArrayList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
convertView = (TextView) getLayoutInflater().inflate(R.layout.section_item, null);
TextView item = (TextView) convertView.findViewById(R.id.item);
item.setText(mArrayList.get(position));
return convertView;
}
}
}
So, what we have in the Activity class is an instance of SectionedAdapter adapter; class with override method getHeaderView(String caption, int index, View convertView, ViewGroup parent) by which we can inflate any xml and create our own custom Header. Also I had created an inner class MyAdapter that extends BaseAdapter which will be used as an Adapter for each Header. To add an Seperator as Header we can use addSection(String Caption, Adapter adapter) method to add the Header caption and a seperate Adapter related to that Header. In this way you can create seperate Adapter for each Header and link to it. I am attaching Demo source code for the same. Enjoy!!!!
Thursday, June 28, 2012
How to update Activity from Service using ResultReceiver
Today I am going to show how can we update Activity using android.os.ResultReceiver. What we need is just create and inner class inside an Activity that extends ResultReceiver and override its onReceiveResult() methods that will be called while sending data from Service class and inside this method we can update UI components.
What I will show in Demo?
I will just create an Activity with a TextView and update the TextView with current seconds of time.
So, create an Activity with main.xml having a TextView. Also, an inner class that extends ResultReceiver and a class that extends Runnable to be used for runOnUiThread.
public class ResultReceiverDemoActivity extends Activity{
Intent intent;
TextView txtview;
MyResultReceiver resultReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
resultReceiver = new MyResultReceiver(null);
txtview = (TextView) findViewById(R.id.txtview);
intent = new Intent(this, MyService.class);
intent.putExtra("receiver", resultReceiver);
startService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
}
class UpdateUI implements Runnable
{
String updateString;
public UpdateUI(String updateString) {
this.updateString = updateString;
}
public void run() {
txtview.setText(updateString);
}
}
class MyResultReceiver extends ResultReceiver
{
public MyResultReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if(resultCode == 100){
runOnUiThread(new UpdateUI(resultData.getString("start")));
}
else if(resultCode == 200){
runOnUiThread(new UpdateUI(resultData.getString("end")));
}
else{
runOnUiThread(new UpdateUI("Result Received "+resultCode));
}
}
}
}
As, you can see there is nothing much in the above code just a simple one. The new thing about you would be the class that extends ResultReceiver. It is having an overrided method onReceiveResult(int resultCode, Bundle resultData) with parameters resultCode and Bundle. These two parameters we will pass from the Service class using send(resultCode, Bundle resultData) of ResultReceiver which will be pass to onReceiveResult(int resultCode, Bundle resultData) where we can update the UI.
Also, one more important thing is that you might have seen that I am passing a putExtra to Service class as
intent.putExtra("receiver", resultReceiver); where resultReceiver is the instance of MyResultReceiver class that extends ResultReceiver. We will get the putExtra in the Service class and use the same instance to send data from Service to Activity using send(resultCode, Bundle resultData).
Now, lets add the Service class that is also a simple one having a Timer with 1 second.
public class MyService extends Service{
Timer timer = new Timer();
MyTimerTask timerTask;
ResultReceiver resultReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
resultReceiver = intent.getParcelableExtra("receiver");
timerTask = new MyTimerTask();
timer.scheduleAtFixedRate(timerTask, 1000, 1000);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Bundle bundle = new Bundle();
bundle.putString("end", "Timer Stopped....");
resultReceiver.send(200, bundle);
}
class MyTimerTask extends TimerTask
{
public MyTimerTask() {
Bundle bundle = new Bundle();
bundle.putString("start", "Timer Started....");
resultReceiver.send(100, bundle);
}
@Override
public void run() {
SimpleDateFormat dateFormat = new SimpleDateFormat("s");
resultReceiver.send(Integer.parseInt(dateFormat.format(System.currentTimeMillis())), null);
}
}
}
So, simply we are getting the putExtra of ResultReceiver's instance using resultReceiver = intent.getParcelableExtra("receiver"); inside onStartCommand() to use it further for sending the data to Activity. You can send any data to Activity using send(resultCode, Bundle resultData) method of ResultReceive, you can send an error message also with the same method checking the resultCode.
Source code can be found here.
What I will show in Demo?
I will just create an Activity with a TextView and update the TextView with current seconds of time.
So, create an Activity with main.xml having a TextView. Also, an inner class that extends ResultReceiver and a class that extends Runnable to be used for runOnUiThread.
public class ResultReceiverDemoActivity extends Activity{
Intent intent;
TextView txtview;
MyResultReceiver resultReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
resultReceiver = new MyResultReceiver(null);
txtview = (TextView) findViewById(R.id.txtview);
intent = new Intent(this, MyService.class);
intent.putExtra("receiver", resultReceiver);
startService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
}
class UpdateUI implements Runnable
{
String updateString;
public UpdateUI(String updateString) {
this.updateString = updateString;
}
public void run() {
txtview.setText(updateString);
}
}
class MyResultReceiver extends ResultReceiver
{
public MyResultReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if(resultCode == 100){
runOnUiThread(new UpdateUI(resultData.getString("start")));
}
else if(resultCode == 200){
runOnUiThread(new UpdateUI(resultData.getString("end")));
}
else{
runOnUiThread(new UpdateUI("Result Received "+resultCode));
}
}
}
}
As, you can see there is nothing much in the above code just a simple one. The new thing about you would be the class that extends ResultReceiver. It is having an overrided method onReceiveResult(int resultCode, Bundle resultData) with parameters resultCode and Bundle. These two parameters we will pass from the Service class using send(resultCode, Bundle resultData) of ResultReceiver which will be pass to onReceiveResult(int resultCode, Bundle resultData) where we can update the UI.
Also, one more important thing is that you might have seen that I am passing a putExtra to Service class as
intent.putExtra("receiver", resultReceiver); where resultReceiver is the instance of MyResultReceiver class that extends ResultReceiver. We will get the putExtra in the Service class and use the same instance to send data from Service to Activity using send(resultCode, Bundle resultData).
Now, lets add the Service class that is also a simple one having a Timer with 1 second.
public class MyService extends Service{
Timer timer = new Timer();
MyTimerTask timerTask;
ResultReceiver resultReceiver;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
resultReceiver = intent.getParcelableExtra("receiver");
timerTask = new MyTimerTask();
timer.scheduleAtFixedRate(timerTask, 1000, 1000);
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Bundle bundle = new Bundle();
bundle.putString("end", "Timer Stopped....");
resultReceiver.send(200, bundle);
}
class MyTimerTask extends TimerTask
{
public MyTimerTask() {
Bundle bundle = new Bundle();
bundle.putString("start", "Timer Started....");
resultReceiver.send(100, bundle);
}
@Override
public void run() {
SimpleDateFormat dateFormat = new SimpleDateFormat("s");
resultReceiver.send(Integer.parseInt(dateFormat.format(System.currentTimeMillis())), null);
}
}
}
So, simply we are getting the putExtra of ResultReceiver's instance using resultReceiver = intent.getParcelableExtra("receiver"); inside onStartCommand() to use it further for sending the data to Activity. You can send any data to Activity using send(resultCode, Bundle resultData) method of ResultReceive, you can send an error message also with the same method checking the resultCode.
Source code can be found here.
Calling SOAP WebService using HTTPPOST and getting response in XML.
Today I am going to show you how we can call soap web-service using HTTP-POST. As we know for calling SOAP web-service you require ksoap jar to be added to your project and you can call it. But, sometimes when you have complex response from SOAP web-services its very difficult to parse.So, my motive in this post is to call the SOAP web-service and get the response in XML rather than getting response in SOAP. Though you can get the request by using "requestDump" & response in XML by using "responseDump" as
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL, timeout);
androidHttpTransport.debug=true;
androidHttpTransport.call(SOAP_ACTION, envelope);
String requestString = androidHttpTransport.requestDump;
Log.d("Request in XML", requestString);
String response = androidHttpTransport.responseDump;
Log.d("Response in XML", response);
So, what you can do is create a file with an Request and keep it inside assets folder of your project. Also you have to add %s in place of paramters if you want to pass dynamic parameters to your web-service. I am going to use a live web-service from www.w3schools.com so that you can test the source code directly if you don't have your own web-service.
I am going to use a web-service that will convert Celcius to Fahrenheit. Below is my request.xml in assets folder.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<CelsiusToFahrenheit xmlns="http://tempuri.org/">
<Celsius>%s</Celsius>
</CelsiusToFahrenheit>
</soap:Body>
</soap:Envelope>
You can see I am using %s in place of Celcius value because I am going to pass the parameter dynamically from the code not a static one. Now we have to read the xml from assets folder and pass parameter to it dynamically. Below is how you can read the xml from assets folder and convert it to String.
public static String convertStreamToString(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line+"\n");
}
is.close();
return sb.toString();
}
You can just pass InputStream to this method and get the xml as response from this method. Just call it by
String xml = convertStreamToString(getAssets().open("request.xml"));
Now, you have the xml String you need to pass the parameter that is the value of Celcius, so you can do that by using String.format(String format, Object...args)
In this case you can do it as
String RequestString = String.format(xml, "12"); (If you have multiple paramters you can pass it by comma seperated)
Now you have your Request String ready to be passed to HTTPPost and get the Response. So, just pass the URL and RequestString to get the Response.
I had just created a simple method that will except the arguments as URL of our web-service and a String request that is the xml from assets folder.
public String getResponseByXML(String URL, String request) {
HttpPost httpPost = new HttpPost(URL);
StringEntity entity;
String response_string = null;
try {
entity = new StringEntity(request, HTTP.UTF_8);
httpPost.setHeader("Content-Type","text/xml;charset=UTF-8");
httpPost.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(httpPost);
response_string = EntityUtils.toString(response.getEntity());
Log.d("request", response_string);
} catch (Exception e) {
e.printStackTrace();
}
return response_string;
}
Call above method to get the HTTP-POST Response using the URL and Request String that we created with parameter.
private String URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
String ResponseInXML = getResponseByXML(URL, RequestString);
Log.d("ResponseInXML", ResponseInXML);
So, you will get your response in ResponseInXML . Then you can easily parse ResponseInXML using any XML Parser. You can checkout for a Demo example for github.
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL, timeout);
androidHttpTransport.debug=true;
androidHttpTransport.call(SOAP_ACTION, envelope);
String requestString = androidHttpTransport.requestDump;
Log.d("Request in XML", requestString);
String response = androidHttpTransport.responseDump;
Log.d("Response in XML", response);
So, what you can do is create a file with an Request and keep it inside assets folder of your project. Also you have to add %s in place of paramters if you want to pass dynamic parameters to your web-service. I am going to use a live web-service from www.w3schools.com so that you can test the source code directly if you don't have your own web-service.
I am going to use a web-service that will convert Celcius to Fahrenheit. Below is my request.xml in assets folder.
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<CelsiusToFahrenheit xmlns="http://tempuri.org/">
<Celsius>%s</Celsius>
</CelsiusToFahrenheit>
</soap:Body>
</soap:Envelope>
You can see I am using %s in place of Celcius value because I am going to pass the parameter dynamically from the code not a static one. Now we have to read the xml from assets folder and pass parameter to it dynamically. Below is how you can read the xml from assets folder and convert it to String.
public static String convertStreamToString(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line+"\n");
}
is.close();
return sb.toString();
}
You can just pass InputStream to this method and get the xml as response from this method. Just call it by
String xml = convertStreamToString(getAssets().open("request.xml"));
Now, you have the xml String you need to pass the parameter that is the value of Celcius, so you can do that by using String.format(String format, Object...args)
In this case you can do it as
String RequestString = String.format(xml, "12"); (If you have multiple paramters you can pass it by comma seperated)
Now you have your Request String ready to be passed to HTTPPost and get the Response. So, just pass the URL and RequestString to get the Response.
I had just created a simple method that will except the arguments as URL of our web-service and a String request that is the xml from assets folder.
public String getResponseByXML(String URL, String request) {
HttpPost httpPost = new HttpPost(URL);
StringEntity entity;
String response_string = null;
try {
entity = new StringEntity(request, HTTP.UTF_8);
httpPost.setHeader("Content-Type","text/xml;charset=UTF-8");
httpPost.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(httpPost);
response_string = EntityUtils.toString(response.getEntity());
Log.d("request", response_string);
} catch (Exception e) {
e.printStackTrace();
}
return response_string;
}
Call above method to get the HTTP-POST Response using the URL and Request String that we created with parameter.
private String URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
String ResponseInXML = getResponseByXML(URL, RequestString);
Log.d("ResponseInXML", ResponseInXML);
So, you will get your response in ResponseInXML . Then you can easily parse ResponseInXML using any XML Parser. You can checkout for a Demo example for github.
Sunday, June 3, 2012
ListView with CheckBox Scrolling Issue
Today I am going to show how to deal with Custom ListView having Chekbox. Many developers are facing the issue of Checkbox item getting uncheck or check while scrolling the ListView. So, I will make it clear to developers how to deal with ListView having Checkbox. You can learn about the recycling of view in ListView from this Blog.
The issue with CheckBox inside ListView is that the view gets recycled due to recycling of ListView and the value of Checkbox(check or uncheck) is not maintained. To, maintain the state to CheckBox there has to be something that can store the state of Checkbox.
So, we have a Model class that will have name and selected property of ListView row having TextView and CheckBox.
Model.java
public class Model {
private String name;
private boolean selected;
public Model(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
The issue with CheckBox inside ListView is that the view gets recycled due to recycling of ListView and the value of Checkbox(check or uncheck) is not maintained. To, maintain the state to CheckBox there has to be something that can store the state of Checkbox.
So, we have a Model class that will have name and selected property of ListView row having TextView and CheckBox.
Model.java
public class Model {
private String name;
private boolean selected;
public Model(String name) {
this.name = name;
}
public String getName() {
return name;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
Now, we will setup the main Activity that will set the Adapter for the Custom ListView.
MainActivity.java
public class MainActivity extends Activity implements OnItemClickListener{
ListView listView;
ArrayAdapter<Model> adapter;
List<Model> list = new ArrayList<Model>();
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
listView = (ListView) findViewById(R.id.my_list);
adapter = new MyAdapter(this,getModel());
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
TextView label = (TextView) v.getTag(R.id.label);
CheckBox checkbox = (CheckBox) v.getTag(R.id.check);
Toast.makeText(v.getContext(), label.getText().toString()+" "+isCheckedOrNot(checkbox), Toast.LENGTH_LONG).show();
}
private String isCheckedOrNot(CheckBox checkbox) {
if(checkbox.isChecked())
return "is checked";
else
return "is not checked";
}
private List<Model> getModel() {
list.add(new Model("Linux"));
list.add(new Model("Windows7"));
list.add(new Model("Suse"));
list.add(new Model("Eclipse"));
list.add(new Model("Ubuntu"));
list.add(new Model("Solaris"));
list.add(new Model("Android"));
list.add(new Model("iPhone"));
list.add(new Model("Java"));
list.add(new Model(".Net"));
list.add(new Model("PHP"));
return list;
}
}
ListView listView;
ArrayAdapter<Model> adapter;
List<Model> list = new ArrayList<Model>();
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
listView = (ListView) findViewById(R.id.my_list);
adapter = new MyAdapter(this,getModel());
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
TextView label = (TextView) v.getTag(R.id.label);
CheckBox checkbox = (CheckBox) v.getTag(R.id.check);
Toast.makeText(v.getContext(), label.getText().toString()+" "+isCheckedOrNot(checkbox), Toast.LENGTH_LONG).show();
}
private String isCheckedOrNot(CheckBox checkbox) {
if(checkbox.isChecked())
return "is checked";
else
return "is not checked";
}
private List<Model> getModel() {
list.add(new Model("Linux"));
list.add(new Model("Windows7"));
list.add(new Model("Suse"));
list.add(new Model("Eclipse"));
list.add(new Model("Ubuntu"));
list.add(new Model("Solaris"));
list.add(new Model("Android"));
list.add(new Model("iPhone"));
list.add(new Model("Java"));
list.add(new Model(".Net"));
list.add(new Model("PHP"));
return list;
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/my_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ListView
android:id="@+id/my_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@+id/label"
android:textSize="30sp" >
</TextView>
<CheckBox
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="4dip"
android:layout_marginRight="10dip"
android:focusable="false"
android:focusableInTouchMode="false" >
</CheckBox>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@+id/label"
android:textSize="30sp" >
</TextView>
<CheckBox
android:id="@+id/check"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="4dip"
android:layout_marginRight="10dip"
android:focusable="false"
android:focusableInTouchMode="false" >
</CheckBox>
</RelativeLayout>
Finally, now we will have the Adapter class.
MyAdapter.java
public class MyAdapter extends ArrayAdapter<Model> {
private final List<Model> list;
private final Activity context;
boolean checkAll_flag = false;
boolean checkItem_flag = false;
public MyAdapter(Activity context, List<Model> list) {
super(context, R.layout.row, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
protected TextView text;
protected CheckBox checkbox;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
convertView = inflator.inflate(R.layout.row, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.label);
viewHolder.checkbox = (CheckBox) convertView.findViewById(R.id.check);
viewHolder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int getPosition = (Integer) buttonView.getTag(); // Here we get the position that we have set for the checkbox using setTag.
list.get(getPosition).setSelected(buttonView.isChecked()); // Set the value of checkbox to maintain its state.
}
});
convertView.setTag(viewHolder);
convertView.setTag(R.id.label, viewHolder.text);
convertView.setTag(R.id.check, viewHolder.checkbox);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkbox.setTag(position); // This line is important.
viewHolder.text.setText(list.get(position).getName());
viewHolder.checkbox.setChecked(list.get(position).isSelected());
return convertView;
}
}
private final List<Model> list;
private final Activity context;
boolean checkAll_flag = false;
boolean checkItem_flag = false;
public MyAdapter(Activity context, List<Model> list) {
super(context, R.layout.row, list);
this.context = context;
this.list = list;
}
static class ViewHolder {
protected TextView text;
protected CheckBox checkbox;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
LayoutInflater inflator = context.getLayoutInflater();
convertView = inflator.inflate(R.layout.row, null);
viewHolder = new ViewHolder();
viewHolder.text = (TextView) convertView.findViewById(R.id.label);
viewHolder.checkbox = (CheckBox) convertView.findViewById(R.id.check);
viewHolder.checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
int getPosition = (Integer) buttonView.getTag(); // Here we get the position that we have set for the checkbox using setTag.
list.get(getPosition).setSelected(buttonView.isChecked()); // Set the value of checkbox to maintain its state.
}
});
convertView.setTag(viewHolder);
convertView.setTag(R.id.label, viewHolder.text);
convertView.setTag(R.id.check, viewHolder.checkbox);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.checkbox.setTag(position); // This line is important.
viewHolder.text.setText(list.get(position).getName());
viewHolder.checkbox.setChecked(list.get(position).isSelected());
return convertView;
}
}
So, the important line in the above Adapter class is to setTag() position of CheckBox and then retrieve it using getTag() inside onCheckedChanged() and then set the current state of CheckBox in your Model class instance. I am also attaching the complete source code for the same so that anyone can download and understand that how it works. Here is the complete source code.
Tuesday, May 29, 2012
Saturday, May 19, 2012
Thursday, May 17, 2012
Thursday, May 3, 2012
Thursday, March 22, 2012
Thursday, March 15, 2012
Monday, March 5, 2012
Tuesday, February 21, 2012
Saturday, February 18, 2012
Thursday, February 16, 2012
Friday, February 10, 2012
Wednesday, February 1, 2012
Tuesday, January 31, 2012
Sunday, January 29, 2012
Saturday, January 28, 2012
Wednesday, January 18, 2012
Tuesday, January 3, 2012
Subscribe to:
Posts (Atom)