안녕하세요.
UART를 통해 수신된 데이터를 Activity로 전송해야 합니다. 이는 활동에서 while 루프(!isInterrupted())를 구성하고 UART 버퍼에서 데이터를 읽는 스레드를 생성하여 수행할 수 있습니다. 그런 다음 UI 스레드 Activity - MainActivity.this.runOnUiThread(new Runnable() )를 호출하여 이 Activity로 필요한 작업을 수행합니다. 그러나 기본 Activity에서 다른 Activity를 호출하면 구성된 스레드는 데이터 전달을 허용하지 않습니다. 내가 올바르게 이해한 경우 스트림의 데이터를 활동으로 전송하려면 스트림이 활동이 아닌 서비스에서 생성되어야 합니다.
질문: 데이터가 UART를 통해 도착했습니다. 스트림(Servce에서 생성됨)에서 현재 활성화된 활동으로 데이터를 전송해야 합니다. 이 작업을 어떻게 수행할 수 있으며 실제로 수행됩니까?
답변 1개
각 활동에서 핸들러를 생성합니다. 이 Activity의 onResume() 메서드에서 BindService()가 수행됩니다. 매개변수 중 하나는 ServiceConnection 인터페이스입니다. 최소한 동일한 활동으로 구현하십시오. onServiceConnected() 메소드를 구현하십시오. 이 콜백에서 매개변수 중 하나는 서비스 자체입니다. 따라서 이 서비스의 자체 setHandler() 메서드를 호출하세요. 현재 활동에 있는 핸들러를 전달합니다. 하지만 UART를 통해 들어오는 데이터를 이 핸들러의 서비스로 보냅니다. 그런데 Handler는 전통적으로 메인 스레드에서 실행되므로 OnUiThread를 실행할 필요가 없습니다.
마지막 업데이트: 2018년 4월 3일
Intent 객체는 두 활동 간에 데이터를 전송하는 데 사용됩니다. putExtra() 메소드를 통해 키와 관련 값을 추가할 수 있습니다.
예를 들어 현재 활동에서 "hello" 키를 사용하여 "Hello World" 문자열을 SecondActivity에 전달합니다.
// SecondActivity를 실행하기 위한 Intent 객체 생성 Intentint = new Intent(this, SecondActivity.class); // 키가 "hello"이고 값이 "Hello World"인 객체 전달 의도.putExtra("hello", "Hello World"); // SecondActivity 시작 startActivity(의도);
데이터를 전송하기 위해 가장 간단한 유형의 데이터를 값(String, int, float, double, long, short, byte, char, 이러한 유형의 배열 또는 직렬화 가능)으로 전송할 수 있는 putExtra() 메소드가 사용됩니다. 인터페이스 객체.
SecondActivity를 로드할 때 전송된 데이터를 얻으려면 객체 키가 전달되는 get() 메서드를 사용할 수 있습니다.
번들 인수 = getIntent().getExtras(); 문자열 이름 = 인수.get("hello").toString(); // 안녕하세요 세계
보내는 데이터의 유형에 따라, 이를 수신할 때 Bundle 객체에 대해 여러 가지 메서드를 사용할 수 있습니다. 이들 모두는 객체 키를 매개변수로 사용합니다. 주요 내용:
get() : Object 유형의 값을 반환하는 일반 메서드입니다. 따라서 이 값의 수신 필드를 원하는 유형으로 변환해야 합니다.
getString() : String 객체를 반환합니다.
getInt() : int 값을 반환합니다.
getByte() : 바이트 값을 반환합니다.
getChar() : char 값을 반환합니다.
getShort() : short 유형의 값을 반환합니다.
getLong() : 긴 값을 반환합니다.
getFloat() : 부동 소수점 값을 반환합니다.
getDouble() : double을 반환합니다.
getBoolean() : 부울 값을 반환합니다.
getCharArray() : char 객체의 배열을 반환합니다.
getIntArray() : int 객체의 배열을 반환합니다.
getFloatArray() : float 객체의 배열을 반환합니다.
getSerialized() : 직렬화 가능 인터페이스 객체를 반환합니다.
프로젝트에 MainActivity와 SecondActivity라는 두 가지 활동이 정의되어 있습니다.
SecondActivity 코드에서는 수신 데이터를 정의합니다.
패키지 com.example.eugene.serializeapp; android.support.v7.app.AppCompatActivity 가져오기; import android.os.Bundle; import android.widget.TextView; 공개 클래스 SecondActivity는 AppCompatActivity를 확장합니다( @Override protected void onCreate(Bundle saveInstanceState)( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16) ); 번들 인수 = getIntent().getExtras(); if(arguments!=null)( 문자열 이름 = 인수.get("name").toString(); 문자열 회사 = 인수.getString("회사"); int 가격 = 인수.getInt("가격"); textView.setText("이름: " + 이름 + "\n회사: " + 회사 + "\n가격: " + 가격 ) setContentView(textView) )
이 경우 SecondActivity에서는 Bundle 개체에서 모든 데이터를 가져와 TextView 텍스트 필드에 표시합니다. 이 활동에는 세 가지 요소, 즉 키 이름과 회사가 포함된 두 개의 문자열과 키 가격이 포함된 숫자가 전달된다고 가정합니다.
이제 SecondActivity로의 데이터 전송을 정의해 보겠습니다. 예를 들어, Activity_main.xml 파일에서 MainActivity에 대해 다음 인터페이스를 정의해 보겠습니다.
여기에는 데이터 입력을 위한 세 개의 텍스트 필드와 버튼이 정의되어 있습니다.
MainActivity 클래스에서는 다음 콘텐츠를 정의합니다.
패키지 com.example.eugene.serializeapp; import android.content.Intent; android.support.v7.app.AppCompatActivity 가져오기; import android.os.Bundle; import android.view.View; android.widget.EditText 가져오기; 공용 클래스 MainActivity는 AppCompatActivity를 확장합니다( @Override protected void onCreate(Bundle saveInstanceState)( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v)( final EditText nameText = findViewById(R.id) .name); final EditText companyText = findViewById(R.id.company); final EditText PriceText = findViewById(R.id.price); String name = nameText.getText().toString(); 가격 = Integer.parseInt(priceText.getText().toString()); 의도 의도 = new Intent(this, SecondActivity.class);intent.putExtra("name", name); intent.putExtra("price", 가격) startActivity(intent) )
버튼 클릭 핸들러에서 EditText 텍스트 필드에 입력된 데이터를 수신하고 putExtra() 메소드를 사용하여 Intent 객체에 전달합니다. 그런 다음 SecondActivity를 시작합니다.
결과적으로 버튼을 클릭하면 SecondActivity가 실행되고 텍스트 필드에 입력된 일부 데이터가 수신됩니다.
복잡한 객체 전송
위의 예에서는 숫자, 문자열 등 간단한 데이터가 전송되었습니다. 하지만 더 복잡한 데이터를 전송할 수도 있습니다. 이 경우 직렬화 메커니즘이 사용됩니다.
예를 들어 프로젝트에 Product 클래스가 정의되어 있다고 가정해 보겠습니다.
패키지 com.example.eugene.serializeapp; import java.io.Serialized; 공개 클래스 제품은 직렬화 가능을 구현합니다( 비공개 문자열 이름; 비공개 문자열 회사; 비공개 int 가격; 공개 제품(문자열 이름, 문자열 회사, int 가격)( this.name = 이름; this.company = 회사; this.price = 가격; ) public String getName() (반환 이름; ) public void setName(String name) ( this.name = name; ) public String getCompany() (반환 회사; ) public void setCompany(String 회사) ( this.company = 회사; ) public int getPrice() (반환 가격; ) public void setPrice(int 가격) ( this.price = 가격; ) )
이 클래스가 직렬화 가능 인터페이스를 구현한다는 점은 주목할 가치가 있습니다. 이제 MainActivity 코드를 변경해 보겠습니다.
패키지 com.example.eugene.serializeapp; import android.content.Intent; android.support.v7.app.AppCompatActivity 가져오기; import android.os.Bundle; import android.view.View; android.widget.EditText 가져오기; 공용 클래스 MainActivity는 AppCompatActivity를 확장합니다( @Override protected void onCreate(Bundle saveInstanceState)( super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ) public void onClick(View v)( final EditText nameText = findViewById(R.id) .name); final EditText companyText = findViewById(R.id.company); final EditText PriceText = findViewById(R.id.price); String name = nameText.getText().toString(); 가격 = Integer.parseInt(priceText.getText().toString()); 제품 product = new Product(이름, 회사, 가격); Intentintent(this, SecondActivity.class); .getSimpleName(), 제품); startActivity(의도) )
이제 세 개의 개별 데이터 대신 하나의 Product 객체가 전송됩니다. 키는 기본적으로 클래스 이름을 반환하는 Product.class.getSimpleName() 메서드의 결과입니다.
그리고 SecondActivity 클래스를 변경합니다.
패키지 com.example.eugene.serializeapp; android.support.v7.app.AppCompatActivity 가져오기; import android.os.Bundle; import android.widget.TextView; 공개 클래스 SecondActivity는 AppCompatActivity를 확장합니다( @Override protected void onCreate(Bundle saveInstanceState)( super.onCreate(savedInstanceState); TextView textView = new TextView(this); textView.setTextSize(20); textView.setPadding(16, 16, 16, 16) ); 번들 인수 = getIntent().getExtras(); 최종 제품 제품; if(arguments!=null)( product = (제품) 인수.getSerialized(Product.class.getSimpleName()); textView.setText("이름: " + product.getName() + "\n회사: " + product.getCompany() + "\n가격: " + String.valueOf(product.getPrice())); ) setContentView(textView); ) )
Product 클래스가 직렬화 가능 인터페이스를 구현하기 때문에 getSerialized() 메소드는 데이터를 검색하는 데 사용됩니다. 이렇게 하면 여러 개의 서로 다른 데이터 대신 하나의 단일 개체를 전달할 수 있습니다.
애플리케이션이 항상 하나의 화면으로 구성되는 것은 아닙니다. 예를 들어, 우리는 매우 유용한 프로그램을 만들었고 사용자는 그 프로그램의 작성자가 누구인지 알고 싶어합니다. 그는 "프로그램 정보" 버튼을 클릭하고 프로그램 버전, 작성자, 웹사이트 주소, 작성자의 고양이 수 등에 대한 유용한 정보가 있는 새 화면으로 이동합니다. 활동 화면을 다른 페이지에 대한 링크가 있는 웹 페이지로 생각하십시오. 파일의 코드를 보면 MainActivity.java이전 수업에서 우리 수업이 주요 활동에도 적용됩니다 활동(또는 그의 상속인) 또는 더 정확하게는 그로부터 물려 받았습니다.
공용 클래스 MainActivity는 AppCompatActivity를 확장합니다.
짐작할 수 있듯이 다음과 유사한 새 클래스를 만들어야 합니다. 주요 활동그런 다음 버튼을 누르면 어떻게든 전환됩니다.
실험을 위해 첫 번째 강의의 프로그램을 가져와 실험용 버튼을 사용합니다(또는 화면에 버튼 하나로 새 프로젝트를 생성합니다). 다음으로 유용한 정보를 표시하는 새 양식을 만들어 보겠습니다. 예를 들어, 고양이가 좌우로 움직일 때 무엇을 하는지 사용자에게 보여드리겠습니다. 동의하세요. 이것은 우주를 푸는 열쇠를 제공하는 매우 중요한 정보입니다.
스튜디오에 미리 만들어진 템플릿이 있지만 수동으로 새 활동을 만듭니다. 그러나 거기에는 복잡한 것이 없으며 더 나은 이해를 위해서는 모든 것을 손으로 수행하는 것이 유용합니다.
새로운 XML 마크업 파일을 만들어 보겠습니다. 활동_about.xml폴더에 해상도/레이아웃. 폴더를 마우스 오른쪽 버튼으로 클릭하세요. 공들여 나열한 것상황에 맞는 메뉴에서 선택하세요. 신규 | 레이아웃 리소스 파일. 대화 상자가 나타납니다. 첫 번째 필드에 파일 이름을 입력하십시오. 활동_정보. 두 번째에서는 루트 요소를 입력해야 합니다. 기본적으로 거기에 있습니다 제약 레이아웃. 텍스트를 지우고 입력하세요. 스크롤뷰. 몇 글자만 입력하면 스튜디오에서 미리 만들어진 옵션을 제안할 수 있습니다. 전체 단어가 입력될 때까지 기다리지 않고 즉시 Enter 키를 누를 수 있습니다.
요소를 삽입할 해당 공백이 표시됩니다. 텍스트뷰.
정보는 리소스, 즉 문자열 리소스에서 검색됩니다. about_text. 이제 빨간색으로 강조 표시되어 정보가 없음을 나타냅니다. 누르면 가능했는데 Alt+Enter대화 상자에 텍스트를 입력합니다. 그러나 이 예에서는 텍스트가 제어 문자를 사용하여 여러 줄로 구성되므로 이 방법은 작동하지 않습니다. 그럼 다르게 해봅시다. 파일을 열어보자 입술/값/strings.xml다음 텍스트를 수동으로 입력하세요.
우리는 다음과 같은 가장 간단한 HTML 텍스트 형식 태그를 사용했습니다. , , . 우리의 예에서는 고양이와 관련된 단어와 이동 방향을 굵게 강조하는 것으로 충분합니다. 텍스트를 새 줄로 이동하려면 기호를 사용하세요. \N. 새 화면의 제목에 대한 또 다른 문자열 리소스를 추가해 보겠습니다.
우리는 표시를 알아 냈습니다. 다음으로 창에 대한 클래스를 만들어야 합니다. AboutActivity.java. 메뉴에서 선택하세요 파일 | 신규 | 자바 클래스필수 항목을 입력하세요. 처음에는 이름만 표시하는 것으로 충분합니다. 그런 다음 다른 분야를 다루게 됩니다.
공백을 얻자.
이제 수업은 거의 비어 있습니다. 코드를 수동으로 추가해 보겠습니다. 클래스는 추상 클래스에서 상속되어야 합니다. 활동아니면 그의 친척이 좋아 조각 활동, AppCompatActivity등. 추가하자 활동 확장. 활동 클래스에는 메소드가 있어야 합니다. onCreate(). 클래스 내부에 마우스 커서를 놓고 메뉴에서 선택하세요. 코드 | 재정의 방법(Ctrl+O). 대화 상자에서 필요한 클래스를 찾습니다. 빠른 검색을 위해 키보드의 첫 번째 문자를 입력할 수 있습니다. 생성된 메소드에서 메소드를 호출해야 합니다. setContentView(), 그러면 준비된 마크업이 화면에 로드됩니다. 우리는 이 옵션을 갖게 될 것입니다.
패키지 ru.alexanderklimov.helloworld; android.app.Activity 가져오기; import android.os.Bundle; /** * Alexander Klimov가 2014년 12월 1일에 작성했습니다. */ 공개 클래스 AboutActivity 확장 활동 ( @Override protected void onCreate(Bundle saveInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); ) )
이제 가장 중요한 부분이 나옵니다. 우리의 임무는 첫 번째 화면에서 버튼을 클릭하면 새 화면으로 이동하는 것입니다. 수업으로 돌아가자 주요 활동. 버튼 클릭 핸들러를 작성해 보겠습니다.
Public void onClick(View view) ( 의도 의도 = new Intent(MainActivity.this, AboutActivity.class); startActivity(intent); )
여기서는 강의에서 설명한 버튼 클릭 처리 방법을 사용했습니다.
새 화면을 시작하려면 클래스의 인스턴스를 만들어야 합니다. 의지첫 번째 매개변수에 현재 클래스를 나타내고 두 번째 매개변수에 이동할 클래스를 나타냅니다. 활동정보. 이 후에 메소드가 호출됩니다. 시작활동(), 새 화면이 시작됩니다.
이제 에뮬레이터에서 애플리케이션을 테스트하려고 하면 오류 메시지가 표시됩니다. 우리가 뭘 잘못했어요? 우리는 한 가지 중요한 단계를 놓쳤습니다. 새로 등록하셔야 합니다 활동선언문에서 AndroidManifest.xml. 프로젝트에서 이 파일을 찾아 두 번 클릭하세요. 파일 편집 창이 열립니다. 새 태그 추가
문자열 리소스가 유용한 곳입니다. about_title. 응용 프로그램을 시작하고 버튼을 클릭하면 창이 나타납니다. 프로그램 소개. 이로써 새 창을 생성하고 버튼을 클릭하여 호출하는 방법을 배웠습니다. 그리고 우리는 매우 편리한 프로그램을 사용할 수 있습니다. 이제 고양이가 왼쪽으로 갈 때 무엇을 하는지에 대한 힌트를 항상 얻을 수 있습니다.
다시 한 번, 생성된 두 번째 활동 클래스는 클래스에서 상속되어야 한다는 점에 유의하세요. 활동또는 이와 유사한 것( 목록활동등), XML 마크업 파일(필요한 경우)이 있고 매니페스트에 지정되어야 합니다.
메소드를 호출한 후 시작활동()새로운 활동이 시작됩니다(이 경우 활동정보), 표시되고 실행 중인 구성 요소가 포함된 스택의 맨 위로 이동합니다. 메소드를 호출할 때 마치다()새 활동에서(또는 하드웨어 반환 키를 누르면) 닫히고 스택에서 제거됩니다. 개발자는 동일한 방법을 사용하여 이전(또는 다른) 활동으로 이동할 수도 있습니다. 시작활동().
세 번째 화면 만들기 - 게으른 사람들을 위한 방법
프로그래머는 고양이처럼 게으른 생물입니다. 활동의 경우 마크업과 다음을 상속하는 클래스를 생성해야 한다는 점을 항상 기억하세요. 활동, 매니페스트에 클래스를 등록하는 것을 잊지 마세요.
이 경우 메뉴에서 선택하세요. 파일 | 신규 | 활동 | 기본 활동(또는 다른 템플릿). 다음으로, 새 활동을 생성하기 위한 친숙한 창이 나타납니다. 필수 입력란을 작성하세요.
버튼을 클릭하세요 마치다그러면 활동이 준비됩니다. 이를 확인하려면 매니페스트 파일을 열고 새 항목을 확인하세요. 클래스와 마크업 파일에 대해 말하는 것이 아닙니다. 그것들은 저절로 여러분 앞에 나타날 것입니다.
메인 액티비티 화면에 직접 새로운 버튼을 추가하고, 생성된 액티비티로 전환하는 코드를 작성하세요.
처음에는 클래스, 마크업 및 매니페스트 간의 관계를 이해할 수 있도록 새 활동에 필요한 모든 구성 요소를 수동으로 생성하는 것이 좋습니다. 그리고 익숙해지면 활동 생성 마법사를 사용하여 작업 속도를 높일 수 있습니다.
활동 간 데이터 전달
우리는 다른 활동 화면을 호출하기 위해 간단한 예를 사용했습니다. 때로는 새 화면을 호출해야 할 뿐만 아니라 데이터도 해당 화면으로 전송해야 합니다. 예를 들어 사용자 이름입니다. 이 경우 특별한 영역을 이용해야 합니다. 추가 데이터, 클래스에는 의지.
지역 추가 데이터쌍의 목록입니다 핵심 가치, 의도와 함께 전송됩니다. 문자열은 키로 사용되며 모든 기본 데이터 유형, 기본 배열, 클래스 객체를 값으로 사용할 수 있습니다. 묶음등등
데이터를 다른 활동으로 전송하려면 다음 메소드를 사용하십시오. putExtra():
Intent.putExtra("키", "값");
수신 활동은 적절한 메소드를 호출해야 합니다. getIntExtra(), getStringExtra()등.:
Int count = getIntent().getIntExtra("name", 0);
이전 예제를 다시 실행해 보겠습니다. 우리에게는 이미 세 가지 활동이 있습니다. 첫 번째 활동에는 두 개의 텍스트 필드와 버튼이 있습니다. 모양은 다음과 같을 수 있습니다.
두 번째 활동에서는 두 번째 활동요소를 설정하다 텍스트뷰, 첫 번째 활동에서 받은 텍스트를 표시합니다. 메소드에 대해 다음 코드를 작성해 보겠습니다. onCreate()두 번째 활동에서.
@Override protected void onCreate(Bundle saveInstanceState) ( super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); String user = "Animal"; String Gift = "donuthole"; TextView infoTextView = (TextView)findViewById( R .id.textViewInfo); infoTextView.setText(user + ", 당신은 " + 선물을 받았습니다);
이제 프로그램을 실행하고 기사의 첫 번째 부분에서 설명한 대로 두 번째 창을 불러오면 기본 비문이 표시됩니다. 짐승아, 그들이 너에게 도넛 구멍을 건네줬어. 동의합니다. 그러한 메시지를 받는 것은 꽤 짜증나는 일입니다.
상황을 바로 잡자. 첫 번째 활동에 코드를 추가합니다.
Public void onClick(보기 보기) ( EditText userEditText = (EditText) findViewById(R.id.editTextUser); EditText GiftEditText = (EditText) findViewById(R.id.editTextGift); 의도 의도 = 새 의도(MainActivity.this, SecondActivity. class); // 첫 번째 텍스트 필드의 텍스트를 사용자 이름 키로 푸시합니다.intent.putExtra("username", userEditText.getText().toString()) //두 번째 텍스트 필드의 텍스트를 선물 키로 푸시합니다. intent.putExtra("선물" ", giftEditText.getText().toString()); startActivity(intent); )
우리는 그 물건을 특별한 용기에 담았습니다. 의지텍스트 필드에서 가져온 값을 가진 두 개의 키. 사용자가 텍스트 필드에 데이터를 입력하면 이 컨테이너로 이동하여 두 번째 액티비티로 전달됩니다.
두 번째 액티비티에서는 다음과 같이 메시지를 따뜻하게 받을 준비가 되어 있어야 합니다(굵은 글씨).
// 기본값 String user = "동물"; 문자열 선물 = "도넛 구멍"; user = getIntent().getExtras().getString("사용자 이름"); 선물 = getIntent().getExtras().getString("선물"); TextView infoTextView = (TextView)findViewById(R.id.textViewInfo); infoTextView.setText(user + " , 당신은 " + 선물을 받았습니다);
이제 메시지는 덜 불쾌해 보이고 어떤 사람들에게는 심지어 유쾌해 보이기도 합니다. 복잡한 예에서는 데이터를 처리할 때 검사를 추가하는 것이 좋습니다. 유형의 빈 데이터로 두 번째 활동을 시작하는 상황이 있을 수 있습니다. 없는, 이로 인해 애플리케이션이 중단될 수 있습니다.
우리의 경우에는 문자열 값이 필요하다는 것을 알고 있으므로 코드를 다음과 같이 다시 작성할 수 있습니다.
의도 의도 = getIntent(); user =intent.getStringExtra("사용자 이름");
User = getIntent().getStringExtra("사용자 이름");
이 프로그램에는 단점이 있습니다. 누구로부터 인사를 받는지 명확하지 않습니다. 잘 자란 원숭이는 익명의 출처로부터 선물을 받지 않습니다. 따라서 숙제로 다른 텍스트 필드를 추가하여 메시지를 보내는 사용자의 이름을 입력하세요.
Google에서는 키에 다음 형식을 사용할 것을 권장합니다. 즉, 패키지 이름을 접두사로 사용한 다음 키 자체를 사용하는 것입니다. 이 경우 다른 애플리케이션과 상호 작용할 때 키의 고유성을 확신할 수 있습니다. 이 같은:
공개 최종 정적 문자열 USER = "ru.alexanderklimov.myapp.USER";
누가 고양이 Vaska를 모함했는지 - 결과를 다시 얻습니다.
단순히 데이터를 다른 활동에 전달하는 것만으로는 항상 충분하지 않습니다. 때로는 다른 활동이 종료되었을 때 다른 활동에서 정보를 다시 가져와야 하는 경우도 있습니다. 이전에 우리가 이 방법을 사용했다면 startActivity(의도 의도), 관련 방법이 있습니다 startActivityForResult(의도 의도, int RequestCode). 두 방법의 차이점은 추가 매개변수입니다. 요청 코드. 기본적으로 스스로 생각해 낼 수 있는 정수입니다. 결과가 누구에게서 나왔는지 구별하기 위해 필요합니다. 5개의 추가 화면이 있고 여기에 1부터 5까지의 값을 할당하고 이 코드를 사용하여 처리해야 할 결과를 결정할 수 있다고 가정해 보겠습니다. -1 값을 사용하면 메소드를 호출하는 것과 동일합니다. 시작활동(), 즉. 우리는 어떤 결과도 얻지 못할 것입니다.
방법을 사용하면 startActivityForResult(), 결과를 받으려면 코드의 메서드를 재정의해야 합니다. onActivityResult()그리고 그 결과를 처리합니다. 혼란스러운? 예를 살펴보겠습니다.
당신이 탐정이라고 가정해 봅시다. 한 식당의 유력 인사 테이블에서 소시지 2조각과 기타 물품이 도난당했다는 제보를 받았습니다. 까마귀, 빌어 먹을 개, 고양이 Vaska 등 세 명의 용의자가 의심되었습니다.
방문객 중 한 명이 자신의 자랑스러운 iPhone에서 일련의 사진을 제공했습니다.
또 다른 목격자의 증언도 있습니다. 그리고 Vaska는 듣고 먹습니다.
새 프로젝트 만들기 셜록두 가지 활동으로. 첫 번째 화면에는 두 번째 화면으로 전환하는 버튼과 도둑의 이름이 표시되는 텍스트 라벨이 있습니다.
두 번째 화면에는 스위치 그룹이 있습니다.
두 번째 화면에서 응답을 기대하므로 다음 메소드를 사용해야 합니다. startActivityForResult()변수를 전달하는 첫 번째 화면에서 CHOOSE_THIEF매개변수로 요청 코드.
정적 최종 개인 int CHOOSE_THIEF = 0; public void onClick(View v) ( IntentquestionIntent = new Intent(MainActivity.this, ChooseActivity.class); startActivityForResult(questionIntent, CHOOSE_THIEF); )
코드를보세요. 버튼을 클릭하면 두 번째 화면에서 작업하게 됩니다. 활동 선택결과를 기다리는 두 번째 화면을 시작합니다.
두 번째 화면으로 이동하여 두 번째 액티비티에 대한 코드를 작성해 보겠습니다.
공개 최종 정적 문자열 THIEF = "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick(View v) ( Intent AnswerIntent = new Intent(); 스위치 (v.getId()) ( 케이스 R.id.radioDog: AnswerIntent.putExtra(THIEF, "Fucking doggie"); break; 케이스 R.id .radioCrow: responseIntent.putExtra(THIEF, "Crow"); case R.id.radioCat: AnswerIntent.putExtra(THIEF, "Przewalski's Horse"); break; ;
여기에서는 모든 것이 간단합니다. 형사가 범죄자의 이름을 선택한 다음 방법을 통해 putExtra()키의 이름과 그 값을 전달합니다.
편의상 선택 후 두 번째 창을 즉시 닫고 닫기 전에 값을 전달합니다. RESULT_OK, 선택이 이루어졌음을 분명히 알 수 있습니다. 사용자가 뒤로 버튼을 통해 화면을 닫으면 값이 전달됩니다. RESULT_취소됨.
방법 setResult()두 개의 매개변수, 즉 결과 코드와 인텐트로 표현되는 결과 자체를 사용합니다. 결과 코드는 일반적으로 활동이 완료된 결과를 알려줍니다. 활동.RESULT_OK, 또는 활동.RESULT_CANCELED. 어떤 경우에는 애플리케이션에 특정한 변형을 처리하기 위해 자체 반환 코드를 사용해야 합니다. 방법 setResult()모든 정수 값을 지원합니다.
버튼을 통해 명시적으로 데이터를 전달하려는 경우 메서드를 추가하는 것이 좋습니다. 마치다()불필요하게 두 번째 활동을 닫습니다. 뒤로 버튼을 통해 전환이 발생하는 경우에는 필요하지 않습니다.
사용자가 하드웨어 반환 버튼을 눌러 액티비티를 닫았거나 메소드가 종료된 경우 마치다()메소드 이전에 호출되었습니다. setResult(), 결과 코드는 다음과 같이 설정됩니다. RESULT_취소됨, 반환된 인텐트에 값이 표시됩니다. 없는.
첫 화면으로 돌아갑니다. 첫 번째 화면은 두 번째 화면의 응답을 기다리고 있으므로 코드에 메소드를 추가해야 합니다. onActivityResult().
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) ( super.onActivityResult(requestCode, resultCode, data); TextView infoTextView = (TextView) findViewById(R.id.textViewInfo); if (requestCode == CHOOSE_THIEF) ( if (resultCode == RESULT_OK) ( String thiefname = data.getStringExtra(ChooseActivity.THIEF); infoTextView.setText(thiefname); )else ( infoTextView.setText(""); // 텍스트 지우기 ) ) )
이 메서드는 코드와 함께 들어오는 데이터를 예상합니다. CHOOSE_THIEF, 그러한 데이터가 도착하면 키에서 값을 검색합니다. ChooseActivity.THIEF방법을 사용하여 getStringExtra. 결과 값을 다음과 같이 표시합니다. 텍스트뷰(변하기 쉬운 infoTextView). 뒤로 버튼을 통해 화면으로 돌아오면 텍스트를 지우면 됩니다.
상위 구성 요소 내에서 하위 활동이 닫히면 핸들러가 실행됩니다. onActivityResult(). 매니저 onActivityResult()여러 매개변수를 허용합니다.
- 요청 코드. 결과를 반환하는 활동을 시작하는 데 사용되는 코드
- 결과 코드. 작업이 어떻게 완료되었는지를 나타내는 하위 활동에 의해 설정된 결과 코드입니다. 이는 임의의 정수 값일 수 있지만 일반적으로 다음 중 하나입니다. 활동.RESULT_OK, 또는 활동.RESULT_CANCELED
- 데이터. 반환된 데이터를 패키징하는 데 사용되는 인텐트입니다. 하위 활동의 목적에 따라 선택한 콘텐츠를 나타내는 URI 경로가 포함될 수 있습니다. 대안으로(또는 보완적으로) 하위 활동은 인텐트 매개변수에 래핑된 간단한 값으로 정보를 반환할 수 있습니다. 엑스트라
하위 활동이 예기치 않게 종료되거나 종료되기 전에 결과 코드가 지정되지 않은 경우 이 매개변수는 활동.RESULT_CANCELED.
프로젝트를 시작하고 버튼을 클릭하면 두 번째 화면으로 이동합니다. 거기에서 옵션 중 하나를 선택합니다. 까마귀를 선택하면 화면이 닫히고 첫 화면에 범인의 이름이 나타난다. 개를 선택하면 이름이 표시됩니다.
참고로 고양이를 선택하면 이름이 표시되지 않습니다! 직접 확인해 보세요. 왜냐고 물어보시겠어요? 초등학생 왓슨! 범죄자는 한 가지 중요한 세부 사항을 고려하지 않았습니다. 식당은 비디오 카메라로 감시되고 있었고, 녹화 결과 실제로 누가 소시지를 훔치고 고양이를 액자에 넣었는지 드러났습니다. 바스카, 잠깐만요!
추신 처음에는 뭔가 불분명해 보였다면 연습을 통해 많은 것이 더 명확해질 것입니다. 화면 간 데이터 전송은 애플리케이션에서 흔히 발생하며 예제를 두 번 이상 학습하게 됩니다.
추신 최고의 생선은 소시지입니다. 이런 약점을 알기 때문에 고양이를 모함하는 것은 어렵지 않았습니다.
필터 사용
기사에서 나는 메서드에 있을 때 다른 활동으로 전환하는 일반적인 방법을 보여주었습니다. 시작활동()현재 수업과 이전할 수업이 표시됩니다. 그런데 활동 클래스가 애플리케이션의 일부일 필요는 없습니다. 다른 애플리케이션의 클래스 이름을 알고 있는 경우 해당 애플리케이션으로 전환할 수 있습니다. 하지만 다른 방법으로 다른 활동으로 이동할 수 있습니다.
실제로는 덜 일반적이지만 유용할 수 있습니다. 이미 두 번째 활동이 있다고 가정해 보겠습니다. 매니페스트에 특수 필터를 추가합니다.
그리고 이런 식으로 버튼을 클릭하면 두 번째 액티비티가 시작됩니다.
공개 무효 onClick(보기 보기) ( startActivity(new Intent("ru.alexanderklimov.testapplication.SecondActivity")); )
긴 문자열을 상수로 바꾸겠습니다.
공개 정적 최종 문자열 ACTION_SECOND_ACTIVITY = "ru.alexanderklimov.testapplication.SecondActivity"; 공개 무효 onClick(보기 보기) ( startActivity(new Intent(ACTION_SECOND_ACTIVITY)); )
그래서 우리는 무엇을 했습니까? 두 번째 활동에서는 필터를 등록하고 이름을 지정했습니다. 행동속성에 안드로이드:이름. 편의상 패키지 이름과 함께 액티비티의 전체 이름만 넣었습니다. 클래스 생성자 의지여러 가지 오버로드된 버전이 있습니다. 한 버전에서는 작업에 대한 문자열을 지정할 수 있습니다. 두 번째 활동에 등록된 생성된 작업을 표시했습니다. 작동 중에 시스템은 설치된 모든 애플리케이션의 매니페스트를 봅니다. 일치하는 항목을 검색하면 시스템에서 필터를 찾아 필요한 활동을 시작합니다.
동일한 원리를 사용하여 다른 활동을 시작할 수 있습니다. 예를 보세요. 예제를 직접 복사하고 설명서를 보면 android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, 이 코드가 문자열 상수에 해당하는 것을 볼 수 있습니다 공개 정적 최종 java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS". 우리 코드와 비교해 보세요. 오프라인 모드에 대한 설정 활동의 필터에 이 줄이 있다고 가정할 수 있습니다.
카테고리 이름 필터링 android.intent.category.DEFAULT활동을 시작하는 기본 작업을 수행하도록 시스템에 지시합니다. 아직 우리에게 관심이 없는 다른 이름이 있습니다.
이제 마지막 질문입니다. 다른 활동을 만들고 두 번째 활동과 동일한 필터를 지정하면 어떻게 되나요? 확인 해보자. 세 번째 활동을 만들고 두 번째 활동의 필터가 포함된 블록을 해당 활동에 복사합니다.
첫 번째 활동에서 버튼을 클릭합니다. 시스템에서 원하는 옵션을 선택하라는 메시지를 표시합니다.
선택하면 언제나, 그러면 다음번에는 선택할 필요가 없습니다. 선택을 재설정하려면 설정의 애플리케이션 속성으로 이동하여 버튼을 찾으세요. 기본값 지우기.
이름으로 활동 시작
생성자에서 의지두 번째 매개변수는 클래스입니다. 그러나 활동 이름이 표시되는 일종의 데이터베이스가 있고 해당 이름으로 원하는 활동을 시작해야 한다고 가정해 보겠습니다. 문자열 변수를 기반으로 클래스 자체를 가져오고 활동을 시작할 수 있습니다.
Try ( // 활동 클래스의 전체 이름 String ActivityName = "ru.alexanderklimov.testapplication.SecondActivity"; // 클래스 객체 가져오기>myClass = Class.forName(activityName); 인텐트 인텐트 = new Intent(this, myClass); startActivity(의도); ) catch (ClassNotFoundException e) ( e.printStackTrace(); )
어떻게 든 서비스에서 활동으로 데이터를 전송하는 작업이 있었습니다. 표준 SDK에서 솔루션을 찾기 시작했는데 시간이 없어서 데이터베이스를 활용하는 형태로 잘못된 솔루션을 만들었습니다. 그러나 질문은 열려 있었고 얼마 후 SDK에 있는 Message, Handler, Messenger 클래스를 사용하는 더 정확한 방법을 알아냈습니다.
아이디어
활동에서 서비스로 데이터를 전송하고 그 반대로 전송해야 합니다. 어떻게 해야 할까요? 우리는 문제를 해결하는 데 필요한 모든 것을 이미 갖추고 있습니다. 필요한 것은 BindService를 사용하여 활동에 서비스를 바인딩하고 필요한 매개변수와 메시지 클래스를 사용하는 형태로 약간의 마법을 전달하는 것뿐입니다. 그리고 마술은 Message 인스턴스 변수, 특히 replyTo를 사용하는 것입니다. 활동에서 Messanger 서비스 인스턴스에 액세스하고 서비스에서 활동의 Messanger 인스턴스에 액세스하려면 이 변수가 필요합니다. 사실 그렇게 간단하지는 않습니다. 적어도 내 재능이 부족한 마음에는. 부분적으로는 이미 존재하는 문서를 개선하는 중입니다. 서비스 또한 StackOverflow에 대한 좋은 예가 있습니다. 어쨌든 이 기사가 적어도 누군가에게 유용하고 내 작업이 헛되지 않았기를 바랍니다.
예
예를 들어, 카운터 값을 늘리거나 줄이고 결과를 TextView의 활동에 반환하는 서비스를 구현하겠습니다. 두 개의 버튼과 하나의 텍스트 필드가 있으므로 레이아웃 코드는 생략하겠습니다. 모든 것이 간단합니다.
구현
전체 활성화 코드는 다음과 같습니다.
Public 클래스 MainActivity는 Activity를 확장합니다( public static final String TAG = "TestService"; TestServiceConnection testServConn; TextView testTxt; final Messenger 메신저 = new Messenger(new IncomingHandler()); Messenger toServiceMessenger; @Override public void onCreate(Bundle saveInstanceState)( super. onCreate(savedInstanceState); setContentView(R.layout.activity_main); testTxt = (TextView)findViewById(R.id.test_txt);bindService(new Intent(this, TestService.class), (testServConn = new TestServiceConnection()) .BIND_AUTO_CREATE); ) @Override 공개 void onDestroy())( super.onDestroy(); unbindService(testServConn); ) 공개 void countIncrClick(보기 버튼)( 메시지 msg = Message.obtain(null, TestService.COUNT_PLUS); msg. replyTo = 메신저; 시도 ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) public void countDecrClick(보기 버튼)( 메시지 msg = Message.obtain(null, TestService.COUNT_MINUS); msg .replyTo = 메신저; try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) 개인 클래스 IncomingHandler 확장 핸들러 ( @Override public void handlerMessage(Message msg)( 스위치 (msg.what) ( 사례 TestService. GET_COUNT: Log.d(TAG, "(activity)...get count"); testTxt.setText(""+msg.arg1); break; ) private class TestServiceConnection은 ServiceConnection을 구현합니다( @Override public void onServiceConnected(ComponentName) 이름, IBinder 서비스) ( toServiceMessenger = new Messenger(service); //카운터의 초기 값을 보냅니다. Message msg = Message.obtain(null, TestService.SET_COUNT); msg.replyTo = 메신저; msg.arg1 = 0; / /우리 카운터 try ( toServiceMessenger.send(msg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) @Override public void onServiceDisconnected(ComponentName name) ( ) ) )
설명하겠습니다. 활동을 생성할 때 즉시 서비스에 바인딩하여 ServiceConnection 인터페이스를 구현하고 그 안에서 "카운터 값 설정" 서비스에 메시지를 보내고 0을 전달하고 toServiceMessanger를 생성하고 IBinder 인터페이스를 생성자에 전달합니다. 그런데 이 복사본을 서비스에 반환해야 합니다. 그렇지 않으면 NPE가 발생합니다. 이 클래스를 사용하여 서비스에 메시지를 보냅니다. 여기에 마법이 있습니다. replyTo 변수에 다른 메신저 인스턴스를 저장합니다. 이 인스턴스는 서버로부터 응답을 받고 이를 통해 활동과의 통신이 수행됩니다.
서비스로부터 메시지를 받으려면 핸들러를 사용하여 필요한 변수를 찾아 조치를 취하면 됩니다. 버튼(countIncrClick, countDecrClick 메소드)을 클릭하면 msg.what 변수에 원하는 작업을 나타내는 요청이 서비스에 전송됩니다.
패키지 com.example.servicetest; import android.app.Service; import android.content.*; import android.os.*; import android.os.Process; import android.util.Log; 공용 클래스 TestService 확장 서비스( public static final int COUNT_PLUS = 1; public static final int COUNT_MINUS = 2; public static final int SET_COUNT = 0; public static final int GET_COUNT = 3; int count = 0; IncomingHandler inHandler; 메신저 메신저; 메신저 toActivityMessenger; @Override public void onCreate())( super.onCreate(); HandlerThread 스레드 = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start(); inHandler = new IncomingHandler(thread.getLooper()); messanger = new Messenger(inHandler); ) @Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); ) @Override public int onStartCommand(Intentintent, int flags, int startId) ( return START_STICKY; ) //메시지 핸들러 활동 비공개 클래스 IncomingHandler 확장 핸들러( public IncomingHandler(Looper looper)( super(looper); ) @Override public void handlerMessage(Message msg)( //super.handleMessage(msg); toActivityMessenger = msg.replyTo; 스위치 (msg.what) ( 케이스 SET_COUNT: count = msg.arg1; Log.d(MainActivity.TAG, "(service)...set count"); break; 케이스 COUNT_PLUS: count++; Log.d(MainActivity.TAG , "(서비스)...카운트 플러스"); 케이스 COUNT_MINUS: Log.d(MainActivity.TAG, "(서비스)...카운트 마이너스"); 활동 중 Message outMsg = Message.obtain(inHandler, GET_COUNT ); outMsg.arg1 = 개수; outMsg.replyTo = 메신저; try ( if(toActivityMessenger != null) toActivityMessenger.send(outMsg); ) catch (RemoteException e) ( e.printStackTrace(); ) ) )
모든 것이 Activiti의 논리와 유사합니다. 설명이 필요한지조차 모르겠습니다. 유일한 요점은 매직 replyTo 변수를 사용하고 위의 원하는 메신저를 꺼내서 즉시 요청을 HandleMessage의 활동으로 다시 보낸다는 것입니다. 제가 이미 이야기한 두 번째 요점은 다음과 같습니다.
@Override public IBinder onBind(Intent arg0) ( return messanger.getBinder(); )
그것 없이는 모든 것이 무너질 것입니다. ServiceConnection에 전달되는 것은 이 인터페이스 인스턴스입니다.
결론
전체적으로. 이는 활동과 서비스 간의 상호작용에 대한 믿기 힘든 예입니다. 다른 사람들은 다르게 생각할 수도 있지만 이것은 다소 사소하지 않은 상호 작용인 것 같습니다.
PM의 질문, 설명 등. 일부 내용에 부정확한 내용이 있을 수 있으므로 자유롭게 작성하고 수정하세요.
이 게시물이 독자들에게 도움이 되었기를 바랍니다.