[Android] 圖片要怎麼填滿layout/填滿螢幕?(How to make ImageView fill the layout/screen?)

若你的parent layout就是整個螢幕的話
在layout屬性裡面加入以下兩行

android:scaleType="centerCrop"
android:adjustViewBounds="true"

就會填滿螢幕了

繼續閱讀 [Android] 圖片要怎麼填滿layout/填滿螢幕?(How to make ImageView fill the layout/screen?)

Android – How to make a imageView full the screen?

在layout檔的屬性中加入

<ImageView
        android:id="@+id/trialIntervalImage"
        android:layout_width="2000dp"
        android:layout_height="1500dp"
        android:scaleType="fitXY"  //這行
        android:src="@drawable/trialintervalimage"
/>

android:scaleType=”fitXY” 會讓原圖滿版到整個螢幕

 

參考:

1.农民伯伯 Android2.2 API 中文文档系列(6) —— ImageView:

http://www.cnblogs.com/over140/archive/2010/09/19/1830703.html

Android – 觸發後只執行一次、要有時間性且更改UI的方法(AsycTask)

原意想要實作出像是delay多少秒之後要做UI更新

找到的方法是用timer、handler去做

 

不過用timer來計時每隔一段時間 重複執行某件事

再由handler去控制畫面UI的更新

-> 這個方法比較適合用在”重複執行”

 

對於這次我想要做的是,被觸發後,只想要執行一次

而這一次的動作,需要延遲幾秒鐘,且延遲完想要做些動作來恢復前面的改變

 

e.g. 在每個Trial間,想要插入間隔2000ms的空檔,實作方式用一張黑色底圖片蓋住原有圖,時間到後再把這張圖片拿掉

建立一個class繼承AsyncTask,其中要帶入三種參數<params, XXX, results > => 中間參數那項我忘記是什麼了

doInBackground是另一個會在背景執行thread,此範例是特地讓他delay一段時間

onPostExecute是執行完doInBackground後,會執行的一段程式,通常會用來顯示thread執行後的結果

在此例中,我拿來恢復原本的改變

private class TrialIntervalUpdate extends AsyncTask<Integer, Void, Integer> {
        @Override
        protected Integer doInBackground(Integer... params) {
            Log.e("doInBackground", "sleep "+params[0]+"ms");
            SystemClock.sleep(params[0]);
            return params[0];
        }

        protected void onPostExecute(Integer param)
        {
            Log.e("After "+ param + "ms","put img to back");
            trialIntervalImage.setImageAlpha(0);
        }
    }

 

創完class後,在想要觸發的地方,寫下:

            // 跑出來蓋住
            trialIntervalImage.bringToFront();
            trialIntervalImage.setImageAlpha(255);
            Log.e("clicked", "bringToFront and setAlpha 255");
            new TrialIntervalUpdate().execute(trialInterval);

先讓圖片跑到最上層、顯示不透明度255(最不透明 vs. 最透明是0)

再執行新的thread來實作delay,傳入想要delay的時間(int trialInterval)

 

 

參考:

1. 渺小且微不足道的晦暗 Android timer / sleep / delay / 更新 UI 的方法:

http://pontiffkao.blogspot.tw/2011/04/android-timer-sleep-delay-ui.html

2.  GIVEMEPASS’S ANDROID惡補筆記 無痛執行緒

http://givemepass.blogspot.tw/2011/10/blog-post.html

3. 老灰鴨的筆記本 【Android】AsyncTask – Thread 外的另一選擇

http://oldgrayduck.blogspot.tw/2013/01/androidasynctask-thread.html

4. Givemepass’s Android 惡補筆記 如何使用Handler

http://givemepass-blog.logdown.com/posts/296606-how-to-use-a-handler

對於Java新手,要如何開發Android Bluetooth App?

  1. 要寫Java程式,包括Android,一定要先安裝JDK(Java Developement Kit)
    1) 中文教學:http://rx1226.pixnet.net/blog/post/284754793-%5Bandroid-studio%5D-1-1-修改sdk和jdk位置
    2
    ) 前提是先抓 Java SE Development Kit 8u101
    http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
  2. 再來要寫Android App的話,就是要裝Android的開發環境,就是Android studio,怎麼抓?
    google搜尋:android studio download/ install
    – 如果抓下來安裝完後,不會設定、不知道要做什麼
    google搜尋:android studio tutorial / android studio 教學
    範例:http://androidstation.pixnet.net/blog/post/261391402-android-studio入門教學一:安裝和設定
  3. 要注意一點,以前開發android app是用eclipse,近幾年才改成android studio,所以在google時,注意一下google到的開發環境是哪一個,有時候看起來很像
  4. 弄完android studio後,需要安裝sdk(Software developement kit)
    google搜尋:android studio sdk
    範例:http://www.codedata.com.tw/mobile/android-tutorial-the-1st-class-2-android-sdk
所有環境弄好後,也試著把別人的範例程式抓下來,卻不知道如何下手或改寫?
在此我建議可以先從基本元件開始熟悉,我的熟悉方式和流程大約是
  1. 先創一個File-> New project-> empty activity
    – 如果到這邊不知道怎麼做的話,google搜尋:android studio new project
  2. 創好後,瀏覽一下左邊的檔案列表
    MainActivity_java_-_GmailTest_-____Documents_AndroidProject_GmailTest_
    看一看裡面的檔案有哪些,Java資料夾內有MainActivity.java,其他不重要
    再來res資料夾(resource)內有drawable(放圖片的)、layout(App的畫面呈現)、這兩個資料夾最重要,其餘可以之後有用到在學即可
    所以在layout裡,可以看到activity_main.xml檔,他就是App的主畫面,點進去看可以看到
    activity_main_xml_-_GmailTest_-____Documents_AndroidProject_GmailTest_
    可以試著切換Text和Design兩種呈現方式,基本上一開始只需要用Design的模式去做就好,換過去Design後,可以看到你的app畫面出來了
  3. 燒進去手機實體看看
    google搜尋:android studio 燒入手機
    範例:http://chiachiku.pixnet.net/blog/post/60204745-30分鐘做出自己的android-app
    如果
    找不到手機裡的開發人員模式在哪裡
    google搜尋:你的手機品牌 型號 開發人員
    範例:zenfone selfie 開發人員
燒成功後,再來就是試著熟悉元件了,元件就是有Button(按鈕)、TextView(文字方塊)、ImageView(圖片方塊)、EditText(編輯文字方塊)等等,還有很多元件,
但我建議這四個先練習過一次,怎麼練習?
  1. google搜尋:android button 教學
    google搜尋:android textview 教學
    google搜尋:android imageview 教學
    google搜尋:android edittext 教學
  2. 同樣都是照著裡面的程式,先照著打,不要複製貼上
  3. 一樣燒進去手機跑跑看
  4. 以button為例,跑完後,好,開始看網站上的教學,看一下網站上是如何解釋button程式碼的,如果沒有解釋,那再google下一個button教學,多看三、四個教學後,會發現有些共通點,都是寫在MainActivity內的onCreate()裡
  5. 這時,google搜尋:android oncreate
  6. 可以查到android作業系統內是如何控制App的存亡
  7. 再來button程式碼內,也都可以看到onClick
    google搜尋:android button onclick
  8. 可以查到onclick是做什麼的,沒查到就再查別人的教學
  9. 以此類推,把Button, TextView, ImageView, EditText的基礎程式碼學完
再回去看你抓過的Android範例程式碼,會發現你已經看得懂部分程式碼的運作了
以這個google的技巧為基礎,慢慢找出範例程式碼內的運作方式
Android App難的地方在於除了程式語言之外,還有包含作業系統
所以稍微複雜一點的App會用到Thread的概念
google搜尋:Android thread 教學

舉個例子:
可以看到有三個thread:
  1. AcceptThread
  2. ConnectThread
  3. ConnectedThread
都是跟藍芽連接有關的thread,網頁裡介紹的很詳細,可以先試著把程式碼燒進去兩隻手機裡,試跑看看能不能動
能動就來看看我們想改什麼?
假如想要改變成 藍牙圖片分享器
那麼可以想像,
應該要把原本藍牙聊天室的textview和edittext 改成 imageview和選取圖片的button
這時,就可以google: android button 選圖片

PhotoUploader: Using Android socket client send photo to Java socket server

大四下最後一學期 Bo的Java期末project
原本就很想做的socket練習
剛好在這次有機會來實做

project內容:
在Android端從圖片庫裡面選一張圖片(可從圖片庫或相簿裡選擇)
透過socket傳給已經在電腦上開好的Java Server

緣由:
因為每次拍完照要傳照片到電腦收藏都很麻煩
不是透過USB線就是透過雲端或是社群軟體或網站
用USB有時候會讀不到或是還要找線很麻煩
而雲端的容量會不夠放、也不確定安不安全
社群軟體或網站(Line, FB)都會把照片壓縮,畫質變很差,而且要一張一張抓
所以不如自己做一個傳照片的App吧!

Demo圖:



會傳到桌面,命名為socketReceive.jpg
使傳照片變得非常方便的App~~~~

Java Server:

JavaSocketServer.java:

import java.io.FileOutputStream;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class JavaSocketServer implements Runnable {
    
    public static final int SERVERPORT = 5987;
    
    // 最後要儲存照片的位置
    public static final String file_name = “/Users/RongSonHo/Desktop/socketReceive.jpg”;
    public void run() {
        
        try {
            
            System.out.println(“Server: Connecting…”);
            ServerSocket serverSocket = new ServerSocket(SERVERPORT);
            
            while (true) {
                
                Socket client = serverSocket.accept();
                System.out.println(“Server: Receiving…”);
                
                OutputStream out = new FileOutputStream(file_name);
                byte buf[] = new byte[1024];
                int len;
                
                // 讀入從手機端傳來的照片
                InputStream inputStream = client.getInputStream();
                try {
                    while ((len = inputStream.read(buf)) != -1) {
                        // 將照片寫入到電腦裡
                        out.write(buf, 0, len);
                    }
                    out.close();
                    inputStream.close();
                    
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    
                    client.close();
                    System.out.println(“Server: Done.”);
                    
                }
                
            }
            
        } catch (Exception e) {
            
            System.out.println(“Server: Error”);
            e.printStackTrace();
            
        }
        
    }
    public static void main(String str[]) {
        
        Thread desktopSerThread = new Thread(new JavaSocketServer());
        desktopSerThread.start();
        
    }

}



Android Client:

1. activity_main.xml:

<?xml version=”1.0″ encoding=”utf-8″?>
<RelativeLayout xmlns:android=”http://schemas.android.com/apk/res/android”
    xmlns:tools=”http://schemas.android.com/tools”
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:paddingBottom=”@dimen/activity_vertical_margin”
    android:paddingLeft=”@dimen/activity_horizontal_margin”
    android:paddingRight=”@dimen/activity_horizontal_margin”
    android:paddingTop=”@dimen/activity_vertical_margin”
    tools:context=”com.javacourse.rongsonho.androidsocketclient.MainActivity”
    android:background=”#006699″>
    <Button
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:text=”Choose Image”
        android:id=”@+id/button”
        android:background=”#0080FF”
        android:textColor=”@android:color/white”
        android:layout_above=”@+id/button2″
        android:layout_centerHorizontal=”true” />
    <Button
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:text=”Upload”
        android:id=”@+id/button2″
        android:background=”#0080FF”
        android:textColor=”@android:color/white”
        android:layout_alignParentBottom=”true”
        android:layout_centerHorizontal=”true” />
    <TextView
            android:layout_width=”wrap_content”
            android:layout_height=”wrap_content”
            android:textSize=”25dp”
            android:id= “@+id/textView”
            android:text=”Status”
            android:textColor=”@android:color/white”
            android:scrollbars=”vertical”
            android:singleLine=”false”
            android:maxLines=”20″
            android:layout_alignParentTop=”true”
            android:layout_centerHorizontal=”true” />
    <Button
        android:layout_width=”wrap_content”
        android:layout_height=”wrap_content”
        android:id=”@+id/refreshLog”
        android:text=”Refresh Log”
        android:layout_alignParentBottom=”true”
        android:layout_alignParentEnd=”true”
        android:background=”#0080FF”
        android:textColor=”@android:color/white”/>
</RelativeLayout>


2. MainActivity.java:

package com.javacourse.rongsonho.androidsocketclient;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
    Socket socket;
    //從手機裡的”我的檔案”選張照片,準備傳到電腦,
    //因不同的手機路徑可能不同,可自行修改。
    //public static final String file_name = “//storage/MicroSD/DCIM/Hello.jpg”;
    Button imageChooser, connecter, refreshLog;
    OutputStream outputstream;
    String ImagePath=””, timeString=””;
    BufferedInputStream bis;
    FileInputStream fis;
    TextView statusText;
    static byte[] mybytearray;
    int serverPort;
    InetAddress serverAddr;
    MyDBHandler dbHandler;
    SimpleDateFormat formatter;
    Date curDate;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageChooser = (Button)findViewById(R.id.button);
        connecter = (Button) findViewById(R.id.button2);
        refreshLog = (Button) findViewById(R.id.refreshLog);
        statusText = (TextView) findViewById(R.id.textView);
        statusText.setMovementMethod(ScrollingMovementMethod.getInstance());
        formatter = new SimpleDateFormat(“yyyy年MM月dd日HH:mm:ss”);
        Date curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
        String timeString = formatter.format(curDate);
        dbHandler = new MyDBHandler(this, null, null, 1);
        dbHandler.addLog(“[*]”+ timeString +”: Choose a picture to send to PCn”);
        printDatabase();
        imageChooser.setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                // 建立 “選擇檔案 Action” 的 Intent
                Intent intent = new Intent(Intent.ACTION_PICK);
                // 過濾檔案格式
                intent.setType(“image/*”);
                // 建立 “檔案選擇器” 的 Intent  (第二個參數: 選擇器的標題)
                Intent destIntent = Intent.createChooser(intent, “選擇檔案”);
                // 切換到檔案選擇器 (它的處理結果, 會觸發 onActivityResult 事件)
                startActivityForResult(destIntent, 0);
            }
        });
        connecter.setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                Thread test = new Thread(clientSocket);
                test.start();
                //statusText.setText(statusText.getText() + “[*] Connecting to server: ” + serverAddr.toString() + “/” + serverPort + ” …n”);
                //statusText.setText(statusText.getText()+”[*] Done!”);
            }
        });
        refreshLog.setOnClickListener(new View.OnClickListener() {
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
                printDatabase();
            }
        });
    }
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);
        // 有選擇檔案
        if ( resultCode == RESULT_OK ) {
            // 取得檔案的 Uri
            if (data != null) {
                Log.e(“Socket”, “great, data is not null”);
                Uri uri = data.getData();
                if (uri != null) {
                    String path = MagicFileChooser.getAbsolutePathFromUri(this,uri);
                    ImagePath = “/”+ path;
                    Log.e(“Socket”, ImagePath);
                    curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                    timeString = formatter.format(curDate);
                    dbHandler.addLog(“[*]”+timeString+”: “+ “ImagePath: “+ ImagePath + ” n”);
                    File myFile = new File(ImagePath);
                    if (myFile.exists()) {
                        try {
                            mybytearray = new byte[(int) myFile.length()];
                            fis = new FileInputStream(myFile);
                            bis = new BufferedInputStream(fis, 8 * 1024);
                            bis.read(mybytearray, 0, mybytearray.length);
                            Log.e(“Socket”, mybytearray.toString());
                            curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                            timeString = formatter.format(curDate);
                            Log.e(“Socket”, “File read done!”);
                            dbHandler.addLog(“[*]”+timeString + “: Image has been chosenn”);
                            printDatabase();
                        } catch (IOException e) {
                            curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                            timeString = formatter.format(curDate);
                            Log.e(“Socket”, “File read error!”);
                            dbHandler.addLog(“[*]”+timeString + “: file read error!”);
                            printDatabase();
                        }
                        //輸出到電腦
                    } else {
                        curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                        timeString = formatter.format(curDate);
                        Log.e(“Socket”, “file doesn’t exist!”);
                        dbHandler.addLog(“[*]”+timeString + “: file doesn’t exist!”);
                        printDatabase();
                    }
                } else {
                    setTitle(“無效的檔案路徑 !!”);
                }
            } else {
                setTitle(“取消選擇檔案 !!”);
            }
        }
    }
    Runnable clientSocket = new Runnable() {
        @Override
        public void run() {
            try {
                serverAddr = InetAddress.getByName(“172.20.10.4”);
                serverPort = 5987;
                curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                timeString = formatter.format(curDate);
                Log.e(“Socket”, “Client: Connecting…”);
                dbHandler.addLog(“[*]”+ timeString + “: Client: Connecting…: ” + serverAddr + “/” + serverPort + “n”);
                //printDatabase();
                try {
                    socket = new Socket(serverAddr, serverPort);
                    outputstream = socket.getOutputStream();
                    outputstream.write(mybytearray, 0, mybytearray.length);
                    outputstream.flush();
                } catch (Exception e) {
                    curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                    timeString = formatter.format(curDate);
                    Log.e(“Socket”, “Client: Error”, e);
                    dbHandler.addLog(“[*]”+timeString+ “: Client: Error” + e + “n”);
                    //printDatabase();
                } finally {
                    curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                    timeString = formatter.format(curDate);
                    Log.e(“Socket”, “Transfer done!”);
                    dbHandler.addLog(“[*]”+timeString+ “: Transfer done!n”);
                    socket.close();
                }
            } catch (Exception e) {
                curDate = new Date(System.currentTimeMillis()) ; // 獲取當前時間
                timeString = formatter.format(curDate);
                Log.e(“Socket”, “Client: Error”, e);
                dbHandler.addLog(“[*]”+timeString+ “: Client: Error” + e + “n”);
                //printDatabase();
            }
        }
    };
    public void printDatabase(){
        String DBString = dbHandler.databaseToString();
        statusText.setText(DBString);
    }
}


3. MyDBHandler.java:

package com.javacourse.rongsonho.androidsocketclient;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
 * Created by RongSonHo on 5/24/16.
 */
public class MyDBHandler extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 1;
    private static final String DATABASE_NAME = “socket.db”;
    private static final String TABLE_LOG = “socket_log”;
    private static final String COLUME_ID = “_id”;
    private static final String COLUME_LOG= “socketLog”;
    public MyDBHandler(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, DATABASE_NAME, factory, DATABASE_VERSION);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        String query = “CREATE TABLE ” + TABLE_LOG + ” ( ” +
                COLUME_ID + ” INTEGER PRIMARY KEY AUTOINCREMENT, ” +
                COLUME_LOG + ” TEXT ” +
                “);”;
        db.execSQL(query);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL(“DROP TABLE IF EXISTS ” + TABLE_LOG);
        onCreate(db);
    }
    public String databaseToString(){
        String dbString = “”;
        SQLiteDatabase db = getWritableDatabase();
        String query = “SELECT * FROM ” + TABLE_LOG + ” WHERE 1″;
        Cursor cursor = db.rawQuery(query, null);
        cursor.moveToFirst();
        while(!cursor.isAfterLast()){
            if(cursor.getString(cursor.getColumnIndex(COLUME_LOG))!= null){
                dbString += cursor.getString(cursor.getColumnIndex(COLUME_LOG));
                dbString += “n”;
            }
            cursor.moveToNext();
        }
        db.close();
        return dbString;
    }
    public void addLog(String newlog){
        ContentValues values = new ContentValues();
        values.put(COLUME_LOG, newlog);
        SQLiteDatabase db = getWritableDatabase();
        db.insert(TABLE_LOG, null, values);
        db.close();
    }
    public void deleteLog(){
        SQLiteDatabase db = getWritableDatabase();
        db.execSQL(“TRUNCATE TABLE ” + TABLE_LOG +”;” );
        db.close();
    }
}

4. MagicFileChooser.java: (別人寫好的工具,取自:https://magiclen.org/android-filechooser/)

package com.javacourse.rongsonho.androidsocketclient;

/**
 * Created by RongSonHo on 6/20/16.
 */
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ClipData;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
@SuppressLint(“NewApi”)
public class MagicFileChooser {
    public static final int ACTIVITY_FILE_CHOOSER = 9973;
    private final Activity activity;
    private boolean choosing = false;
    private boolean mustCanRead;
    private File[] chosenFiles;
    public MagicFileChooser(final Activity activity) {
        this.activity = activity;
    }
    public boolean showFileChooser() {
        return showFileChooser(“*/*”);
    }
    public boolean showFileChooser(final String mimeType) {
        return showFileChooser(mimeType, null);
    }
    public boolean showFileChooser(final String mimeType, final String chooserTitle) {
        return showFileChooser(mimeType, chooserTitle, false);
    }
    public boolean showFileChooser(final String mimeType, final String chooserTitle, final boolean allowMultiple) {
        return showFileChooser(mimeType, chooserTitle, allowMultiple, false);
    }
    public boolean showFileChooser(final String mimeType, final String chooserTitle, final boolean allowMultiple, final boolean mustCanRead) {
        if (mimeType == null || choosing) {
            return false;
        }
        choosing = true;
        // 檢查是否有可用的Activity
        final PackageManager packageManager = activity.getPackageManager();
        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType(mimeType);
        List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
        if (list.size() > 0) {
            this.mustCanRead = mustCanRead;
            // 如果有可用的Activity
            Intent picker = new Intent(Intent.ACTION_GET_CONTENT);
            picker.setType(mimeType);
            picker.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
            picker.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
            // 使用Intent Chooser
            Intent destIntent = Intent.createChooser(picker, chooserTitle);
            activity.startActivityForResult(destIntent, ACTIVITY_FILE_CHOOSER);
            return true;
        } else {
            return false;
        }
    }
    public boolean onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        if (requestCode == ACTIVITY_FILE_CHOOSER) {
            choosing = false;
            if (resultCode == Activity.RESULT_OK) {
                Uri uri = data.getData();
                if (uri != null) {
                    // 單選
                    chosenFiles = getFilesFromUris(activity, new Uri[]{uri}, mustCanRead);
                    return true;
                } else if (Build.VERSION.SDK_INT >= 16) {
                    // 複選
                    ClipData clipData = data.getClipData();
                    if (clipData != null) {
                        int count = clipData.getItemCount();
                        if (count > 0) {
                            Uri[] uris = new Uri[count];
                            for (int i = 0; i < count; i++) {
                                uris[i] = clipData.getItemAt(i).getUri();
                            }
                            chosenFiles = getFilesFromUris(activity, uris, mustCanRead);
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
    public File[] getChosenFiles() {
        return chosenFiles;
    }
    public static String[] getAbsolutePathsFromUris(final Context context, final Uri[] uris) {
        return getAbsolutePathsFromUris(context, uris, false);
    }
    public static String[] getAbsolutePathsFromUris(final Context context, final Uri[] uris, final boolean mustCanRead) {
        File[] files = getFilesFromUris(context, uris, mustCanRead);
        int filesLength = files.length;
        String[] paths = new String[filesLength];
        for (int i = 0; i < filesLength; i++) {
            paths[i] = files[i].getAbsolutePath();
        }
        return paths;
    }
    public static File[] getFilesFromUris(final Context context, final Uri[] uris) {
        return getFilesFromUris(context, uris, false);
    }
    public static File[] getFilesFromUris(final Context context, final Uri[] uris, final boolean mustCanRead) {
        ArrayList<File> fileList = new ArrayList<File>();
        int urisLength = uris.length;
        for (int i = 0; i < urisLength; i++) {
            Uri uri = uris[i];
            File file = getFileFromUri(context, uri, mustCanRead);
            if (file != null) {
                fileList.add(file);
            }
        }
        File[] files = new File[fileList.size()];
        fileList.toArray(files);
        return files;
    }
    public static String getAbsolutePathFromUri(final Context context, final Uri uri) {
        return getAbsolutePathFromUri(context, uri, false);
    }
    public static String getAbsolutePathFromUri(final Context context, final Uri uri, final boolean mustCanRead) {
        File file = getFileFromUri(context, uri, mustCanRead);
        if (file != null) {
            return file.getAbsolutePath();
        } else {
            return null;
        }
    }
    public static File getFileFromUri(final Context context, final Uri uri) {
        return getFileFromUri(context, uri, false);
    }
    @SuppressLint(“NewApi”)
    public static File getFileFromUri(final Context context, final Uri uri, final boolean mustCanRead) {
        if (uri == null) {
            return null;
        }
        // 判斷是否為Android 4.4之後的版本
        final boolean after44 = Build.VERSION.SDK_INT >= 19;
        if (after44 && DocumentsContract.isDocumentUri(context, uri)) {
            // 如果是Android 4.4之後的版本,而且屬於文件URI
            final String authority = uri.getAuthority();
            // 判斷Authority是否為本地端檔案所使用的
            if (“com.android.externalstorage.documents”.equals(authority)) {
                // 外部儲存空間
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] divide = docId.split(“:”);
                final String type = divide[0];
                if (“primary”.equals(type)) {
                    String path = Environment.getExternalStorageDirectory() + “/” + divide[1];
                    return createFileObjFromPath(path, mustCanRead);
                }
            } else if (“com.android.providers.downloads.documents”.equals(authority)) {
                // 下載目錄
                final String docId = DocumentsContract.getDocumentId(uri);
                final Uri downloadUri = ContentUris.withAppendedId(Uri.parse(“content://downloads/public_downloads”), Long.parseLong(docId));
                String path = queryAbsolutePath(context, downloadUri);
                return createFileObjFromPath(path, mustCanRead);
            } else if (“com.android.providers.media.documents”.equals(authority)) {
                // 圖片、影音檔案
                final String docId = DocumentsContract.getDocumentId(uri);
                final String[] divide = docId.split(“:”);
                final String type = divide[0];
                Uri mediaUri = null;
                if (“image”.equals(type)) {
                    mediaUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                } else if (“video”.equals(type)) {
                    mediaUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                } else if (“audio”.equals(type)) {
                    mediaUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                } else {
                    return null;
                }
                mediaUri = ContentUris.withAppendedId(mediaUri, Long.parseLong(divide[1]));
                String path = queryAbsolutePath(context, mediaUri);
                return createFileObjFromPath(path, mustCanRead);
            }
        } else {
            // 如果是一般的URI
            final String scheme = uri.getScheme();
            String path = null;
            if (“content”.equals(scheme)) {
                // 內容URI
                path = queryAbsolutePath(context, uri);
            } else if (“file”.equals(scheme)) {
                // 檔案URI
                path = uri.getPath();
            }
            return createFileObjFromPath(path, mustCanRead);
        }
        return null;
    }
    public static File createFileObjFromPath(final String path) {
        return createFileObjFromPath(path, false);
    }
    public static File createFileObjFromPath(final String path, final boolean mustCanRead) {
        if (path != null) {
            try {
                File file = new File(path);
                if (mustCanRead) {
                    file.setReadable(true);
                    if (!file.canRead()) {
                        return null;
                    }
                }
                return file.getAbsoluteFile();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }
    public static String queryAbsolutePath(final Context context, final Uri uri) {
        final String[] projection = {MediaStore.MediaColumns.DATA};
        Cursor cursor = null;
        try {
            cursor = context.getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
                final int index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                return cursor.getString(index);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            if (cursor != null) {
                cursor.close();
            }
        }
        return null;
    }
}


參考文章:

1. Android 如何選取圖片或是檔案?:https://magiclen.org/android-filechooser/
2. 西加加 Android 手機資料傳到電腦: http://pianovv510.blogspot.tw/2013/04/android-wifi.html
3. Android TextView多行本文滾動輕鬆實現:http://sunylin.pixnet.net/blog/post/91068996-android-textview多行本文滾動輕鬆實現