برنامه همیشه از یک صفحه تشکیل نمی شود. به عنوان مثال، ما یک بسیار ایجاد کرده ایم برنامه مفیدو کاربر می خواهد بداند نویسنده کیست. او روی دکمه "درباره" کلیک می کند و به صفحه جدیدی می رسد که در آن اطلاعات مفیدی در مورد نسخه برنامه، نویسنده، آدرس سایت، تعداد گربه های نویسنده و غیره وجود دارد. یک صفحه فعالیت را به عنوان یک صفحه وب با پیوند به صفحه دیگر در نظر بگیرید. اگر به کد داخل فایل نگاه کنید MainActivity.javaاز درس های قبلی، خواهید دید که کلاس ما فعالیت اصلینیز اعمال می شود فعالیت(یا ورثه او) یا به عبارت دقیق تر از او به ارث رسیده است.
کلاس عمومی MainActivity AppCompatActivity را گسترش می دهد
همانطور که ممکن است حدس بزنید، ما باید یک کلاس جدید ایجاد کنیم که ممکن است شبیه به آن باشد فعالیت اصلیو سپس با کلیک روی دکمه به نحوی به آن تغییر دهید.
برای آزمایش، برنامه را از درس اول می گیریم و از دکمه آزمایش ها (یا ایجاد پروژه جدیدبا یک دکمه روی صفحه). بعد، بیایید ایجاد کنیم فرم جدیدبرای نمایش اطلاعات مفید. به عنوان مثال، اجازه دهید به کاربر نشان دهیم که گربه وقتی به چپ و راست می رود چه می کند. موافقم، خیلی است اطلاعات مهم، که کلید کشف جهان را می دهد.
ما یک اکتیویتی جدید را به صورت دستی ایجاد خواهیم کرد، اگرچه استودیو دارای قالب های آماده است. اما هیچ چیز پیچیده ای وجود ندارد و برای درک بهتر انجام همه کارها با دست مفید است.
بیایید یک فایل نشانه گذاری XML جدید ایجاد کنیم activity_about.xmlدر پوشه res/layout. روی پوشه کلیک راست کنید چیدمانو انتخاب کنید منوی زمینه جدید | فایل منبع چیدمان. یک جعبه گفتگو ظاهر خواهد شد. در فیلد اول نام فایل را وارد کنید فعالیت_درباره. در مرحله دوم، باید عنصر ریشه را وارد کنید. به طور پیش فرض وجود دارد ConstraintLayout. متن را پاک کنید و وارد کنید اسکرول نمای. وارد کردن چند کاراکتر کافی است تا استودیو گزینه های آماده را پیشنهاد دهد، می توانید بلافاصله Enter را فشار دهید بدون اینکه منتظر ورودی کامل کلمه باشید:
جای خالی مربوطه را می گیریم که عنصر را در آن وارد می کنیم نمای متنی.
اطلاعات از منابع، یعنی از یک منبع رشته ای بازیابی خواهد شد about_text. اکنون با رنگ قرمز مشخص شده است که نشان دهنده عدم وجود اطلاعات است. می توان فشار داد Alt+Enterو متن را در کادر محاوره ای وارد کنید. اما برای مثال ما، این روش کار نخواهد کرد، زیرا متن ما با استفاده از کاراکترهای کنترلی چند خطی خواهد بود. پس بیایید آن را متفاوت انجام دهیم. بیایید فایل را باز کنیم res/values/strings.xmlو متن زیر را به صورت دستی وارد کنید:
ما از سادهترین تگهای قالببندی متن HTML مانند استفاده کردیم , , . برای مثال ما کافی است کلماتی را که به گربه و جهت حرکت اشاره می کنند پررنگ کنیم. برای ترجمه متن به خط جدیداز نمادها استفاده کنید \n. بیایید یک منبع رشته ای دیگر برای عنوان صفحه جدید اضافه کنیم:
با نشانه گذاری قابل درک است. بعد، باید یک کلاس برای پنجره ایجاد کنید AboutActivity.java. از منو انتخاب کنید فایل | جدید | کلاس جاواو فیلدهای مورد نیاز را پر کنید. در ابتدا کافی است فقط نام را مشخص کنید. سپس به حوزه های دیگر بپردازید.
بیایید آماده سازی را انجام دهیم.
اکنون کلاس تقریباً خالی است. بیایید کد را به صورت دستی اضافه کنیم. کلاس باید از کلاس انتزاعی ارث ببرد فعالیتیا بستگانش FragmentActivity, AppCompatActivityو غیره. اضافه كردن فعالیت را گسترش می دهد. کلاس اکتیویتی باید متد داشته باشد onCreate(). نشانگر ماوس را داخل کلاس قرار داده و از منو انتخاب کنید کد | روشهای لغو(Ctrl+O). در کادر محاوره ای ما به دنبال کلاس مورد نظر هستیم که می توانید اولین کاراکترهای صفحه کلید را برای آن تایپ کنید جستجوی سریع. در متد ایجاد شده، باید متد را فراخوانی کنید setContentView()، که نشانه گذاری آماده شده را روی صفحه بارگذاری می کند. ما چنین گزینه ای خواهیم داشت.
Package en.alexanderklimov.helloworld; وارد کردن android.app.Activity; وارد کردن android.os.Bundle; /** * ایجاد شده توسط Alexander Klimov در 12/01/2014. */ کلاس عمومی AboutActivity فعالیت را گسترش میدهد ( @Override محافظت شده است void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about)؛ ))
اکنون مهمترین چیز شروع می شود. وظیفه ما این است که با کلیک روی یک دکمه در صفحه اول، به صفحه جدیدی برویم. برگردیم سر کلاس فعالیت اصلی. اجازه دهید کنترل کننده کلیک دکمه را بنویسیم:
Public void onClick(View view) ( Intent intent = New Intent (MainActivity.this, AboutActivity.class)؛ startActivity(intent)؛ )
در اینجا از روش مدیریت کلیک روی دکمه توضیح داده شده در درس استفاده کردم.
برای شروع یک صفحه جدید، باید یک نمونه از کلاس ایجاد کنید قصدو کلاس فعلی را در پارامتر اول و کلاس انتقال را در پارامتر دوم مشخص کنید، این را داریم درباره فعالیت. پس از آن متد فراخوانی می شود startActivity()، که صفحه جدیدی را راه اندازی می کند.
اگر اکنون سعی کنید برنامه را در شبیه ساز تست کنید، یک پیام خطا دریافت خواهید کرد. چه اشتباهی کردیم؟ ما یک قدم مهم را از دست دادیم. شما نیاز به ثبت نام جدید دارید فعالیتدر مانیفست AndroidManifest.xml. این فایل را در پروژه خود پیدا کنید و روی آن دوبار کلیک کنید. پنجره ویرایش فایل باز می شود. یک برچسب جدید اضافه کنید
اینجاست که منبع رشته به کار می آید about_title. برنامه را اجرا کنید، روی دکمه کلیک کنید و پنجره را دریافت کنید در مورد برنامه. بنابراین، ما یاد گرفتیم که چگونه یک پنجره جدید ایجاد کنیم و آن را با کلیک روی دکمه فراخوانی کنیم. و یک برنامه فوق العاده راحت در اختیار ما قرار گرفته است - اکنون همیشه اشاره ای وجود دارد که گربه هنگام رفتن به سمت چپ چه می کند.
یک بار دیگر توجه شما را به این نکته جلب می کنم که دومین کلاس اکتیویتی ایجاد شده باید از کلاس به ارث برده شود فعالیتیا مشابه ( ListActivityو غیره)، یک فایل نشانه گذاری XML (در صورت نیاز) داشته باشید و در مانیفست نوشته شود.
پس از فراخوانی روش startActivity()یک فعالیت جدید شروع خواهد شد (در این مورد درباره فعالیت، قابل مشاهده می شود و به بالای پشته حاوی اجزای در حال اجرا منتقل می شود. هنگام فراخوانی یک روش پایان ()از اکتیویتی جدید (یا زمانی که کلید backspace سخت افزاری فشار داده می شود) بسته می شود و از پشته حذف می شود. توسعه دهنده همچنین می تواند با استفاده از همین روش به فعالیت قبلی (یا هر فعالیت دیگری) پیمایش کند startActivity().
ایجاد صفحه سوم - راهی برای تنبل ها
برنامه نویسان نیز مانند گربه ها موجوداتی تنبل هستند. همیشه به یاد داشته باشید که برای فعالیت باید نشانه گذاری و کلاسی که از آن ارث می برد ایجاد کنید فعالیت، و سپس فراموش نکنید که کلاس را در مانیفست ثبت کنید - اوه خوب، چه جهنمی.
در این حالت از منو انتخاب کنید فایل | جدید | فعالیت | فعالیت اساسی(یا الگوی دیگر). در مرحله بعد، پنجره آشنا برای ایجاد یک فعالیت جدید ظاهر می شود. فیلدهای مورد نیاز را پر کنید.
روی دکمه کلیک کنید پایانو فعالیت آماده خواهد شد. برای تأیید این موضوع، فایل مانیفست را باز کنید و ورودی جدید را بررسی کنید. من در مورد فایل های کلاس و نشانه گذاری صحبت نمی کنم، آنها در مقابل شما ظاهر می شوند.
خودتان یک دکمه جدید روی صفحه اکتیویتی اصلی اضافه کنید و کد آن را بنویسید تا به فعالیت ایجاد شده بروید.
در ابتدا، من به شما توصیه می کنم که به صورت دستی تمام اجزای لازم برای یک فعالیت جدید را ایجاد کنید تا رابطه بین کلاس، نشانه گذاری و مانیفست را درک کنید. و هنگامی که به دستتان رسید، می توانید از جادوگر ایجاد فعالیت برای سرعت بخشیدن به کارها استفاده کنید.
انتقال داده ها بین فعالیت ها
ما از ساده ترین مثال برای فراخوانی یک صفحه فعالیت دیگر استفاده کردیم. گاهی اوقات لازم است نه تنها یک صفحه نمایش جدید را فراخوانی کنید، بلکه داده ها را به آن منتقل کنید. مثلا نام کاربری. در این مورد، شما باید از یک منطقه خاص استفاده کنید اطلاعات اضافی، که کلاس دارد قصد.
منطقه اطلاعات اضافییک لیست از جفت است ارزش کلیدی، که همراه با قصد منتقل می شود. رشته ها به عنوان کلید استفاده می شوند و برای مقادیر می توانید از انواع داده های اولیه، آرایه های اولیه، اشیاء کلاس استفاده کنید. دستهو غیره.
برای ارسال داده به یک فعالیت دیگر، از روش استفاده کنید putExtra():
Intent.putExtra("Key"، "Value");
فعالیت دریافت کننده باید روش مناسبی را فراخوانی کند: getIntExtra(), getStringExtra()و غیره.:
Int count = getIntent().getIntExtra("name", 0);
بیایید مثال قبلی را دوباره بسازیم. ما در حال حاضر سه فعالیت داریم. اولین فعالیت دارای دو فیلد متنی و یک دکمه خواهد بود. ظاهر ممکن است به شرح زیر باشد:
در فعالیت دوم SecondActivityعنصر را تنظیم کنید نمای متنی، که در آن متن دریافتی از اولین اکتیویتی را نمایش خواهیم داد. بیایید کد زیر را برای متد بنویسیم onCreate()در فعالیت دوم
@Override void protected onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState)؛ setContentView(R.layout.activity_second)؛ String user = "Animal"؛ String gift = "donut hole"؛ TextView infoTextView=dT .id.textViewInfo)؛ infoTextView.setText(user + "، به شما " + هدیه داده شد)؛ )
اگر اکنون برنامه را اجرا کنیم و به سادگی پنجره دوم را فراخوانی کنیم، همانطور که در قسمت اول مقاله توضیح داده شد، کتیبه پیش فرض را خواهیم دید. ZhYvotnoe، به شما یک سوراخ دونات داده شد. موافقم، دریافت چنین پیام هایی مایه شرمساری است.
ما وضعیت را درست می کنیم. اضافه کردن کد به فعالیت اول:
خالی عمومی onClick(نمایش) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser)؛ EditText giftEditText = (EditText) findViewById(R.id.editTextGift)؛ Intent intent = SecondActivity. class)؛ // متن را از اولین فیلد متنی به کلید نام کاربری فشار دهید intent.putExtra("username", userEditText.getText().toString())؛ // متن را از قسمت متن دوم به کلید هدیه فشار دهید. intent.putExtra("gift", giftEditText.getText().toString()); startActivity(intent); )
ما در ظرف مخصوص شی قرار دادیم قصددو کلید با مقادیر گرفته شده از فیلدهای متنی. هنگامی که کاربر داده ها را در فیلدهای متنی وارد می کند، در این ظرف قرار می گیرد و به اکتیویتی دوم منتقل می شود.
فعالیت دوم باید برای دریافت گرم پیام ها به شرح زیر آماده باشد (با پررنگ برجسته شده است).
// مقادیر پیشفرض String user = "LIFE"; هدیه رشته = "سوراخ دونات"; user = getIntent().getExtras().getString("username"); gift = getIntent().getExtras().getString("gift"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , به شما داده شد " + هدیه);
اکنون این پیام چندان توهین آمیز به نظر نمی رسد، اما برای برخی حتی خوشایند است. در مثال های پیچیده، افزودن اعتبارسنجی در طول پردازش داده ها مطلوب است. موقعیت هایی وجود دارد که شما یک فعالیت دوم را با داده های خالی مانند شروع می کنید خالی، که می تواند برنامه را خراب کند.
در مورد ما، می دانیم که منتظر یک مقدار رشته هستیم، بنابراین کد را می توان به صورت زیر بازنویسی کرد:
intent intent = getIntent(); user = intent.getStringExtra("username");
User = getIntent().getStringExtra("username");
این برنامه یک اشکال دارد - مشخص نیست که از چه کسی احوالپرسی دریافت می کنیم. هر میمون خوش اخلاق هدیه ای از منبع ناشناس را نمی پذیرد. بنابراین برای تکالیف، یک فیلد متنی دیگر اضافه کنید تا نام کاربری که پیام را ارسال می کند وارد کنید.
گوگل استفاده از فرمت زیر را برای کلیدها توصیه می کند: نام بسته شما به عنوان پیشوند و به دنبال آن خود کلید. در این صورت، می توانید مطمئن باشید که کلید در تعامل با سایر برنامه ها منحصر به فرد است. تقریباً به این صورت:
عمومی نهایی استاتیک String USER = "ru.alexanderklimov.myapp.USER";
چه کسی گربه واسکا را قاب کرد - نتیجه را پس می گیریم
همیشه انتقال داده ها به یک فعالیت دیگر کافی نیست. گاهی اوقات شما نیاز دارید که اطلاعاتی را از یک فعالیت دیگر پس از بسته شدن دریافت کنید. اگر قبلا از روش استفاده می کردیم startActivity (نیت قصد)، سپس یک روش مرتبط وجود دارد startActivityForResult (هدف، int RequestCode). تفاوت بین روش ها در پارامتر اضافی نهفته است کد درخواست. این اساسا فقط یک عدد صحیح است که می توانید در مورد خودتان فکر کنید. برای تشخیص اینکه نتیجه از چه کسی به دست آمده است ضروری است. فرض کنید پنج صفحه اضافی دارید و مقادیری از 1 تا 5 را به آنها اختصاص می دهید و از این کد می توانید تعیین کنید که نتیجه چه کسی را باید پردازش کنید. می توانید از مقدار -1 استفاده کنید، سپس معادل فراخوانی متد خواهد بود startActivity()، یعنی هیچ نتیجه ای نخواهیم گرفت
اگر از روش استفاده می کنید startActivityForResult()، سپس برای دریافت نتیجه باید روش موجود در کد را لغو کنید onActivityResult()و نتیجه را پردازش کنید. سردرگم؟ بیایید نگاهی به یک مثال بیندازیم.
فرض کنید شما یک کارآگاه هستید. اطلاعاتی مبنی بر سرقت دو قطعه سوسیس و کالباس از میز یکی از افراد ذی نفوذ رستوران به دست آمد. سوء ظن به سه مظنون افتاد - یک کلاغ، یک سگ لعنتی و یک گربه واسکا.
یکی از بازدیدکنندگان مجموعهای از عکسها از آیفون پانتونی خود ارائه کرد:
شهادت یکی دیگر از شاهدان نیز وجود دارد: و واسکا گوش می دهد و می خورد.
ما یک پروژه جدید ایجاد می کنیم شرلوکبا دو فعالیت در صفحه اول یک دکمه برای تغییر به صفحه دوم و یک برچسب متنی وجود دارد که نام دزد را نشان می دهد.
صفحه دوم دارای یک گروه از دکمه های رادیویی است:
از آنجایی که ما منتظر پاسخ از صفحه دوم خواهیم بود، باید از روش استفاده کنیم startActivityForResult()در صفحه اول که در آن متغیر را ارسال می کنیم CHOOSE_THIEFبه عنوان یک پارامتر کد درخواست.
استاتیک نهایی خصوصی int CHOOSE_THIEF = 0; public void onClick(View v) (Intent questionIntent = New Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF)؛ )
به کد نگاه کنید. وقتی دکمه کلیک شد، با صفحه دوم کار می کنیم Activity را انتخاب کنیدو صفحه دوم را در انتظار نتیجه راه اندازی کنید.
به صفحه دوم می رویم و کد اکتیویتی دوم را می نویسیم.
عمومی نهایی static String THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent answerIntent = new Intent(); switch (v.getId()) ( case R.id.radioDog: answerIntent.putExtra (THIEF, "Fucking Dog"); break; case R.id .radioCrow: answerIntent.putExtra(THIEF، "Crow")؛ break؛ case R.id.radioCat: answerIntent.putExtra(THIEF، "اسب پرژوالسکی")؛ break; پیش فرض: break;) setResult(RESULT_OK، answerIntent)؛ پایان ();)
همه چیز در اینجا ساده است، وقتی کارآگاه نام مجرم را انتخاب می کند، سپس از طریق روش putExtra()نام کلید و مقدار آن را ارسال می کنیم.
برای راحتی کار، پس از انتخاب، بلافاصله پنجره دوم را می بندیم و مقدار را قبل از بسته شدن پاس می کنیم RESULT_OKتا مشخص شود که انتخاب انجام شده است. اگر کاربر صفحه را از طریق دکمه Back ببندد، مقدار ارسال می شود RESULT_CANCELED.
روش setResult()دو پارامتر را می گیرد: کد حاصل و خود نتیجه که به عنوان یک intent نشان داده می شود. کد به دست آمده می گوید که فعالیت با چه نتیجه ای به پایان رسید، به عنوان یک قاعده، یکی است فعالیت.RESULT_OK، یا فعالیت.RESULT_CANCELED. در برخی موارد، باید از کد بازگشتی خود برای مدیریت گزینههای خاص برنامه استفاده کنید. روش setResult()از هر مقدار صحیح پشتیبانی می کند.
اگر داده ها را به طور صریح از طریق دکمه ارسال می کنید، بهتر است یک روش اضافه کنید پایان ()برای بستن فعالیت دوم به عنوان غیر ضروری. اگر انتقال از طریق دکمه برگشت رخ دهد، این کار ضروری نیست.
اگر با فشار دادن دکمه برگشت سخت افزاری، فعالیت توسط کاربر بسته شده باشد، یا اگر روش پایان ()قبل از متد فراخوانی شد setResult()، کد به دست آمده روی تنظیم می شود RESULT_CANCELEDو intent برگشتی مقدار را نشان می دهد خالی.
به صفحه اول برمی گردیم. صفحه اول منتظر پاسخ از صفحه دوم است، بنابراین باید روشی را به کد اضافه کنید onActivityResult().
@Override void محافظت شده onActivityResult(int requestCode، int resultCode، intent data) (super.onActivityResult(requestCode, resultCode, data)؛ TextView infoTextView = (TextView) findViewById(R.id.textViewInfo)؛ اگر (CHOOSE_F=IE) if (resultCode == RESULT_OK) (String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else (infoTextView.setText("")؛ // پاک کردن متن) )
این روش انتظار داده های ورودی را با کد دارد CHOOSE_THIEF، و اگر چنین داده ای رسید، مقدار را از کلید استخراج می کند Activity.THIEF را انتخاب کنیدبا استفاده از روش getStringExtra. مقدار حاصل را به خروجی می دهیم نمای متنی(متغیر infoTextView). اگر از طریق دکمه Back به صفحه بازگشتیم، به سادگی متن را پاک می کنیم.
هنگامی که فعالیت فرزند در داخل مؤلفه والد بسته می شود، کنترل کننده شلیک می کند onActivityResult(). کنترل کننده onActivityResult()چندین پارامتر می گیرد
- کد درخواست. کد مورد استفاده برای راه اندازی فعالیتی که نتیجه را برمی گرداند
- کد حاصل کد نتیجه تنظیم شده توسط فعالیت کودک که نشان می دهد فعالیت کودک چگونه به پایان رسیده است. می تواند هر عدد صحیحی باشد، اما معمولاً هر دو فعالیت.RESULT_OK، یا فعالیت.RESULT_CANCELED
- داده ها. هدفی که برای بسته بندی داده های برگشتی استفاده می شود. بسته به هدف فعالیت کودک، ممکن است شامل یک مسیر URI باشد که محتوای انتخاب شده را نشان می دهد. از طرف دیگر (یا علاوه بر این)، یک فعالیت فرزند می تواند اطلاعات را به صورت مقادیر ساده پیچیده شده در یک پارامتر intent برگرداند. اضافی
اگر فعالیت فرزند به طور غیرمنتظره به پایان برسد، یا اگر هیچ کد نتیجه ای قبل از بستن آن مشخص نشده باشد، این پارامتر برابر با فعالیت.RESULT_CANCELED.
پروژه را شروع می کنیم، روی دکمه کلیک می کنیم و به صفحه دوم می رویم. در آنجا یکی از گزینه ها را انتخاب می کنیم. اگر کلاغی را انتخاب کنید، صفحه بسته می شود و نام مجرم در صفحه اول نمایش داده می شود. اگر سگی را انتخاب کنید، نام او نمایش داده می شود.
ضمنا اگر گربه را انتخاب کنید نامش نمایش داده نمی شود! بررسی کنید و خودتان ببینید. خواهید پرسید چرا؟ واتسون ابتدایی! مجرم یک جزئیات مهم را در نظر نگرفت. رستوران تحت نظارت دوربین های فیلمبرداری بود و ضبط نشان می داد که واقعاً چه کسی سوسیس را دزدیده و گربه را قاب کرده است. واسکا، صبر کن!
P.S. اگر در ابتدا چیزی غیرقابل درک به نظر می رسید ، با تمرین خیلی چیزها روشن می شود. انتقال داده ها بین صفحه نمایش ها در برنامه ها رایج است و شما مثال را بیش از یک بار مطالعه خواهید کرد.
P.P.S. بهترین ماهی کالباس است. با دانستن این ضعف، قاب گرفتن گربه کار سختی نبود.
استفاده از فیلترها
در مقاله، من یک روش متداول را برای تغییر به یک فعالیت دیگر، زمانی که در روش هستید، نشان دادم startActivity()کلاس فعلی و کلاس به انتقال نشان داده شده است. به هر حال، کلاس اکتیویتی نباید بخشی از برنامه شما باشد. اگر نام یک کلاس را از یک برنامه دیگر می دانید، می توانید به آن نیز تغییر دهید. اما میتوانید به روشی دیگر به فعالیت دیگری بروید.
در عمل کمتر رایج است، اما مفید است. فرض کنید شما در حال حاضر یک فعالیت دوم دارید. در مانیفست، یک فیلتر خاص به آن اضافه کنید:
و اکتیویتی دوم را از طریق یک دکمه به این ترتیب راه اندازی می کنیم.
Public void onClick(View View) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity"); )
بیایید یک رشته طولانی را با یک ثابت جایگزین کنیم.
رشته نهایی ثابت عمومی ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick(View view) ( startActivity(new intent(ACTION_SECOND_ACTIVITY))؛ )
پس چه کرده ایم. برای فعالیت دوم، یک فیلتر ثبت کرده ایم و نامی برای آن مشخص کرده ایم عملدر صفت android:name. برای راحتی، فقط نام کامل فعالیت را با نام بسته در آن قرار دادم. سازنده کلاس قصدچندین نسخه اضافه بار دارد. در یک نسخه، می توانید یک رشته برای عمل مشخص کنید. ما اقدام ایجاد شده خود را نشان دادیم که در فعالیت دوم ثبت شده است. این سیستم در حین کار به مانیفست تمام برنامه های نصب شده نگاه می کند. هنگام جستجوی یک مسابقه، سیستم فیلتر ما را پیدا کرده و فعالیت مورد نظر را راه اندازی می کند.
با همین اصل می توانید فعالیت های دیگری را شروع کنید. به یک مثال نگاه کنید. اگر مثال را برای خود کپی کنید و به مستندات آن نگاه کنید android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS، خواهید دید که این کد با یک ثابت رشته مطابقت دارد عمومی ثابت نهایی java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". با کد ما مقایسه کنید می توانید فرض کنید که فعالیت تنظیمات برای حالت آفلاین دارای این خط در فیلتر است.
نام دسته فیلتر android.intent.category.DEFAULTبه سیستم می گوید که اقدام پیش فرض را انجام دهد، یعنی شروع فعالیت. نام های دیگری هم هستند که هنوز مورد توجه ما نیستند.
و حالا یک سوال پیچیده اگر یک اکتیویتی دیگر ایجاد کنید و همان فیلتر اکتیویتی دوم را مشخص کنید چه اتفاقی می افتد؟ و بیایید بررسی کنیم. یک اکتیویتی سوم برای خود ایجاد کنید و بلوک را با فیلتر از اکتیویتی دوم در آن کپی کنید.
در اولین اکتیویتی روی دکمه کلیک می کنیم. سیستم از شما می خواهد که گزینه مورد نظر را انتخاب کنید.
اگر مورد را انتخاب کنید همیشهسپس دفعه بعد شما مجبور به انتخاب نخواهید بود. برای تنظیم مجدد انتخاب، به ویژگی های برنامه در تنظیمات بروید و دکمه را پیدا کنید پاک کردن پیش فرض ها.
راه اندازی یک فعالیت با نام آن
در سازنده قصدپارامتر دوم کلاس است. اما بیایید فرض کنیم که نوعی پایگاه داده وجود دارد که نام فعالیت ها در آن مشخص شده است و باید فعالیت مورد نظر را با نام آن راه اندازی کنیم. میتوانیم خود کلاس را بر اساس متغیر رشته دریافت کنیم و فعالیت را شروع کنیم.
(// نام کامل کلاس اکتیویتی را امتحان کنید String activityName = "ru.alexanderklimov.testapplication.SecondActivity"؛ // شی Class Class را دریافت کنید>myClass = Class.forName(activityName); Intent intent = New Intent(this, myClass); startActivity(intent); ) catch (ClassNotFoundException e) (e.printStackTrace();)
به نوعی وظیفه انتقال داده از سرویس به اکتیویتی را داشتم. جستجوی راه حل در SDK استاندارد شروع شد، اما از آنجایی که زمان وجود نداشت، تصمیم بدی در قالب استفاده از پایگاه داده گرفتم. اما سوال باز بود و بعد از مدتی روش صحیح تری را که در SDK وجود دارد پیدا کردم - با استفاده از کلاس های Message، Handler، Messenger.
اندیشه
ما باید داده ها را از فعالیت به سرویس منتقل کنیم و بالعکس. چگونه میتوانیم آنرا انجام دهیم؟ برای حل مشکل خود، ما در حال حاضر همه چیز مورد نیاز خود را داریم. تنها چیزی که نیاز است این است که سرویس را با استفاده از bindService به اکتیویتی متصل کنید، پارامترهای لازم و کمی جادو را در قالب استفاده از کلاس های Message ارسال کنید. و جادو این است که از متغیرهای نمونه پیام و به ویژه replyTo استفاده کنید. ما به این متغیر نیاز داریم تا بتوانیم به نمونه سرویس مسنجر از Activity و در سرویس به نمونه مسنجر فعالیت دسترسی داشته باشیم. در واقع، به این سادگی نیست. حداقل به ذهن نه چندان مستعد من. تا حدی من فقط اسناد موجود را بهبود میدهم - خدمات همچنین، یک مثال خوب در StackOverflow وجود دارد. در هر صورت، امیدوارم مقاله حداقل برای کسی مفید باشد و من بیهوده کار نکردم.
مثال
به عنوان مثال، ما سرویسی را پیاده سازی می کنیم که مقدار شمارنده را افزایش و کاهش می دهد و نتیجه را در یک اکتیویتی در یک TextView برمی گرداند. من کد طرح بندی را حذف می کنم، زیرا دو دکمه و یک فیلد متنی وجود دارد - همه چیز ساده است.
پیاده سازی
این هم کد فعال سازی کامل:
کلاس عمومی MainActivity فعالیت را گسترش می دهد ( TAG نهایی استاتیک عمومی = "TestService"؛ TestServiceConnection testServConn؛ TextView testTxt؛ نهایی مسنجر مسنجر= مسنجر جدید (IncomingHandler جدید ()); پیام رسان به سرویس مسنجر؛ @Override public void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState)؛ setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt)؛ bindclass.Tests. )، (testServConn = New TestServiceConnection())، Context.BIND_AUTO_CREATE؛ ) @Override public void onDestroy()( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(View Messsage.)g get(null, TestService.COUNT_PLUS)؛ msg.replyTo = مسنجر؛ امتحان کنید ( toServiceMessenger.send(msg)؛ ) catch (RemoteException e) (e.printStackTrace(); ) ) count public voidDecrClick(دکمه مشاهده)( پیامک Message.obtain(null, TestService.COUNT_MINUS)؛ msg.replyTo = مسنجر؛ امتحان کنید ( toServiceMessenger.send(msg)؛ ) catch (RemoteException e) (e.printStackTrace(); ) ) کلاس خصوصی IncomingHandler Handler عمومی را گسترش می دهد (@Override void handleMessage(Message msg)( switch (msg.what) ( case TestServic e.GET_COUNT: Log.d(TAG، "(فعالیت)...دریافت تعداد"); testTxt.setText(""+msg.arg1); زنگ تفريح؛ ) ) ) کلاس خصوصی TestServiceConnection ServiceConnection را پیاده سازی می کند (@Override public void onServiceConnected(ComponentName name, IBinder service) ( toServiceMessenger = new Messenger(service); //send مقدار اولیه counter Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = پیام رسان; msg.arg1 = 0; // شمارنده ما را امتحان کنید ( toServiceMessenger.send(msg)؛ ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
بگذار توضیح بدهم. هنگام ایجاد یک اکتیویتی، ما بلافاصله با پیاده سازی رابط ServiceConnection به سرویس متصل می شویم و پیامی را به سرویس ارسال می کنیم "مقدار شمارنده" را در آن تنظیم کنید، با عبور از صفر و ایجاد یک toServiceMessanger، رابط IBinder را به سازنده ارسال می کنیم. به هر حال، این نمونه باید در سرویس برگردانده شود، در غیر این صورت NPE وجود خواهد داشت. با کمک این کلاس به سرویس پیام می فرستیم. و اینجا جادو است - در متغیر replyTo نمونه دیگری از مسنجر خود را ذخیره می کنیم - موردی که پاسخی از سرور دریافت می کند و از طریق آن است که ارتباط با فعالیت انجام می شود.
برای دریافت پیام از سرویس، از Handler خود استفاده می کنیم و به سادگی به دنبال متغیرهای مورد نیاز خود می گردیم و اقداماتی را روی آنها انجام می دهیم. با کلیک روی دکمه (روشهای countIncrClick، countDecrClick) درخواستهایی را به سرویس ارسال میکنیم و عمل مورد نظر را در متغیر msg.what مشخص میکنیم.
بسته com.example.servicetest; وارد کردن android.app.Service; وارد کردن android.content.*; وارد کردن android.os.*; وارد کردن android.os.Process; وارد کردن android.util.Log. کلاس عمومی TestService سرویس را گسترش می دهد (int نهایی استاتیک عمومی COUNT_PLUS = 1؛ عمومی استاتیک نهایی int COUNT_MINUS = 2؛ عمومی استاتیک نهایی int SET_COUNT = 0؛ عمومی استاتیک int نهایی GET_COUNT = 3؛ int count = 0؛ IncomingHandler inHandler؛ مسنجر مسنجر؛ مسنجر toActivityMessenger. = مسنجر جدید(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(intent intent, int flags, int startId) ( بازگشت START_STICKY; ) //message فعالیت کلاس خصوصی IncomingHandler Handler را گسترش می دهد ( عمومی IncomingHandler(Looper Looper)( super(looper); ) @Override public void handleMessage(پیام پیام)( //super.handleMessage(msg)؛ toActivityMess enger = msg.replyTo; سوئیچ (msg.what) ( مورد SET_COUNT: count = msg.arg1؛ Log.d (MainActivity.TAG، "(سرویس)...تعداد مجموعه")؛ شکست؛ مورد COUNT_PLUS: count++؛ Log.d (MainActivity.TAG , "(سرویس)... شمارش بعلاوه"؛ شکست؛ مورد COUNT_MINUS: Log.d(MainActivity.TAG, "(سرویس)... شمارش منهای"); شمارش--؛ شکست؛ ) //ارسال شمارنده مقدار در Activity Message outMsg = Message.obtain(inHandler, GET_COUNT); outMsg.arg1 = شمارش; outMsg.replyTo = پیام رسان; امتحان کنید ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg)؛ ) catch (RemoteException e) (e.printStackTrace(); ) ) )
همه با قیاس با منطق در فعالیت. حتی نمی دونم لازمه چیزی توضیح بدم یا نه. تنها نکته این است که من بلافاصله درخواست را به اکتیویتی در handleMessage برمی گردم و از متغیر replyTo جادویی برای این کار استفاده می کنم و مسنجر مورد نظر را در بالا بیرون می کشم. و نکته دومی که قبلا به آن اشاره کردم این است:
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
بدون آن همه چیز سقوط خواهد کرد. این نمونه رابط است که به ServiceConnection ارسال می شود
نتیجه
در مجموع. چنین مثال ساختگی از تعامل بین یک فعالیت و یک سرویس. به نظر من این یک تعامل نسبتاً بی اهمیت است، اگرچه ممکن است برای کسی متفاوت به نظر برسد.
سوالات، توضیحات و ... ممکن است در مورد هر جنبه ای نادرستی وجود داشته باشد، پس با خیال راحت بنویسید و تصحیح کنید.
امیدوارم پست برای خوانندگان مفید بوده باشد.
سلام.
انتقال داده های دریافتی از طریق UART به Activity ضروری است. این را می توان با ایجاد یک رشته در Activity انجام داد که در آن یک حلقه while (!isInterrupted()) سازماندهی شود و داده ها از بافر UART خوانده شود. پس از آن با فراخوانی رشته رابط کاربری Activity - MainActivity.this.runOnUiThread(new Runnable() اقدامات لازم را با این Activity انجام دهید.اما اگر سایر Activity ها را از Activity اصلی فراخوانی کنیم، رشته سازماندهی شده اجازه عبور نمی دهد. دادهها به فعالیتهای تازه ایجاد شده. اگر به درستی متوجه شده باشم که برای اینکه دادههای جریان به هر فعالیتی منتقل شوند، جریان باید نه در Activity، بلکه در سرویس ایجاد شود.
سوال: داده ها از طریق UART آمده است، در تاپیک (که در Servce ایجاد می شود) باید اطلاعات را به Activity منتقل کرد که اکنون فعال است، چگونه می توان این کار را انجام داد و آیا اصلا انجام می شود؟
1 پاسخ
در هر فعالیت، یک Handler ایجاد کنید. در متد onResume() این Activity، bindService() انجام می شود. در آنجا یکی از پارامترها رابط ServiceConnection است. حداقل با همان Activity آن را اجرا کنید. متد onServiceConnected() را در آن پیاده سازی کنید. در این callback خود Service به عنوان یکی از پارامترها می آید. بنابراین این Service را متد ()setHandler خودتان صدا بزنید. Handler که در Activity فعلی است را به آنجا منتقل کنید. اما داده های دریافتی از طریق UART را در سرویس این Handler قرار دهید. به هر حال، Handler به طور سنتی روی رشته اصلی اجرا می شود، بنابراین runOnUiThread نیازی به اجرا نخواهد داشت.