Сәлеметсіз бе.
UART арқылы алынған деректерді Әрекетке жіберу қажет. Бұл әрекетте уақытша циклды (!isInterrupted()) ұйымдастыратын және UART буферінен деректерді оқитын ағын жасау арқылы жасауға болады. Осыдан кейін, UI ағынын шақыру арқылы Activity - MainActivity.this.runOnUiThread(new Runnable() , осы әрекетпен қажетті әрекеттерді орындаңыз. Бірақ егер біз негізгі әрекеттен басқа Әрекеттерді шақырсақ, онда ұйымдастырылған ағын деректерді жіберуге рұқсат бермейді. жаңадан жасалған әрекеттерді дұрыс түсінсем, ағындағы деректер кез келген әрекетке тасымалдануы үшін ағын әрекетте емес, қызметте жасалуы керек.
Сұрақ: деректер UART арқылы келді, ағында (ол Сервседе жасалған) қазір белсенді әрекетке деректерді тасымалдау керек, мұны қалай жасауға болады және бұл орындалды ма?
1 жауап
Әрбір әрекетте өңдеуші жасайсыз. Осы әрекеттің onResume() әдісінде bindService() орындалады. Параметрлердің бірі ServiceConnection интерфейсі болып табылады. Оны кем дегенде бірдей әрекетпен жүзеге асырыңыз. Ондағы onServiceConnected() әдісін енгізіңіз. Бұл кері қоңырауда параметрлердің бірі Қызметтің өзі болып табылады. Сондықтан осы Қызметтің жеке setHandler() әдісін шақырыңыз. Ағымдағы әрекеттегі өңдеушіге өтіңіз. Бірақ кіріс деректерді UART арқылы осы өңдегіштегі Қызметке жіберіңіз. Айтпақшы, Handler дәстүрлі түрде негізгі ағында жұмыс істейді, сондықтан runOnUiThread қажет болмайды.
Соңғы жаңарту: 04.03.2018
Intent нысаны екі әрекет арасында деректерді тасымалдау үшін пайдаланылады. Оның putExtra() әдісі арқылы кілтті және онымен байланысты мәнді қосуға болады.
Мысалы, «Hello World» жолын «сәлем» пернесі ағымдағы әрекеттен SecondActivity-ке беру:
// SecondActivity іске қосу үшін Intent нысанын жасау Intent intent = new Intent(бұл, SecondActivity.class); // «сәлем» пернесі және «Hello World» мәні бар нысанды беру intent.putExtra("сәлем", "Hello World"); // іске қосу SecondActivity startActivity(inent);
Деректерді тасымалдау үшін ең қарапайым типтегі деректерді мән ретінде тасымалдауға мүмкіндік беретін putExtra() әдісі пайдаланылады - String, int, float, double, long, short, байт, char, осы типтегі массивтер немесе Serializable. интерфейс объектісі.
SecondActivity жүктелген кезде жіберілген деректерді алу үшін сіз нысан кілті арқылы берілетін get() әдісін пайдалана аласыз:
Бума аргументтері = getIntent().getExtras(); Жол атауы = arguments.get("сәлем").toString(); // Сәлем Әлем
Біз жіберіп жатқан деректер түріне байланысты біз оны алған кезде Bundle нысанында бірқатар әдістерді пайдалана аламыз. Олардың барлығы объект кілтін параметр ретінде қабылдайды. Негізгілері:
get() : Object түрінің мәнін қайтаратын жалпы әдіс. Сәйкесінше, қабылдау өрісі бұл мәнді қажетті түрге түрлендіруі керек
getString(): String нысанын қайтарады
getInt(): int мәнін қайтарады
getByte(): байт мәнін қайтарады
getChar(): таңба мәнін қайтарады
getShort() : short түріндегі мәнді қайтарады
getLong() : ұзын мәнді қайтарады
getFloat(): қалқымалы мәнді қайтарады
getDouble(): қос мәнді қайтарады
getBoolean(): логикалық мәнді қайтарады
getCharArray(): char нысандарының массивін қайтарады
getIntArray() : int нысандарының массивін қайтарады
getFloatArray() : қалқымалы нысандардың массивін қайтарады
getSerializable() : Серияланатын интерфейс нысанын қайтарады
Біздің жобада анықталған екі әрекетті алайық: MainActivity және SecondActivity.
SecondActivity кодында біз деректерді қабылдауды анықтаймыз:
com.example.eugene.serializeapp бумасы; android.support.v7.app.AppCompatActivity импорттау; android.os.Bundle импорттау; android.widget.TextView импорттау; жалпы класс SecondActivity AppCompatActivity кеңейтеді ( @Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(бұл); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16) ); Bundle аргументтері = getIntent().getExtras(); if(arguments!=null)( String name = arguments.get("name").toString(); String company = arguments.getString("компания"); int price = arguments.getInt("price"); textView.setText("Атауы: " + атауы + "\nКомпания: " + компания + "\nБағасы: " + бағасы ) setContentView(textView) )
Бұл жағдайда SecondActivity бағдарламасында біз Bundle нысанынан барлық деректерді аламыз және оны TextView мәтіндік өрісінде көрсетеміз. Бұл әрекетке үш элемент беріледі деп болжануда - кілттердің аты мен компаниясы бар екі жол және кілт бағасы бар сан.
Енді деректерді SecondActivity-ге тасымалдауды анықтайық. Мысалы, activity_main.xml файлында MainActivity үшін келесі интерфейсті анықтайық:
Мұнда деректерді енгізуге арналған үш мәтіндік өріс және түйме анықталған.
MainActivity класында біз келесі мазмұнды анықтаймыз:
com.example.eugene.serializeapp бумасы; android.content.Intent импорттау; android.support.v7.app.AppCompatActivity импорттау; android.os.Bundle импорттау; android.view.View импорттау; android.widget.EditText импорттау; жалпы класс MainActivity AppCompatActivity кеңейтеді ( @Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( соңғы EditText nameTextd(findViewBy) .name); final EditText companyText = findViewById(R.id.company); findViewById(R.id.price); price = Integer.parseInt(priceText.getText().toString()); intent.putExtra("баға",бастауActivity(ниет));
Түймені басу өңдегішінде біз EditText мәтіндік өрістеріне енгізілген деректерді аламыз және оны putExtra() әдісі арқылы Intent нысанына береміз. Содан кейін біз SecondActivity іске қосамыз.
Нәтижесінде, түймені басқан кезде, мәтіндік өрістерге енгізілген кейбір деректерді алатын SecondActivity іске қосылады.
Күрделі объектілерді тасымалдау
Жоғарыдағы мысалда қарапайым деректер жіберілді - сандар, жолдар. Бірақ біз одан да күрделі деректерді жібере аламыз. Бұл жағдайда сериялау механизмі қолданылады.
Мысалы, жобамызда анықталған Өнім класы бар делік:
com.example.eugene.serializeapp бумасы; java.io.Serializable импорттау; public class Өнімді іске асыру Serializable (жеке жол атауы; жеке жол компаниясы; жеке инт бағасы; жалпы өнім(жол атауы, жолдық компания, int бағасы)( this.name = атау; this.company = компания; this.price = баға; ) public String getName() ( қайтарылатын атау; ) public void setName(String name) ( this.name = name; ) public String getCompany() ( return company; ) public void setCompany(String company) ( this.company = company; ) public int getPrice() (қайтару бағасы; ) public void setPrice(int price) ( this.price = price; ) )
Айта кету керек, бұл класс Serializable интерфейсін жүзеге асырады. Енді MainActivity кодын өзгертейік:
com.example.eugene.serializeapp бумасы; android.content.Intent импорттау; android.support.v7.app.AppCompatActivity импорттау; android.os.Bundle импорттау; android.view.View импорттау; android.widget.EditText импорттау; жалпы класс MainActivity AppCompatActivity кеңейтеді ( @Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v) ( соңғы EditText nameTextd(findViewBy) .name); final EditText companyText = findViewById(R.id.company); findViewById(R.id.price); баға = Integer.parseInt(priceText.getText().toString()); .getSimpleName(), startActivity(inent) )
Енді үш бөлек деректердің орнына бір Өнім нысаны жіберіледі. Кілт негізінен сыныптың атын қайтаратын Product.class.getSimpleName() әдісінің нәтижесі болып табылады.
Және SecondActivity сыныбын өзгертіңіз:
com.example.eugene.serializeapp бумасы; android.support.v7.app.AppCompatActivity импорттау; android.os.Bundle импорттау; android.widget.TextView импорттау; жалпы класс SecondActivity AppCompatActivity кеңейтеді ( @Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); TextView textView = new TextView(бұл); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16) ); Bundle arguments = getIntent().getExtras(); " + product.getName() + "\nКомпания: " + product.getCompany() + "\nБағасы: " + String.valueOf(product.getPrice())); ) setContentView(textView); ) )
getSerializable() әдісі деректерді шығарып алу үшін пайдаланылады, себебі Өнім класы Serializable интерфейсін жүзеге асырады. Осылайша біз әртүрлі деректер топтамасының орнына бір нысанды өткізе аламыз.
Қолданба әрқашан бір экраннан тұрмайды. Мысалы, біз өте пайдалы бағдарлама жасадық және пайдаланушы оның авторы кім екенін білгісі келеді. Ол «Бағдарлама туралы» түймесін басып, жаңа экранға өтеді, онда бағдарлама нұсқасы, авторы, веб-сайт мекенжайы, автордың қанша мысықтары бар және т.б. туралы пайдалы ақпарат бар. Белсенділік экранын басқа бетке сілтемесі бар веб-бет ретінде қарастырыңыз. Файлдағы кодты қарасаңыз MainActivity.javaӨткен сабақтардан сіз біздің сыныптың екенін көресіз Негізгі әрекетүшін де қолданылады Белсенділік(немесе оның мұрагерлері) немесе, дәлірек айтқанда, одан мұрагер.
Жалпы сынып MainActivity AppCompatActivity кеңейтеді
Сіз болжағандай, біз ұқсас болуы мүмкін жаңа класс жасауымыз керек Негізгі әрекетсодан кейін түйме басқан кезде оған ауысыңыз.
Эксперимент үшін біз бағдарламаны бірінші сабақтан аламыз және эксперименттер үшін батырманы қолданамыз (немесе экранда бір түйме арқылы жаңа жоба жасаймыз). Әрі қарай, пайдалы ақпаратты көрсету үшін жаңа пішінді жасайық. Мысалы, қолданушыға мысық оңға және солға жүргенде не істейтінін көрсетейік. Келісіңіз, бұл ғаламды ашудың кілтін беретін өте маңызды ақпарат.
Студияда дайын үлгілер болса да, біз жаңа әрекетті қолмен жасаймыз. Бірақ мұнда күрделі ештеңе жоқ және жақсырақ түсіну үшін бәрін қолмен жасау пайдалы.
Жаңа XML белгілеу файлын жасайық activity_about.xmlқалтада res/макет. Қалтаны тінтуірдің оң жақ түймешігімен басыңыз макетжәне контекстік мәзірден таңдаңыз Жаңа | Орналасу ресурстық файлы. Диалогтық терезе пайда болады. Бірінші өріске файл атын енгізіңіз әрекет_туралы. Екіншісінде түбір элементін енгізу керек. Әдепкі бойынша ол сонда ConstraintLayout. Мәтінді өшіріп, енгізіңіз ScrollView. Студияға дайын опцияларды ұсыну үшін бірнеше таңбаны енгізу жеткілікті, сіз толық сөзді енгізуді күтпей-ақ Enter пернесін басуға болады:
Сіз элементті енгізетін сәйкес бос орынды аласыз TextView.
Ақпарат ресурстардан, атап айтқанда жол ресурсынан алынады мәтін туралы. Қазір ол қызыл түспен бөлектеліп, ақпараттың жоқтығын білдіреді. Басу мүмкін болды Alt+Enterжәне диалогтық терезеге мәтінді енгізіңіз. Бірақ біздің мысал үшін бұл әдіс жұмыс істемейді, өйткені біздің мәтін басқару таңбаларын қолданатын көп жолды болады. Сондықтан мұны басқаша жасайық. Файлды ашайық res/values/strings.xmlжәне келесі мәтінді қолмен енгізіңіз:
Біз ең қарапайым HTML мәтін пішімдеу тегтерін қолдандық , , . Біздің мысал үшін мысыққа және қозғалыс бағытына қатысты сөздерді қою қаріппен бөлектеу жеткілікті. Мәтінді жаңа жолға жылжыту үшін таңбаларды пайдаланыңыз \n. Жаңа экран тақырыбы үшін басқа жол ресурсын қосамыз:
Біз белгілерді анықтадық. Әрі қарай терезе үшін класс жасау керек AboutActivity.java. Мәзірден таңдаңыз Файл | Жаңа | Java класыжәне қажетті өрістерді толтырыңыз. Бастапқыда тек атын көрсету жеткілікті. Содан кейін сіз басқа салалармен айналысасыз.
Бланкты алайық.
Қазір сынып бос дерлік. Кодты қолмен қосамыз. Класс абстрактілі сыныптан мұрагер болуы керек Белсенділікнемесе оның туыстары ұнайды FragmentActivity, AppCompatActivityжәне т.б. қосайық әрекетті кеңейтеді. Әрекет сыныбында әдіс болуы керек onCreate(). Тінтуір курсорын сыныптың ішіне қойып, мәзірден таңдаңыз Код | Әдістерді қайта анықтау(Ctrl+O). Диалогтық терезеде біз қажетті классты іздейміз, сіз жылдам іздеу үшін пернетақтадағы бірінші таңбаларды тере аласыз; Құрылған әдісте әдісті шақыру керек setContentView(), ол дайындалған белгілеуді экранға жүктейді. Бізде бұл опция болады.
ru.alexanderkimov.helloworld пакеті; android.app.Activity импорттау; android.os.Bundle импорттау; /** * 12.01.2014 жылы Александр Климов жасаған. */ Public Class AboutActivity әрекетті кеңейтеді ( @Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
Енді ең маңызды бөлігі келді. Біздің міндетіміз - бірінші экрандағы түймені басқан кезде жаңа экранға өту. Сабаққа қайтайық Негізгі әрекет. Түймені басу өңдегішін жазайық:
Public void onClick(Көрініс көрінісі) ( Ниет ниеті = жаңа ниет(MainActivity.this, AboutActivity.class); startActivity(inent); )
Мұнда мен сабақта сипатталған түймені басу арқылы өңдеу әдісін қолдандым.
Жаңа экранды іске қосу үшін сыныптың данасын жасау керек Ниетжәне бірінші параметрде ағымдағы сыныпты, ал екіншісінде баратын сыныпты көрсетіңіз, бізде бұл бар Әрекет туралы. Осыдан кейін әдіс шақырылады startActivity(), ол жаңа экранды іске қосады.
Енді қолданбаны эмуляторда сынап көрсеңіз, қате туралы хабар аласыз. Біз не істедік? Біз бір маңызды қадамды жіберіп алдық. Сізге жаңасын тіркеу керек Белсенділікманифестінде AndroidManifest.xml. Бұл файлды жобаңыздан тауып, оны екі рет басыңыз. Файлды өңдеу терезесі ашылады. Жаңа тег қосыңыз
Бұл жерде жол ресурсы пайдалы болады туралы_атауы. Біз қолданбаны іске қосамыз, түймені басып, терезені аламыз бағдарлама туралы. Осылайша, біз жаңа терезе құруды және түймені басу арқылы шақыруды үйрендік. Біздің қолымызда мега-ыңғайлы бағдарлама бар - енді мысық сол жаққа кеткенде не істейтіні туралы анықтама әрқашан қолымызда болады.
Жасалған әрекеттің екінші сыныбы сыныптан мұрагер болуы керек екенін тағы бір рет ескеріңіз Белсенділікнемесе ұқсас ( ListActivityт.б.), XML белгілеу файлы (қажет болса) және манифестте көрсетілуі керек.
Әдісті шақырғаннан кейін startActivity()жаңа әрекет іске қосылады (бұл жағдайда Әрекет туралы), ол көрінетін болады және іске қосылған құрамдастарды қамтитын стектің жоғарғы жағына жылжиды. Әдісті шақырғанда аяқтау()жаңа әрекеттен (немесе аппараттық құралды қайтару пернесі басылғанда) ол жабылады және стектен жойылады. Әзірлеуші де сол әдісті пайдаланып алдыңғы (немесе кез келген басқа) әрекетке шарлай алады startActivity().
Үшінші экран жасау – жалқауларға арналған әдіс
Бағдарламашылар, мысықтар сияқты, жалқау тіршілік иелері. Әрекет үшін белгі мен мұрагер класс жасау керек екенін әрқашан есте сақтаңыз Белсенділік, содан кейін манифестте сыныпты тіркеуді ұмытпаңыз - жақсы.
Бұл жағдайда мәзірден таңдаңыз Файл | Жаңа | Әрекет | Негізгі әрекет(немесе басқа үлгі). Әрі қарай, жаңа әрекетті жасау үшін таныс терезе пайда болады. Қажетті өрістерді толтырыңыз.
Түймені басыңыз Аяқтаужәне әрекет дайын болады. Мұны тексеру үшін манифест файлын ашып, жаңа жазбаны тексеріңіз. Мен тіпті сынып және белгілеу файлдары туралы айтпаймын, олар сіздің алдыңызда өздігінен пайда болады.
Негізгі әрекет экранына өзіңіз жаңа түймені қосыңыз және жасалған әрекетке ауысу үшін код жазыңыз.
Алдымен сынып, белгілеу және манифест арасындағы байланысты түсіну үшін жаңа әрекетке барлық қажетті құрамдастарды қолмен жасауға кеңес берер едім. Ал оны меңгерген кезде, жұмысыңызды жылдамдату үшін Әрекет жасау шеберін пайдалануға болады.
Әрекеттер арасында деректерді беру
Басқа әрекет экранын шақыру үшін қарапайым мысалды қолдандық. Кейде сіз жаңа экранға қоңырау шалып қана қоймай, оған деректерді тасымалдауыңыз керек. Мысалы, пайдаланушы аты. Бұл жағдайда арнайы аймақты пайдалану керек қосымша деректер, бұл сыныпта бар Ниет.
Аймақ қосымша деректержұптардың тізімі болып табылады кілт/мән, ол ниетпен бірге беріледі. Жолдар кілттер ретінде пайдаланылады және мәндер үшін кез келген қарабайыр деректер түрлері, примитивтердің массивтері, сынып нысандары пайдаланылуы мүмкін Бумажәне т.б.
Деректерді басқа әрекетке тасымалдау үшін әдісті пайдаланыңыз putExtra():
Intent.putExtra("Кілт", "Мән");
Қабылдау әрекеті кейбір сәйкес әдісті шақыруы керек: getIntExtra(), getStringExtra()және т.б.:
Int count = getIntent().getIntExtra("аты", 0);
Алдыңғы мысалды қайталайық. Бізде қазірдің өзінде үш іс-шара бар. Бірінші әрекетте екі мәтіндік өріс және түйме болады. Сыртқы түрі келесідей болуы мүмкін:
Екінші әрекетте Екінші әрекетэлементті орнатыңыз TextView, онда біз бірінші әрекеттен алынған мәтінді көрсетеміз. Әдіс үшін келесі кодты жазайық onCreate()екінші әрекетте.
@Override қорғалған void onCreate(Bundle savedInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); Жол пайдаланушы = "Жануар"; Жол сыйлығы = "пончик тесігі"; TextView infoTextView = (TextView)findViewByI .id.textViewInfo); infoTextView.setText(пайдаланушы + ", сізге " + сыйлық берілді);
Егер біз қазір бағдарламаны іске қосып, мақаланың бірінші бөлігінде сипатталғандай екінші терезені шақыратын болсақ, онда біз әдепкі жазуды көреміз. Жануар, олар саған пончикті берді. Келісемін, мұндай хабарламаларды алу өте тітіркендіргіш.
Жағдайды түзетейік. Бірінші әрекетке кодты қосыңыз:
Қоғамдық жарамсыз onClick(Көрініс көрінісі) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText giftEditText = (EditText) findViewById(R.id.editTextGift); Мақсат мақсаты = жаңа ниет(MainActivity.this, Second-Activity.this) class); // мәтінді бірінші мәтін өрісінен пайдаланушы аты кілтіне итеріңіз intent.putExtra("username", userEditText.getText().toString()) // екінші мәтін өрісіндегі мәтінді сыйлық кілтіне басыңыз intent.putExtra("сыйлық" ", giftEditText.getText().toString()); startActivity(ниет); )
Біз нысанды арнайы контейнерге орналастырдық Ниетмәтіндік өрістерден алынған мәндері бар екі кілт. Пайдаланушы деректерді мәтіндік өрістерге енгізген кезде, ол осы контейнерге кіреді және екінші әрекетке өтеді.
Екінші әрекет келесідей (қалың шрифтпен) хабарламаларды жылы қабылдауға дайын болуы керек.
// Әдепкі мәндер Жол пайдаланушы = «Жануар»; Жіпті сыйлық = «пончик тесігі»; user = getIntent().getExtras().getString("пайдаланушы аты"); сыйлық = getIntent().getExtras().getString("сыйлық"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(пайдаланушы + " , сізге " + сыйлық берілді);
Енді бұл хабар кейбіреулер үшін аз қорлайтын, тіпті жағымды болып көрінеді. Күрделі мысалдарда деректерді өңдеу кезінде чекті қосқан жөн. Бос деректер түрі бар екінші әрекетті іске қосатын жағдайлар болуы мүмкін null, бұл қолданбаның бұзылуына әкелуі мүмкін.
Біздің жағдайда біз жол мәнін күтетінімізді білеміз, сондықтан кодты келесідей қайта жазуға болады:
Мақсат ниет = getIntent(); user = intent.getStringExtra("пайдаланушы аты");
Пайдаланушы = getIntent().getStringExtra("пайдаланушы аты");
Бағдарламаның кемшілігі бар – сәлемдемені кімнен алатынымыз белгісіз. Кез келген жақсы өсірілген маймыл анонимді көзден сыйлықты қабылдамайды. Сонымен, үй тапсырмасы ретінде хабарды жіберетін пайдаланушының атын енгізу үшін басқа мәтін өрісін қосыңыз.
Google кілттер үшін келесі пішімді пайдалануды ұсынады: префикс ретінде пакет атауы, содан кейін кілттің өзі. Бұл жағдайда басқа қолданбалармен әрекеттесу кезінде кілттің бірегейлігіне сенімді бола аласыз. Сол сияқты бірнәрсе:
Жалпыға ортақ соңғы статикалық жол USER = "ru.alexanderkimov.myapp.USER";
Васка мысықты кім жақтады - біз нәтижені қайтарамыз
Деректерді басқа әрекетке жай ғана беру әрқашан жеткіліксіз. Кейде ол жабылған кезде басқа әрекеттен ақпаратты қайтару қажет. Бұрын біз әдісті қолданатын болсақ startActivity(ниет ниеті), онда байланысты әдіс бар startActivityForResult(Intent intent, int RequestCode). Әдістердің айырмашылығы қосымша параметр болып табылады Сұрау коды. Бұл негізінен өзіңіз ойлап таба алатын бүтін сан. Нәтиже кімнен шыққанын ажырату үшін қажет. Сізде бес қосымша экран бар делік және сіз оларға 1-ден 5-ке дейінгі мәндерді тағайындайсыз және осы кодты пайдалана отырып, сіз кімнің нәтижесін өңдеу керектігін анықтай аласыз. Сіз -1 мәнін пайдалана аласыз, содан кейін ол әдісті шақырумен бірдей болады startActivity(), яғни. біз ешқандай нәтиже бермейміз.
Егер сіз әдісті қолдансаңыз startActivityForResult(), содан кейін нәтиже алу үшін кодыңыздағы әдісті қайта анықтауыңыз керек onActivityResult()және нәтижені өңдеңіз. Шатасып кеттіңіз бе? Мысал қарастырайық.
Сіз детективсіз делік. Ресторандағы беделді адамның үстелінен екі дана шұжық пен басқа да өнімдер ұрланғаны туралы ақпарат түскен. Күдік үш күдіктіге түсті - қарға, ит пен мысық Васка.
Келушілердің бірі өзінің iPhone-дан бірнеше фотосуреттерін ұсынды:
Тағы бір куәгердің айғағы бар: Ал Васка тыңдап тамақ ішеді.
Жаңа жоба жасаңыз Шерлокекі әрекетпен. Бірінші экранда екінші экранға ауысу түймесі және ұрының аты көрсетілетін мәтіндік белгі болады.
Екінші экранда қосқыштар тобы болады:
Екінші экраннан жауап күтетіндіктен, әдісті қолдануымыз керек startActivityForResult()айнымалыны өткізетін бірінші экранда CHOOSE_THIEFпараметр ретінде Сұрау коды.
Статикалық соңғы жеке int CHOOSE_THIEF = 0; public void onClick(View v) (Intent questionIntent = жаңа Мақсат(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
Кодты қараңыз. Түймені басқан кезде біз екінші экранмен жұмыс істейміз Белсенділікті таңдаңызжәне нәтижені күтіп тұрған екінші экранды іске қосыңыз.
Екінші экранға өтіп, екінші әрекеттің кодын жазайық.
Қоғамдық қорытынды статикалық жол THIEF = "ru.alexanderkimov.sherlock.THIEF"; public void onRadioClick(View v) (Intent answerIntent = new Intent(); ауысу (v.getId()) (R.id.radioDog жағдайы: answerIntent.putExtra(ҰРЫ, "Бұған ит"); үзіліс; R.id оқиғасы .radioCrow: answerIntent.putExtra(THIEF, "Crow": answerIntent.putExtra(THIEF, "Przewalski's Horse" үзіліс: setResult (); ;
Мұнда бәрі қарапайым, детектив қылмыскердің атын таңдағанда, содан кейін әдіс арқылы putExtra()кілттің атын және оның мәнін береміз.
Ыңғайлы болу үшін таңдағаннан кейін біз екінші терезені дереу жабамыз және жабу алдында мәнді өткіземіз RESULT_OK, сондықтан таңдау жасалғаны анық. Егер пайдаланушы «Артқа» түймесі арқылы экранды жапса, мән беріледі RESULT_CANCELED.
Әдіс setResult()екі параметрді қабылдайды: нәтижелі код және мақсат ретінде ұсынылған нәтиженің өзі. Алынған код әрекеттің нәтижесі қандай болғанын айтады, әдетте, ол да Әрекет.RESULT_OK, немесе Әрекет.RESULT_CANCELED. Кейбір жағдайларда қолданбаға тән нұсқаларды өңдеу үшін өзіңіздің қайтару кодыңызды пайдалануыңыз қажет. Әдіс setResult()кез келген бүтін мәнді қолдайды.
Егер сіз түйме арқылы деректерді нақты жіберетін болсаңыз, әдісті қосу жақсы идея болар еді аяқтау()екінші әрекетті қажетсіз деп жабу. Егер ауысу «Артқа» түймесі арқылы жүзеге асса, бұл қажет емес.
Әрекетті пайдаланушы жабдықты қайтару түймесін басу арқылы жапса немесе әдіс болса аяқтау()әдістен бұрын шақырылған setResult(), нәтижесінде код орнатылады RESULT_CANCELED, және қайтарылған ниет мәнді көрсетеді null.
Біз бірінші экранға ораламыз. Бірінші экран екінші экраннан жауапты күтуде, сондықтан кодқа әдіс қосу керек onActivityResult().
@Override қорғалған void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, деректер); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == IEFOOSE) if (resultCode == RESULT_OK) ( Жол ұры аты = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // мәтінді өшіру ) ) )
Әдіс кодпен кіріс деректерді күтеді CHOOSE_THIEF, және мұндай деректер келсе, ол мәнді кілттен алады ChooseActivity.THIEFәдісін қолдану getStringExtra. Нәтижедегі мәнді көрсетеміз TextView(айнымалы infoTextView). Егер біз «Артқа» түймесі арқылы экранға оралсақ, онда біз жай ғана мәтінді өшіреміз.
Негізгі құрамдас ішінде еншілес әрекет жабылған кезде өңдеуші жұмыстан босатылады onActivityResult(). Өңдеуші onActivityResult()бірнеше параметрлерді қабылдайды.
- Кодты сұрау. Нәтижені қайтаратын әрекетті бастау үшін пайдаланылатын код
- Нәтиже коды. Жұмыстың қалай аяқталғанын көрсететін бала әрекеті арқылы орнатылған нәтиже коды. Бұл кез келген бүтін мән болуы мүмкін, бірақ әдетте екеуі де Әрекет.RESULT_OK, немесе Әрекет.RESULT_CANCELED
- Деректер. Қайтарылған деректерді бумалау үшін пайдаланылатын мақсат. Бала әрекетінің мақсатына байланысты ол мазмұнның таңдалған бөлігін көрсететін URI жолын қамтуы мүмкін. Баламалы (немесе қосымша) бала әрекеті ақпаратты ниет параметріне оралған қарапайым мәндер ретінде қайтара алады. қосымшалар
Егер бала әрекеті күтпеген жерден тоқтатылса немесе оны жабу алдында нәтиже коды көрсетілмесе, бұл параметр келесідей болады Әрекет.RESULT_CANCELED.
Біз жобаны іске қосамыз, түймені басып, екінші экранға өтеміз. Онда біз опциялардың бірін таңдаймыз. Қарғаны таңдасаңыз, экран жабылып, бірінші экранда қылмыскердің аты шығады. Егер сіз ит таңдасаңыз, оның аты көрсетіледі.
Айтпақшы, егер сіз мысық таңдасаңыз, оның аты көрсетілмейді! Оны тексеріп, өзіңіз көріңіз. Сіз неге сұрайсыз? Бастауыш сынып Уотсон! Қылмыскер бір маңызды бөлшекті ескермеген. Мейрамхана бейнекамералардың бақылауында болды, жазбада шын мәнінде шұжықты кім ұрлап, мысықты жақтағанын көрсетті. Васка, күте тұрыңыз!
P.S. Басында бірдеңе түсініксіз болып көрінсе, тәжірибе арқылы көп нәрсе анық болады. Экрандар арасында деректерді тасымалдау қолданбаларда жиі кездеседі және сіз мысалды бірнеше рет зерттейсіз.
P.P.S. Ең жақсы балық - шұжық. Бұл әлсіздікті біле отырып, мысықты жақтау қиын болмады.
Сүзгілерді пайдалану
Мақалада мен әдіс кезінде басқа әрекетке ауысудың жалпы әдісін көрсеттім startActivity()Ағымдағы сынып және тасымалданатын сынып көрсетіледі. Айтпақшы, белсенділік сыныбы қолданбаңыздың бөлігі болуы міндетті емес. Басқа қолданбадан сынып атауын білсеңіз, оған ауыса аласыз. Бірақ сіз басқа әрекетке басқа жолмен ауыса аласыз.
Іс жүзінде бұл сирек кездеседі, бірақ пайдалы болуы мүмкін. Сізде екінші әрекет бар делік. Манифестте біз оған арнайы сүзгіні қосамыз:
Ал біз осы жолмен түймені басу арқылы екінші әрекетті іске қосамыз.
Public void onClick(Көру көрінісі) ( startActivity(new Intent("ru.alexanderkimov.testapplication.SecondActivity")); )
Ұзын жолды тұрақтымен ауыстырайық.
Жалпыға ортақ статикалық соңғы жол ACTION_SECOND_ACTIVITY = "ru.alexanderkimov.testapplication.SecondActivity"; public void onClick(Көру көрінісі) ( startActivity(жаңа ниет(ACTION_SECOND_ACTIVITY)); )
Сонымен біз не істедік. Екінші әрекет үшін сүзгіні тіркедік және атын көрсеттік әрекетатрибутта Android: аты. Ыңғайлы болу үшін мен пакеттің атымен бірге әрекеттің толық атауын қойдым. Класс конструкторы Ниетбірнеше шамадан тыс жүктелген нұсқалары бар. Бір нұсқада әрекет үшін жолды көрсетуге болады. Біз екінші әрекетте тіркелген әрекетімізді көрсеттік. Жұмыс кезінде жүйе барлық орнатылған қолданбалардың манифесттерін қарайды. Сәйкестікті іздеу кезінде жүйе біздің сүзгіні тауып, қажетті әрекетті іске қосады.
Сол принципті пайдаланып басқа әрекеттерді бастауға болады. Мысалға қараңыз. Егер сіз мысалды өзіңізге көшіріп, құжаттаманы қарасаңыз 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.alexanderkimov.testapplication.SecondActivity"; // Класс нысанын алыңыз>myClass = Class.forName(activityName); Мақсат ниет = жаңа ниет (бұл, менің классым); startActivity(ниет); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
Қандай да бір түрде менде деректерді қызметтен әрекетке тасымалдау тапсырмасы болды. Стандартты SDK-де шешімді іздеу басталды, бірақ уақыт болмағандықтан, мен дерекқорды пайдалану түрінде нашар шешім жасадым. Бірақ сұрақ ашық болды және біраз уақыттан кейін мен SDK-де бар дұрысырақ әдісті таптым - Message, Handler, Messenger сыныптарын пайдалану.
Идея
Деректерді әрекеттен қызметке және кері тасымалдауымыз керек. Мұны қалай істейміз? Бізде проблеманы шешу үшін қажет нәрсенің бәрі бар. Сізге тек bindService көмегімен қызметті әрекетке байланыстыру, қажетті параметрлерді беру және Хабарлама сыныптарын пайдалану түрінде кішкене сиқыр қажет. Ал сиқыр - Message данасы айнымалы мәндерін және, атап айтқанда, replyTo пайдалану. Әрекеттен Messanger қызметінің данасына және қызметтегі әрекеттің Messanger данасына қол жеткізу үшін бізге бұл айнымалы қажет. Шын мәнінде, бұл қарапайым емес. Кем дегенде, менің дарынды емес ақыл-ойыма. Ішінара мен бұрыннан бар құжаттаманы жақсартып жатырмын - Қызметтер Сондай-ақ, StackOverflow-та жақсы мысал бар. Қалай болғанда да, мақала кем дегенде біреуге пайдалы болады деп үміттенемін және менің еңбегім бекер болған жоқ.
Мысал
Мысал ретінде біз санауыш мәнін арттыратын және азайтатын және әрекеттегі нәтижені TextView ішінде қайтаратын қызметті жүзеге асырамыз. Мен орналасу кодын өткізбеймін, өйткені екі түйме және мәтіндік өріс бар - бәрі қарапайым.
Іске асыру
Міне, толық белсендіру коды:
Жалпы сынып MainActivity әрекетті кеңейтеді (жалпыға ортақ статикалық соңғы жол TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; соңғы Messenger хабаршысы = жаңа Messenger(жаңа IncomingHandler()); Messenger toServiceMessenger; onCoverridestance public (@Overridestance public v.B.) сақталған. onCreate(savedInstanceState) setContentView(R.layout.activity_main)findViewById(R.id.test_txt), (testServConn = new TestServiceConnection); .BIND_AUTO_CREATE ) @Override public void onDestroy())( super.onDestroy(); unbindService(testServConn); ) public void countIncrClick(Көру түймесі)( Message msg = Message.obtain(null, TestService.COUNT_PL.); replyTo = messenger; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(Көру түймесі)( Message msg = Message.obtain(null, TestService.COUNT_US); msg .replyTo = хабаршы; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) жеке класс IncomingHandler өңдеуші кеңейтеді ( @Override public void handleMessage(Message msg)( switch (msg.what)) ( case TestService. GET_COUNT: Log.d(TAG, "(activity)...get count"); атауы, IBinder қызметі) ( toServiceMessenger = жаңа Messenger(қызмет); //есептегіштің бастапқы мәнін жіберу Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = messenger; msg.arg1 = 0; / /біздің есептегіш әрекетіміз ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName атауы) ( ) ) )
Түсіндірейін. Әрекетті құру кезінде біз ServiceConnection интерфейсін іске асыра отырып, қызметке бірден қосыламыз және онда біз қызметке «есептегіш мәнді орнату» хабарламасын жібереміз, нөлден өтіп, toServiceMessanger жасаймыз, IBinder интерфейсін конструкторға береміз. Айтпақшы, бұл көшірме қызметке қайтарылуы керек, әйтпесе NPE болады. Осы сыныпты пайдалана отырып, біз қызметке хабарлама жібереміз. Міне, сиқырлы - жауап беру айнымалысында біз басқа Messenger данасын сақтаймыз - серверден жауап алатын және сол арқылы әрекетпен байланыс жүзеге асырылады.
Қызметтен хабарлама алу үшін біз өңдеушімізді қолданамыз және жай ғана қажетті айнымалы мәндерді іздеп, олар бойынша әрекет жасаймыз. Түймелерді басу арқылы (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 саны = 0; IncomingHandler inHandler; Messenger; Messenger toActivityMessenger; @Override public void onCreate())( super.onCreate(); HandlerThread ағыны = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandre(thread.Lo); messenger = new Messenger(inHandler ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Intent intent, int flags, int startId) (қайтару START_STICKY; өңдеуші әрекеті жеке сынып IncomingHandler кеңейтеді Handler ( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handleMessage(Хабарлама хабар)( //super.handleMessage(msg); toActivityMessenger = msg.replyTo; ауыстырып-қосқыш (msg.what) (SET_COUNT жағдай: санау = msg.arg1; Log.d(MainActivity.TAG, "(қызмет)...сананы орнату"); үзіліс; COUNT_PLUS жағдай: count++; Log.d(MainActivity.TAG) , "(қызмет)... санау плюс" үзіліс COUNT_MINUS: Log.d(MainActivity.TAG, "(қызмет)...санау". Message outMsg = Message.obtain(inHandler, GET_COUNT). ); outMsg.arg1 = санау; outMsg.replyTo = хабаршы; ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) ұстап көріңіз (RemoteException e) ( e.printStackTrace(); ) ) ) )
Барлығы Activiti-дегі логикаға ұқсас. Мен бірдеңені түсіндіруім керек пе, білмеймін. Жалғыз мәселе, мен сиқырлы replyTo айнымалысын пайдаланып және жоғарыдағы қажетті Messenger-ді шығарып алып, сұрауды handleMessage ішіндегі әрекетке дереу жіберемін. Ал мен айтқан екінші мәселе:
@Override public IBinder onBind(Intent arg0) ( messanger.getBinder(); қайтару)
онсыз бәрі құлайды. Дәл осы интерфейс данасы ServiceConnection қызметіне жіберіледі
Қорытынды
Жалпы алғанда. Бұл әрекет пен қызмет арасындағы өзара әрекеттестіктің шамадан тыс мысалы. Менің ойымша, бұл өте маңызды емес өзара әрекеттесу, басқалар басқаша ойлауы мүмкін.
ПМ-де сұрақтар, түсініктемелер және т.б. Кейбір аспектілерге қатысты дәлсіздіктер болуы мүмкін, сондықтан жазыңыз және түзетіңіз.
Пост оқырмандар үшін пайдалы болды деп үміттенемін.