1. 程式人生 > >Android如何新增圖片

Android如何新增圖片

Android如何新增圖片

一、目標

通過在文章中插入圖片,實現圖文混排的功能。

二、下載地址

神馬筆記最新版本:【神馬筆記Version1.1.0_beta.apk

三、獲取圖片

有2種途徑可以獲取圖片

  1. 拍照(建立新的照片)
  2. 照片相簿(選擇手機上的照片)

在Android平臺,有2種方式可以用來實現這2種途徑

  1. 呼叫第三方應用
  2. 編寫拍照與相簿程式碼,自己實現之

前者在功能上可能會遇到一些限制,但工作量小。

後者更加靈活,可以隨意發揮,但工作量較大。雖然可以在Github上找到不錯的實現方案,終歸需要一些除錯的事件。

神馬筆記採用的是第一種方式——呼叫第三方應用

四、呼叫第三方應用

Android通過startActivityForResult呼叫地方應用,並且通過onActivityResult處理返回結果。這2個方法分別存在於Activity

Fragment中。

  • Activity#startActivityForResult
  • Activity#onActivityResult
  • Fragment#startActivityForResult
  • Fragment#onActivityResult

1. 呼叫拍照應用

public boolean request() {
    SoftInputUtils.hide(context);

    Uri imageUri;
    {
        File file = target.getFile();
        file.
getAbsoluteFile().getParentFile().mkdirs(); imageUri = UriUtils.fromFile(context, file); } Intent intent = new Intent(); { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); } try { parent.startActivityForResult(intent, requestCode); return true; } catch (Exception e) { e.printStackTrace(); } return false; }

2. 呼叫照片相簿應用

public boolean request() {
    SoftInputUtils.hide(context);

    Intent intent = new Intent(Intent.ACTION_PICK, null);
    intent.setDataAndType(
        MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
        "image/*");
    intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

    try {
        parent.startActivityForResult(intent, requestCode);

        return true;
    } catch (Exception e) {

    }

    return false;
}

五、優化呼叫過程

startActivityForResultonActivityResult這2個介面通過requestCode識別請求及結果。為了避免定義常量傳送請求以及使用switch語法處理結果,採用面向物件的方法來優化呼叫過程。

1. 定義呼叫處理類

public abstract class BaseRequestDelegate implements BiConsumer<Integer, Intent> {

    private static int COUNTER = 1;

    protected int requestCode;

    protected Fragment parent;
    protected Activity context;

    public BaseRequestDelegate(Fragment f) {
        this.context = f.getActivity();
        this.parent = f;

        this.requestCode = COUNTER;

        {
            int counter = COUNTER;
            ++counter;
            counter %= 1000;
            COUNTER = counter;
        }
    }

    public int getRequestCode() {
        return requestCode;
    }

    public abstract boolean request();

    public abstract void accept(Integer resultCode, Intent data);
}

BaseRequestDelegate會自動產生requestCode,避免定義常量。這裡使用了是COUNTER的方式,每次建立一個新的請求,計數器累加1作為下一次的requestCode,並且限定在1000以內。

BaseRequestDelegate封裝了2個方法request用與傳送請求,以及accept用於處理結果。

2. 定義呼叫管理類

public class RequestResultManager {

    HashMap<Integer, BiConsumer<Integer, Intent>> map;

    public RequestResultManager() {
        this.map = new HashMap<>();
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        BiConsumer delegate = map.remove(requestCode);
        if (delegate != null) {
            delegate.accept(resultCode, data);
        }
    }

    public void request(BaseRequestDelegate delegate) {
        boolean result = delegate.request();
        if (result) {
            map.put(delegate.getRequestCode(), delegate);
        }
    }

}

RequestResultManager負責管理BaseRequestDelegate,通過request方法傳送請求。在onActivityResult處理結果。

3. 優化呼叫過程

  • 呼叫第三方應用
void requestInsertion() {

    MenuItemClickListener listener = new MenuItemClickListener();

    {

        listener.put(R.id.menu_insert_paragraph, e ->
                     new ParagraphInsertion(insertionCallback).execute()
                    );

        listener.put(R.id.menu_camera, e -> {
            CameraDelegate delegate = new CameraDelegate(this, insertionCallback);
            requestResultManager.request(delegate);
        });

        listener.put(R.id.menu_photo, e -> {
            PhotoDelegate delegate = new PhotoDelegate(this, insertionCallback);
            requestResultManager.request(delegate);
        });

    }

    PopupMenuDialogFragment dialogFragment = new PopupMenuDialogFragment();
    dialogFragment.setTheme(R.style.DialogDimTheme);
    dialogFragment.setMenuResource(R.menu.menu_compose_insertion);
    dialogFragment.setOnMenuItemClickListener(listener);
    dialogFragment.showNow(getFragmentManager(), "insertion");
}
  • 處理呼叫結果
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    requestResultManager.onActivityResult(requestCode, resultCode, data);
}

六、Final

通過呼叫第三方拍照及相簿應用,可以快速實現文章中插入圖片的功能。但是無法進一步操作第三方應用,使用靈活性較低。比如,呼叫相簿應用新增某一相簿下的圖片,需要多次選擇,無法記錄最近一次使用的相簿就頗為麻煩。