Android ActivityForResult的使用與練習

學習了來自ApiDemos中的App->Activity->Receive Rseult的應用程式,此程式主要目的是在於熟悉Intent中startActivityForResult的用法,在此紀錄一下心得以及在實作中遇到的現象。



Intent的作用: 作為Activity之間互動的工具。當要將目前的Activity跳轉至另一個Activity時,先前已知道可以使用Intent來達成這項目的,甚至可以利用setExtras來放上附加資訊來傳遞至下一個Activity。(reference: http://hbiao68.iteye.com/blog/1319225)
若今天的情況是Activity_A需要轉至Activity_B,並從Activity_B取得一些資訊後再回到Activity_A中的話要怎麼作呢?
1. 或許使用Intent(Activity_A.this, Activity_B.class)與Intent(Activity_B.this, Activity_A.class)可以達到A跳至B再回到A來,然後將資料用Extras方式傳送與取得。
2. 第二個方式就是這次範例所用到的startActivityForResult方式。關於說明可以在網路上找到很多教學與解釋。目前理解上就是Activity之間從A轉到B,然後在B中取得資料後用setResult方式回傳至A( 如果B程式中沒有結束指令的話當前的Activity仍然還會是B,範例中是以finish()來結束B而回到A),然後A會去呼叫onActivityResult 函數,在這裡面可以取得B所回傳而來的訊息並作適當處理。
範例程式碼:

public class ActivityForResult extends Activity {
    private TextView texta;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activity_for_result);
        Button btnab = (Button) findViewById(R.id.btnAB);
        Button btnac = (Button) findViewById(R.id.btnAC);
        Button btnactview = (Button) findViewById(R.id.btnActView);
        Button btnactedit = (Button) findViewById(R.id.btnActEdit);
        Button btnactdial = (Button) findViewById(R.id.btnActDial);
        Button btnactweb = (Button) findViewById(R.id.btnActWeb);
        Button btnactcall = (Button) findViewById(R.id.btnActCall);
        Button btnactmap = (Button) findViewById(R.id.btnActMap);
       
       
        btnab.setOnClickListener(btnabListener);
        btnac.setOnClickListener(btnacListener);
        btnactview.setTag(0);
        btnactedit.setTag(1);
        btnactdial.setTag(2);
        btnactcall.setTag(3);
        btnactmap.setTag(4);
        btnactweb.setTag(5);
       
        btnactview.setOnClickListener(btnactListener);
        btnactedit.setOnClickListener(btnactListener);
        btnactdial.setOnClickListener(btnactListener);
        btnactcall.setOnClickListener(btnactListener);
        btnactmap.setOnClickListener(btnactListener);
        btnactweb.setOnClickListener(btnactListener);
        texta = (TextView) findViewById(R.id.textA);
        texta.setText(texta.getText(), TextView.BufferType.EDITABLE);
    }

OnCreate函數主要在做依layout顯示畫面、設定按鈕監聽功能以及設定TextView可編輯項目。設定TextView可編輯項目這邊依目前實作後的理解是能將顯示過的訊息保存下來,而不會被新的訊息清除掉,在後續的程式中會發現並不是用setText()去顯示,而是用append去添加每一筆訊息於前次訊息之後。

static final private int GET_CODE = 0;
    private OnClickListener mGetListener = new OnClickListener() {
        public void onClick(View v) {
            // Start the activity whose result we want to retrieve.  The
            // result will come back with request code GET_CODE.
            Intent intent = new Intent(ReceiveResult.this, SendResult.class);
            startActivityForResult(intent, GET_CODE);
        }
    };

當按鈕按下後表示要執行跳轉到B的程序,其中startActivityForResult(intent, GET_CODE)的GET_CODE是可以用來識別由哪個Activity回傳資訊回來的一項重要參數,在此例中因為只有兩個Activity所以無法發揮作用,但可以想像一下如果App中有多個Activity A,B,C,D,…,假設A會跳轉B或C去取得資料,這時候回傳至A的資料如何分辨是來自B還是C呢,GET_CODE這時就可發揮辨識的作用,之後的範例實作會使用到。

@Override
    protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
        // You can use the requestCode to select between multiple child
        // activities you may have started.  Here there is only one thing
        // we launch.
        if (requestCode == GET_CODE) {

            // We will be adding to our text.
            Editable text = (Editable)mResults.getText();
            // This is a standard resultCode that is sent back if the
            // activity doesn't supply an explicit result.  It will also
            // be returned if the activity failed to launch.
            if (resultCode == RESULT_CANCELED) {
                text.append("(cancelled)");
            // Our protocol with the sending activity is that it will send
            // text in 'data' as its result.
            } else {
                text.append("(okay ");
                text.append(Integer.toString(resultCode));
                text.append(") ");
                if (data != null) {
                    text.append(data.getAction());
                }
            }
            text.append("\n");
        }
    }

這段程式就是在作取得回傳的資料並將其顯示在畫面上的工作。以下是SendResult程式碼:

public class SendResult extends Activity
{
    /**
     * Initialization of the Activity after it is first created.  Must at least
     * call {@link android.app.Activity#setContentView setContentView()} to
     * describe what is to be displayed in the screen.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // Be sure to call the super class.
        super.onCreate(savedInstanceState);

        // See assets/res/any/layout/hello_world.xml for this
        // view layout definition, which is being set here as
        // the content of our screen.
        setContentView(R.layout.send_result);
        // Watch for button clicks.
        Button button = (Button)findViewById(R.id.corky);
        button.setOnClickListener(mCorkyListener);
        button = (Button)findViewById(R.id.violet);
        button.setOnClickListener(mVioletListener);
    }
    private OnClickListener mCorkyListener = new OnClickListener()
    {
        public void onClick(View v)
        {
            // To send a result, simply call setResult() before your
            // activity is finished.
            setResult(RESULT_OK, (new Intent()).setAction("Corky!"));
            finish();
        }
    };
    private OnClickListener mVioletListener = new OnClickListener()
    {
        public void onClick(View v)
        {
            // To send a result, simply call setResult() before your
            // activity is finished.
            setResult(RESULT_OK, (new Intent()).setAction("Violet!"));
            finish();
        }
    };
}

實作:
1. 實驗A->B,A->C時資料回傳的辨識方式。
2. setTag與getTag的使用。

程式碼:

package com.example.activityforresulttest;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.Editable;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class ActivityForResult extends Activity {
    private TextView texta;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activity_for_result);
        Button btnab = (Button) findViewById(R.id.btnAB);
        Button btnac = (Button) findViewById(R.id.btnAC);
        Button btnactview = (Button) findViewById(R.id.btnActView);
        Button btnactedit = (Button) findViewById(R.id.btnActEdit);
        Button btnactdial = (Button) findViewById(R.id.btnActDial);
        Button btnactweb = (Button) findViewById(R.id.btnActWeb);
        Button btnactcall = (Button) findViewById(R.id.btnActCall);
        Button btnactmap = (Button) findViewById(R.id.btnActMap);
       
       
        btnab.setOnClickListener(btnabListener);
        btnac.setOnClickListener(btnacListener);
       //因以下按鈕觸發後執行的工作相近,利用Tag可以共用一個觸發函數
        btnactview.setTag(0);
        btnactedit.setTag(1);
        btnactdial.setTag(2);
        btnactcall.setTag(3);
        btnactmap.setTag(4);
        btnactweb.setTag(5);
       
        btnactview.setOnClickListener(btnactListener);
        btnactedit.setOnClickListener(btnactListener);
        btnactdial.setOnClickListener(btnactListener);
        btnactcall.setOnClickListener(btnactListener);
        btnactmap.setOnClickListener(btnactListener);
        btnactweb.setOnClickListener(btnactListener);
        texta = (TextView) findViewById(R.id.textA);
        texta.setText(texta.getText(), TextView.BufferType.EDITABLE);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_activity_for_result, menu);
        return true;
    }
    private OnClickListener btnabListener = new OnClickListener(){
        public void onClick(View v){
            Intent intent = new Intent(ActivityForResult.this,ActB.class);
            startActivityForResult(intent,0);
        }
    };
   
    private OnClickListener btnacListener = new OnClickListener(){
        public void onClick(View v){
            Intent intent = new Intent(ActivityForResult.this,ActC.class);
            startActivityForResult(intent,1);
        }
    };
   

注意這邊startActivityForResult第二項參數的不同之處,ActB傳來的requestCode=0,ActC傳來的requestCode=1,在A中的OnActivityResult()函數裡可藉此分辨。

    private OnClickListener btnactListener = new OnClickListener(){
        public void onClick(View v){
            Intent intent = new Intent();
            int tag = (Integer) v.getTag();
            String data;
            Uri uri;
            switch(tag){
            case 0:
                data = "content://contacts/people/1"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(uri);
                break;
            case 1:
                data = "content://contacts/people/1"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_EDIT); 
                intent.setData(uri);
                break;
            case 2:
                data = "tel:13811111111"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_DIAL);
                intent.setData(uri);
                break;
            case 3:
                data = "tel:13811111111"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_CALL);
                intent.setData(uri);
                break;
            case 4:
                data = "geo://39.92,116.46"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(uri);
                break;
            case 5:
                data = "http://www.google.com"; 
                uri = Uri.parse(data); 
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(uri);
                break;
            default:
                break;
            }
            startActivity(intent);
        }
    };
   

這裡是在實作用Intent來執行觀看聯絡人資訊、編輯聯絡人資訊、撥號畫面、執行撥號、開啟指定網頁、開啟地圖的方法。

    @Override
    protected void onActivityResult(int requestCode, int resultCode,
            Intent data){
        Editable text = (Editable)texta.getText();
        switch(requestCode){
        case 0:
           
            if(resultCode == RESULT_CANCELED){
                text.append("B:Cancelled!!");
            }
            else{
                text.append("B: ok("+Integer.toString(resultCode)+")- ");
                if(data!=null){
                    text.append(data.getAction());
                }
            }
            text.append("\n");
            break;
        case 1:
            if(resultCode == RESULT_CANCELED){
                text.append("C:Cancelled!");
            }
            else{
                text.append("C: Hello");
            }
            text.append("\n");
            break;
        default:
                break;
           
        }
       
    }
}

透過switch對requestCode的差異進行不一樣的處理,可以分辨出來自B或C回傳的資料。
附上其他Activity的程式碼:

package com.example.activityforresulttest;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class ActB extends Activity {
    private EditText editb;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_b);
        Button btnb = (Button) findViewById(R.id.btnB);
        btnb.setOnClickListener(btnbListener);
        editb = (EditText) findViewById(R.id.editTB);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_act_b, menu);
        return true;
    }
    private OnClickListener btnbListener = new OnClickListener(){
        public void onClick(View v){
            String input = editb.getText().toString();
            setResult(RESULT_OK,(new Intent()).setAction(input));
            finish();
        }
    };
   
}
package com.example.activityforresulttest;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ActC extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_act_c);
        Button btnc = (Button) findViewById(R.id.btnC);
        btnc.setOnClickListener(btncListener);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_act_c, menu);
        return true;
    }
    private OnClickListener btncListener = new OnClickListener(){
        public void onClick(View v){
            setResult(RESULT_OK);
            finish();
        }
       
    };
}

實作結果:
ActivityForResultTest1
ActivityForResultTest2ActivityForResultTest3
ActivityForResultTest4
在實作的過程中發現,當旋轉實機畫面時,TextView中的文字訊息會被回復原值(即message)文字,查了一下資料發現,旋轉實機時因為會變更畫面,而變更的方式是採用重啟Activity的方式,而先前的Activity會被殺掉,如果想要實機旋轉後不去改變文字訊息的話,可以將TextView的設定改為freezesText="true",就可以達到效果。
(reference: http://blog.csdn.net/mg505/article/details/7754678)

留言