در قسمت اول فصل پنجم آموزش اندروید ما سه مبحث SMS ها و اجرای Thread ها در پس زمینه و اتصال برنامه به اینترنت را درون یک پروژه قرار میدهیم و نحوه کارشان را بررسی میکنیم
در این قسمت یک پروژه حاوی سه Button که هرکدام عملیاتی در مباحث Sms , Thread , Http انجام میدهند ایجاد کرده ایم تا بیشتر با این مباحث کاربردی آشنا شویم.
پس شروع میکنیم و یک پروژه با نام دلخواه که ما از Utility استفاده کردیم ایجاد میکنیم
و در فایل activity_main.xml سه دکمه ایجاد میکنیم
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Click to send sms" android:id="@+id/btnsms" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="77dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click to fake thread" android:id="@+id/btnthread" android:layout_below="@+id/btnsms" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="click to download an image" android:id="@+id/btndownloadimage" android:layout_below="@+id/btnthread" android:layout_centerHorizontal="true" />
(مثل تمرین های قبل به صورت گرافیکی دکمه هارا ایجاد کنید و زحمت کدنویسی رو نکشید)حال به ترتیب برای هردکمه عملیاتش را تعریف میکنیم ابتدا دکمه SMS :
برای این دکمه یک اکتیویتی و یک فایل xml ایجاد میکنیم فایل xml شامل اجزا زیر است
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtphonenumber" android:layout_below="@+id/textView2" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Send Sms with Intent" android:id="@+id/sendsms" android:nestedScrollingEnabled="false" android:layout_gravity="center_horizontal" android:layout_below="@+id/txtsendwithintent" android:layout_centerHorizontal="true" android:layout_marginTop="46dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Back" android:id="@+id/btnback" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Phone Number" android:id="@+id/edittext" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_toLeftOf="@+id/sendsms" android:layout_toStartOf="@+id/sendsms" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Text of SMS" android:id="@+id/textView" android:layout_below="@+id/txtphonenumber" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtsmstext" android:layout_below="@+id/textView" android:layout_toRightOf="@+id/edittext" android:layout_toEndOf="@+id/edittext" /> <Button android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Send Sms without Intent" android:id="@+id/btnsendwithoutintent" android:nestedScrollingEnabled="false" android:layout_gravity="center_horizontal" android:layout_below="@+id/sendsms" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Phone Number" android:id="@+id/textView2" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" />
و فایل جاوا برنامه نیز از دونوع ارسال Sms استفاده میکند (یکی با استفاده از اینتنت ها و دیگری بدون استفاده از اینتنت)
package com.tejariapp.utility; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.telephony.SmsManager; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class SendSms extends Activity { public String fillnumber() { EditText edtphone = (EditText) findViewById(R.id.txtphonenumber); String phonenumber = edtphone.getText().toString(); return phonenumber; } public String filltext() { EditText edttext = (EditText) findViewById(R.id.txtsmstext); String text = edttext.getText().toString(); return text; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sms_layout); Button btn = (Button) findViewById(R.id.btnsendwithintent); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent sms = new Intent(Intent.ACTION_VIEW); sms.setData(Uri.parse("smsto:")); sms.setType("vnd.android-dir/mms-sms"); sms.putExtra("address", fillnumber()); sms.putExtra("sms_body",filltext()); try { startActivity(sms); finish(); Toast.makeText(SendSms.this, "Sms has been Send", Toast.LENGTH_SHORT).show(); } catch (android.content.ActivityNotFoundException ex) { Toast.makeText(SendSms.this, "Faild to Send Sms", Toast.LENGTH_SHORT).show(); } } }); Button btnsintent=(Button)findViewById(R.id.btnsendwithoutintent); btnsintent.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { SmsManager sms=SmsManager.getDefault(); sms.sendTextMessage(fillnumber(),null,filltext(),null,null); Toast.makeText(SendSms.this, "Sms has been Send Check Messages", Toast.LENGTH_SHORT).show(); } }); Button btnback=(Button)findViewById(R.id.btnback); btnback.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(SendSms.this, MainActivity.class); startActivity(intent); } }); } }
همانگونه که مشخص است در روش ارسال پیام با اینتنت از یک شی اینتنت و از putExtra برای مشخص کردن متن و شماره استفاده شده و در نتیجه نیز برنامه Sms درون دستگاه اندروید با مشخصاتی که در این برنامه(درون EditText ها) مشخص میشود نمایش داده میشود
و در روش ارسال بدون اینتنت , خود برنامه پیام را ارسال میکند و دیگر از برنامه sms درون دستگاه استفاده نمیکن(بهتر است از یک دستگاه اندرورید به جای شبیه ساز های کامپیوتر استفاده کنید)
فراموش نکنید که در فایل manifest برنامه نیز باید این کلاس جاوا و همچنین مجوز استفاده از برنامه Sms درون دستگاه را تعریف کنیم بدین صورت
<uses-permission android:name="android.permission.SEND_SMS" /> <activity android:name=".SendSms" android:label="@string/app_name" />
دکمه دوم در فایل xml اصلی مربوط به یک Thread ساختگی یا fake میباشد و هدف تنها آشنایی بیشتر با این سیستم است.نکته اصلی در استفاده از سرویس ها پشتیبانی کلاس جاوا از کلاس Service است و همچنین نحوه مشخص کردن این کلاس در manifest برنامه است که بدین صورت نوشته میشود
<service android:name=".Thread"/>
ودرون کلاس این سرویس نیز که هدف اصلی آن اجرای سرویس در پس زمینه میباشد چنین کدنویسی میکنیم
package com.tejariapp.utility; import android.app.Service; import android.content.Intent; import android.os.AsyncTask; import android.os.IBinder; import android.widget.Toast; import java.net.MalformedURLException; import java.net.URL; import static android.widget.Toast.LENGTH_SHORT; public class Thread extends Service { @Override public IBinder onBind(Intent intent) { return null; } @Override public int onStartCommand(Intent intent, int flags,int startId){ /* int result=DownloadFile(); Toast.makeText(Thread.this, "Doenload" + result + "byte", Toast.LENGTH_SHORT).show();*/ try{ new DoBackgroundTask().execute( new URL("http://www.amazon.com/file.pdf"), new URL("http://www.amazon.com/file.pdf"), new URL("http://www.amazon.com/file.pdf"), new URL("http://www.amazon.com/file.pdf") ); } catch (MalformedURLException e) { e.printStackTrace(); } return START_STICKY; } private int DownloadFile(URL url) { try { java.lang.Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return 100; } private class DoBackgroundTask extends AsyncTask<URL,Integer,Long>{ protected Long doInBackground(URL... urls){ int count=urls.length; long totalByteDownload=0; for(int i=0;i<count;i++){ totalByteDownload +=DownloadFile(urls[i]); publishProgress((int) (((i+1)/(float)count)*100)); } return totalByteDownload; } protected void onProgressUpdate(Integer... progress){ Toast.makeText(Thread.this, String.valueOf(progress[0]) + "% downloaded", Toast.LENGTH_SHORT).show(); } protected void onPostExecute(Long result){ Toast.makeText(Thread.this, "Doenload" + result + "byte", Toast.LENGTH_SHORT).show(); stopSelf(); } } @Override public void onDestroy(){ super.onDestroy(); Toast.makeText(Thread.this, "Servic Destroy", LENGTH_SHORT).show(); } }
همانگونه که مشاهده میکنید ما از یک کلاس درونی که از AsyncTask پشتیبانی میکند استفاده کرده ایم تا قابلیت اجرای سرویس در پس زمینه بدون کنترل مستقیم کاربر را به ما بدهد و سه ژنریک URL ,Integer , Long که نوع های داده های مورد استفاده در سه متد را مشخص میکنند.
برای توضیح هر متد میتوان کوتاه گفت متد doInBackground براساس تعداد Url هایی که دریافت میکند عملیات زمان بری را اجرا میکند در این بخش از متد publishProgress استفاده شده که برای گزارش پیشرفت استفاده میشود و همچنین در ادامه متد onProgressUpdate را فراخوانی میکند.
متد onProgressUpdate که توسط متد publishProgress فراخوانی میگردد برای نمایش پیشرفت سرویس به کار بکار میرود.
متد onPostExecute زمانی اجرا میشود که متد doInBackground کارش تمام شده باشد مقدار بایتی که دانلود شده را در انتها به کاربر نمایش میدهد.
و در انتها نیز متد onDestroy اجرا میشود.
(این بخش نیازی به فایل xml نداشت چون نتایح بصورت پیغام Toast به کاربر نمایش داده شد)
و کلید اخر که کلید دانلود تصویر میباشد و هدف وارد کردن یک url تصویر و دیدن تصویر در یک ImageView میباشد.پس یک فایل جاوا و یک xml ایجاد میکنیم و درون فایل xml ابزارهای زیر را ایجاد میکنیم
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Enter an Url" android:id="@+id/textView3" android:layout_gravity="left|center_horizontal" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txturl" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="show image" android:id="@+id/btnshow" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/img1"/>
و در فایل جاوا نیز چنین کدنویسی میکنیم
package com.tejariapp.utility; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ImageView; import android.widget.Toast; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; public class DownloadImage extends Activity { ImageView img; private InputStream OpenHttpConnection(String urlstring)throws IOException{ InputStream in=null; int response=-1; URL url=new URL(urlstring); URLConnection con=url.openConnection(); if(!(con instanceof HttpURLConnection)){ throw new IOException("Not a Http Connection"); } try{ HttpURLConnection httpcon=(HttpURLConnection) con; httpcon.setAllowUserInteraction(false); httpcon.setInstanceFollowRedirects(true); httpcon.setRequestMethod("GET"); httpcon.connect(); response=httpcon.getResponseCode(); if(response == HttpURLConnection.HTTP_OK){ in=httpcon.getInputStream(); } }catch (Exception e){ throw new IOException("Error Connectiong"); } return in; } private Bitmap Download(String url){ Bitmap bitmap=null; InputStream in=null; try{ in = OpenHttpConnection(url); bitmap= BitmapFactory.decodeStream(in); in.close(); } catch (IOException e) { e.getLocalizedMessage(); } return bitmap; } private class DownloadImageTask extends AsyncTask<String, Void,Bitmap>{ protected Bitmap doInBackground(String... urls){ return Download(urls[0]); } protected void onPostExecute(Bitmap result){ img=(ImageView)findViewById(R.id.img1); img.setImageBitmap(result); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.download_layout); Button btn=(Button)findViewById(R.id.btnshow); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { EditText url=(EditText)findViewById(R.id.txturl); new DownloadImageTask().execute(url.getText().toString()); } }); } }
متد openHttpConnection که یک ورودی Url نیز دارد اقدام به برقراری ارتباط با سرور میکند و یک شی InputStream را برمیگرداند.
در ادامه متد Download که از متد openHttpConnection برای برقراری ارتباط استفاده میکند را مشاهده میکنید.همچنین در این متد از یک شی Bitmap که برای تبدیل اطلاعات دانلود شده به bitmap از متدdecodeStream استفاده میکند در نهایت این شی را به خروجی ارسال میکند.
همانگونه که مشاهده میکنید دراین بخش نیز از کلاس AsyncTask استفاده شده.این کلاس این قابلیت را به ما میدهد تا یک کار را در یک Thread دیگر انجام میدهد و نتیجه را به thread رابط کاربری ارسال میکند.که شامل دو متد است که عملیاتی که باید به صورت غیرهمزمان اجرا شود درون متد doInBackground قرار گرفته و زمان اتمام عملیات نتیجه ازطریق متد onPostExecute برگردانده میشود.
برای فراخوانی متد DownloadImageTask نیز هنگام فشردن کلید show باید یک شی ازنوع کلاس مربوطه ایجاد کرده و متد execute را نیز فراخوانی میکنیم و url را ارسال میکنیم تا تصویر را درون imageView نمایش دهد.
فراموش نکنید که در فایل manifest برنامه باید مجوز استفاده از اینترنت و اکتیویتی را بدین صورت تعریف کنیم
<uses-permission android:name="android.permission.INTERNET" /> <activity android:name=".DownloadImage> <android:label="@string/app_name" />