استفاده از HttpPost برای دریافت اطلاعات از یک صفحه اینترنتی (آدرس URL)، با روش POST و به صورت AsyncTask ، در برنامه نویسی اندروید
در مبحثی دیگر، با نحوه استفاده از HttpGet برای دریافت اطلاعات از یک آدرس URL ، آشنا شدیم. در این مبحث قصد داریم که HttpPost را بررسی کنیم، که همان طور که از نامش مشخص است، از روش POST استفاده می کند. ساختار کلی کدها و توضیحات آنها، مشابه همان مبحث HttpGet است، بنابراین همان توضیحات را در اینجا نیز تکرار می کنیم و البته بخش های مهم مربوط به HttpPost را نیز شرح خواهیم داد.
برای این مبحث آموزشی، از آدرس اینترنتی زیر استفاده می کنیم :
همان طور که مشاهده می کنید، صفحه اینترنتی مورد نظر، در سایت کلیدستان (http://www.kelidestan.com) قرار دارد و آن را در پوشه ای (folder) به نام fixed-url قرار داده ایم. نام این پوشه، به این دلیل برایر fixed-url انتخاب شده است، که در آینده حواسمان باشد که نباید آدرس URL صفحات موجود در این پوشه، تغییر کند، بنابراین شما با خیال راحت و بدون نگرانی از تغییر آدرس URL و یا محتوای صفحات، می توانید از آنها استفاده کنید.
در صفحه kelidestan-2.php ، کدهای PHP زیر را می نویسیم :
if(isset($_POST['country']) && isset($_POST['age'])){
$country = $_POST['country'];
$country = htmlspecialchars($country);
$country = strip_tags($country);
$age = $_POST['age'];
$age = htmlspecialchars($age);
$age = strip_tags($age);
echo "country : ".$country." --- age : ".$age."";
}
?>
بنابراین کدهای PHP صفحه، ابتدا چک می کنند که مقادیری برای دو متغیر country و age ، با روش POST ، به صفحه ارسال شده باشد (اگر ارسال نشده باشد، هیچ کد دیگری اجرا نمی شود و خروجی به صورت صفحه خالی خواهد بود). سپس در صورتی که برای هر دو متغیر، مقدار به صفحه ارسال شده باشد، مقادیر دریافت شده و در دو متغیر با همان نام ها، ذخیره می شود. سپس یک عبارت که در آن، مقدار متغیرها نیز وجود دارد، در خروجی چاپ می شود.
اگر در کدها دقت کنید، دو تابع htmlspecialchars و strip_tags را بر روی مقادیر دریافت شده، اعمال کرده ایم. این عمل برای ایجاد امنیت بیشتر است زیرا ممکن است که یک کاربر، به عنوان هکر، تعدادی کد مخرب را در میان ورودی ها قرار بدهد. در این مورد، در مبحثی دیگر صحبت خواهیم کرد، اما بد نیست به طور مختصر بگوییم که تابع htmlspecialchars ، باعث می شود که هنگام چاپ یک عبارت در خروجی صفحه، اگر تگ های (tags) مربوط به HTML در آن عبارت وجود دارند، به جای اجرا شدن به عنوان کد، تنها در خروجی نمایش داده شوند. همچنین تابع strip_tags ، برای حذف تگ های HTML و PHP موجود در یک عبارت به کار می رود. اگر در آینده بخش های امنیتی بیشتری به این کدها اضافه کنیم، شما مطمئن باشید که در خروجی صفحات تاثیری نخواهد داشت و با اطمینان می توانید از این صفحات استفاده کنید (همان طور که گفتیم، آدرس URL آنها همیشه ثابت خواهد بود و عملکرد آنها تغییری نخواهد کرد و فقط ممکن است صلاح بدانیم که بخشی از کدهای امنیتی را در اینجا نمایش ندهیم).
برای تعیین مقدار برای متغیرها (به روش POST)، باید به مباحث مربوط به فرم ها در PHP مراجعه کنید که در آن مباحث، با چگونگی ارسال مقدار برای متغیرها، به یک صفحه اینترنتی، آشنا می شوید، ولی فعلا ما کاری با آن نداریم و تنها می خواهیم به چگونگی ارسال توسط برنامه اندروید، آشنا بشویم. فقط بد نیست این را بدانید که در روش GET ، مقادیر را در آدرس URL می نوشتیم اما در روش POST ، مقادیر توسط یک فرم که دارای دکمه submit است، ارسال می شوند (این نکات در مباحث طراحی سایت شرح داده می شوند). بنابراین قبلا که از HttpGet استفاده می کردیم، تنها کافی بود که مقادیر را در رشته ای (string) که حاوی آدرس URL صفحه اینترنتی بود، بنویسیم، ولی اکنون که می خواهیم از HttpPost استفاده کنیم، باید برای هر کدام از مقادیر (مقادیر در نظر گرفته شده برای متغیرها) یک پارامتر تعریف کنیم.
اگر برای صفحه مورد نظر، برای متغیر country ، مقدار iran و برای متغیر age ، مقدار 27 را با روش POST ارسال کنیم، خروجی به صورت زیر خواهد بود (چگونگی آن را شرح نمی دهم زیرا مربوط به مبحث فرم ها در طراحی سایت است و ممکن است باعث گیجی شما شود) :
استفاده از مرورگر اینترنت، تنها برای آزمایش عملکرد صفحه می باشد، اما می خواهیم در برنامه اندروید خود، از کدهایی استفاده کنیم که همین دو مقدار را برای دو متغیر، به صفحه ارسال کند و سپس نتیجه را از صفحه دریافت کرده و در یک TextView به ما نمایش بدهد.
قبل از هر چیز، باید به برنامه اندروید خود، اجازه دسترسی به اینترنت را بدهیم. برای این منظور، باید کد زیر را به کدهای فایل AndroidManifest.xml پروژه اندروید، اضافه کنیم :
علاوه بر این، بخشی از کدها نیز برای چک کردن اتصال به اینترنت می باشد و برای آنها، باید اجازه دسترسی زیر نیز به فایل AndroidManifest.xml افزوده شود :
فرض کنید که نام package پروژه اندروید، برابر com.kelidestan.httppost و نام activity اصلی آن برابر MainActivity.java و نام فایل xml متناظر با activity اصلی برابر activity_main.xml باشد.
با توجه به فرض هایی که بیان کردیم، کدهای فایل AndroidManifest.xml ، به صورت زیر خواهد بود :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kelidestan.httppost"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.kelidestan.httppost.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
همچنین کدهای فایل activity_main.xml به صورت زیر می باشد (در آن یک TextView تعریف کرده ایم) :
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
و کدهای فایل MainActivity.java که همان activity اصلی پروژه اندروید است را به صورت زیر می نویسیم :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new NetCheck().execute();
}
/**
* Async Task to check whether internet connection is working.
**/
private class NetCheck extends AsyncTask<String,String,Boolean>
{
private ProgressDialog nDialog;
@Override
protected void onPreExecute(){
super.onPreExecute();
nDialog = new ProgressDialog(MainActivity.this);
nDialog.setTitle("Checking Network");
nDialog.setMessage("Loading..");
nDialog.setIndeterminate(false);
nDialog.setCancelable(true);
nDialog.show();
}
/**
* Gets current device state and checks for working internet connection by trying Google.
**/
@Override
protected Boolean doInBackground(String... args){
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnected()) {
try {
URL url = new URL("http://www.google.com");
HttpURLConnection urlc = (HttpURLConnection) url.openConnection();
urlc.setConnectTimeout(3000);
urlc.connect();
if (urlc.getResponseCode() == 200) {
return true;
}
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return false;
}
@Override
protected void onPostExecute(Boolean th){
if(th == true){
nDialog.dismiss();
new GetData().execute();
}
else{
nDialog.dismiss();
Toast.makeText(getApplicationContext(), "Error in Network Connection", Toast.LENGTH_SHORT).show();
}
}
}
/**
* Async Task to get data from URL
**/
private class GetData extends AsyncTask<String, String, String> {
private ProgressDialog pDialog;
private InputStream is = null;
private String url = "http://www.kelidestan.com/fixed-url/kelidestan-2.php";
private String page_output = "";
@Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(MainActivity.this);
pDialog.setTitle("Contacting Servers");
pDialog.setMessage("Logging in ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
@Override
protected String doInBackground(String... args) {
try {
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("country", "iran"));
params.add(new BasicNameValuePair("age", "27"));
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
page_output = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
return page_output;
}
@Override
protected void onPostExecute(String page_output) {
pDialog.dismiss();
try {
// display output of internet page (page_output string)
TextView tv = (TextView) findViewById(R.id.textView1);
tv.setText(page_output);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
اگر در کدها دقت کنید، دو بار از AsyncTask استفاده کرده ایم. در واقع، دو کلاس (class) تعریف کرده ایم که هر کدام به صورت AsyncTask می باشند. AsyncTask به این صورت است که ابتدا یک ProgressDialog به شما نمایش داده می شود تا بدانید که یک سری فرآیند (کد) در حال اجرا شدن می باشد، سپس پس از پایان اجرای کدها، آن ProgressDialog ناپدید شده و نتیجه به شما نمایش داده می شود (یا هر مورد دیگر). استفاده از AsyncTask بسیار مهم می باشد زیرا همیشه باید کدهایی را که نمی دانیم اجرای آنها چه مدت طول می کشد را با AsyncTask اجرا کنیم.
کلاس اول دارای نام NetCheck می باشد و برای چک کردن اتصال به اینترنت به کار می رود. سپس اگر گوشی کاربر به اینترنت متصل باشد، کلاس دوم که دارای نام GetData است، فراخوانی می شود. اگر به کدهای روش onCreate دقت کنید، ابتدا با کد زیر، کلاس NetCheck را اجرا می کنیم :
کلاس NetCheck ، وضعیت اتصال به اینترنت را چک می کند و اگر گوشی کاربر به اینترنت متصل باشد، آنگاه کلاس GetData را اجرا خواهد کرد که برای دریافت اطلاعات از آدرس اینترنتی می باشد.
به کدهای زیر دقت کنید :
// Building Parameters
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("country", "iran"));
params.add(new BasicNameValuePair("age", "27"));
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
page_output = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
در کدهای فوق، متغیر url به صورت رشته (string) می باشد که آدرس URL صفحه اینترنتی در آن ذخیره شده است. با استفاده از httpPost ، اطلاعات را از صفحه اینترنتی دریافت کرده ایم و سپس خروجی صفحه در یک رشته با نام page_output ذخیره می شود (که بعدا آن را در TextView نمایش خواهیم داد).
اگر برنامه را بر روی یک گوشی واقعی نصب کنیم، نتیجه به صورت زیر خواهد بود (البته قبل از نمایش نتیجه، دو بار، ProgressDialog نمایش داده می شود) :
فایل های پروژه اندروید را می توانید از لینک های زیر دریافت کنید :