大疆文档-Android教程-MediaManager功能实现

大疆文档-Android教程-MediaManager功能实现

如果您在本教程中发现任何错误或bug,请发送电子邮件至[email protected]告知我们。请随时发送给我们Github pull request,帮助我们解决任何问题。在本教程中,您将学习如何使用MediaManager与飞机相机SD卡上的文件系统进行交互。在本教程结束时,您将拥有一个应用程序,您可以使用它来预览照片、播放视频、下载或删除文件等。然而,为了让我们的应用程序管理照片和视频,它必须首先能够拍摄和记录它们。幸运的是,通过使用DJI Android UX SDK,您可以使用标准的DJI Go ui轻松实现拍照和录制视频的功能。您可以从这个Github页面下载本教程的最终示例项目。我们使用Mavic Pro和Nexus 5作为例子来做这个演示。有关为iPhone设备定制布局的更多细节,请查看教程的Github示例项目。

应用激活和飞机绑定在中国

对于国内使用的DJI SDK移动应用,需要激活该应用并绑定飞机到用户的DJI账号。
如果应用程序没有激活,飞机不绑定(如果需要的话),或遗留版本的SDK(< 4.1)使用,所有相机生活流将被禁用,和飞行将有限区域的100米直径和30米高度,以确保飞机保持在视线之内。
要了解如何实现此功能,请查看本教程中的应用程序激活和飞机绑定。

导入UX SDK Maven依赖项

现在,在Android Studio中创建一个新项目,打开Android Studio,选择File -> new -> new project来创建一个新项目,命名为‘MediaManagerDemo’。输入您想要的公司域名和软件包名称(这里我们使用“com.dji.mediaManagerDemo”),然后按下Next。将最小SDK版本设置为API 19: Android 4.4 (KitKat)用于“手机和平板”,然后按下Next。然后选择“空活动”并按下Next。最后,保持活动名称为“MainActivity”,布局名称为“activity_main”,按“Finish”键创建项目。
请查看开始与UX SDK教程学习

使用UX SDK构建默认布局

现在,在com.dji中创建一个名为“DefaultLayoutActivity”的新空活动类。mediaManagerDemo包。将代码替换为以下代码,记住要按照Android Studio的建议导入相关类:

public class DefaultLayoutActivity extends AppCompatActivity implements View.OnClickListener{

    private Button mMediaManagerBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_default_layout);

        mMediaManagerBtn = (Button)findViewById(R.id.btn_mediaManager);
        mMediaManagerBtn.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_mediaManager: {
                Intent intent = new Intent(this, MainActivity.class);
                startActivity(intent);
                break;
            }
            default:
                break;
        }
    }
}

在上面的代码中,我们创建了一个按钮变量mMediaManagerBtn,并在onCreate()方法中初始化它。此外,实现按钮的onClick()方法并调用startActivity()方法来启动MainActivity。
接下来,继续打开“activity_default_layout”。,并将代码替换为以下代码:




    
    

    

    
    

        

        

        

        

        

        

        

        

        
    

    

        

        

        

        

        

        

        

        

        

    
    

    

        

    

    
    

        

        
    


    


    

    

    

在上面的xml文件中,我们实现了UX SDK的默认布局。要了解更多细节,请查看UX SDK入门教程。
完成以上步骤后,打开color.xml”。,并将内容替换为以下内容:



    #3F51B5
    #303F9F
    #FF4081
    #000000
    #FFFFFF
    #242d34
    #00000000
    #80000000

此外,打开“style.xml”。,并将内容替换为以下内容:

    
    

处理主 MainActivity Layout

完成上述步骤后,让我们打开“activity_main”。,并将内容替换为以下内容:




    

在上面的xml中,我们定义了以下UI元素:

  1. 在左上角创建10个按钮,名称分别为“BACK”、“DELETE”、“RELOAD”、“DOWNLOAD”、“STATUS”、“PLAY”、“RESUME”、“PAUSE”、“STOP”和“MOVETO”。
  2. 在按钮下面创建一个FPVWidget小部件来显示实时摄像机视频流。
  3. 创建一个ImageView来显示下载的照片,并将其覆盖在FPVWidget上。
  4. 在右侧创建一个Recyclerview来显示媒体文件列表的信息。
  5. 最后,用TextView创建一个ScrollView来显示视频播放状态信息。
    以下是MainActivity实现的UI截图:
    大疆文档-Android教程-MediaManager功能实现_第1张图片

初始化MainActivity中的UI元素

完成上述步骤后,让我们打开“MainActivity.java"文件,并将代码替换为以下代码:

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = MainActivity.class.getName();
    private static MainActivity activity;

    private Button mBackBtn, mDeleteBtn, mReloadBtn, mDownloadBtn, mStatusBtn;
    private Button mPlayBtn, mResumeBtn, mPauseBtn, mStopBtn, mMoveToBtn;
    private RecyclerView listView;
    private SlidingDrawer mPushDrawerSd;
    private ImageView mDisplayImageView;
    private TextView mPushTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initUI();
    }

    @Override
    protected void onResume() {
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {    
        super.onDestroy();
    }

    void initUI() {

        //Init RecyclerView
        listView = (RecyclerView) findViewById(R.id.filelistView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(MainActivity.this, OrientationHelper.VERTICAL,false);
        listView.setLayoutManager(layoutManager);

        mPushDrawerSd = (SlidingDrawer)findViewById(R.id.pointing_drawer_sd);
        mPushTv = (TextView)findViewById(R.id.pointing_push_tv);
        mBackBtn = (Button) findViewById(R.id.back_btn);
        mDeleteBtn = (Button) findViewById(R.id.delete_btn);
        mDownloadBtn = (Button) findViewById(R.id.download_btn);
        mReloadBtn = (Button) findViewById(R.id.reload_btn);
        mStatusBtn = (Button) findViewById(R.id.status_btn);
        mPlayBtn = (Button) findViewById(R.id.play_btn);
        mResumeBtn = (Button) findViewById(R.id.resume_btn);
        mPauseBtn = (Button) findViewById(R.id.pause_btn);
        mStopBtn = (Button) findViewById(R.id.stop_btn);
        mMoveToBtn = (Button) findViewById(R.id.moveTo_btn);
        mDisplayImageView = (ImageView) findViewById(R.id.imageView);
        mDisplayImageView.setVisibility(View.VISIBLE);

        mBackBtn.setOnClickListener(this);
        mDeleteBtn.setOnClickListener(this);
        mDownloadBtn.setOnClickListener(this);
        mReloadBtn.setOnClickListener(this);
        mDownloadBtn.setOnClickListener(this);
        mStatusBtn.setOnClickListener(this);
        mPlayBtn.setOnClickListener(this);
        mResumeBtn.setOnClickListener(this);
        mPauseBtn.setOnClickListener(this);
        mStopBtn.setOnClickListener(this);
        mMoveToBtn.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.back_btn: {
                break;
            }
            case R.id.delete_btn:{
                break;
            }
            case R.id.reload_btn: {
                break;
            }
            case R.id.download_btn: {
                break;
            }
            case R.id.status_btn: {
                break;
            }
            case R.id.play_btn: {
                break;
            }
            case R.id.resume_btn: {
                break;
            }
            case R.id.pause_btn: {
                break;
            }
            case R.id.stop_btn: {
                break;
            }
            case R.id.moveTo_btn: {
                break;
            }
            default:
                break;
        }
    }
}

在上述代码中,我们实现了以下功能:

  1. 为Button, clerview, SlidingDrawer, ImageView和TextView创建变量。
  2. 接下来,创建一个initUI()方法来初始化UI元素,并调用按钮的setOnClickListener方法来将MainActivity设置为监听器。然后在onCreate()方法中调用initUI()方法
  3. 最后,为所有按钮实现onClick()方法。

注册应用程序

当您完成以上步骤后,让我们用您在大疆开发者网站上申请的App密钥注册我们的应用程序。如果您不熟悉App Key,请查看Get Started。
此外,关于MApplication、DemoApplication和ConnectionActivity的详细实现,请参阅创建相机应用程序教程和本教程中的示例项目
现在让我们构建并运行该项目,并将其安装到您的Android设备上。如果一切顺利,你应该看到“注册成功”的textView像下面的屏幕.

刷新媒体文件列表

初始化MediaManager

现在,继续进行“MainActivity.java”文件。首先,在MainActivity类的开头添加以下代码:

private FileListAdapter mListAdapter;
private List mediaFileList = new ArrayList();
private MediaManager mMediaManager;
private MediaManager.FileListState currentFileListState = MediaManager.FileListState.UNKNOWN;
private ProgressDialog mLoadingDialog;
private FetchMediaTaskScheduler scheduler;
private int lastClickViewIndex =-1;
private View lastClickView;

在上面的代码中,我们为FileListAdapter、List、MediaManager、FetchMediaTaskScheduler等创建了变量。
接下来,使用以下方法改进onDestroy()方法:

@Override
protected void onDestroy() {
    lastClickView = null;
    DemoApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.SHOOT_PHOTO, new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError mError) {
              if (mError != null){
                  setResultToToast("Set Shoot Photo Mode Failed" + mError.getDescription());
              }
            }
    });

    if (mediaFileList != null) {
        mediaFileList.clear();
    }
    super.onDestroy();
}

在这里,我们实现了以下几点:

  1. 调用Camera的setMode()方法,将Camera模式设置为SHOOT_PHOTO模式,如果在完成回调中出现错误,则显示toast。
  2. 然后调用List的clear()方法来重置mediaFileList。
    在initUI()方法中添加以下代码:
//Init FileListAdapter
mListAdapter = new FileListAdapter();
listView.setAdapter(mListAdapter);

//Init Loading Dialog
mLoadingDialog = new ProgressDialog(MainActivity.this);
mLoadingDialog.setMessage("Please wait");
mLoadingDialog.setCanceledOnTouchOutside(false);
mLoadingDialog.setCancelable(false);

在上面的代码中,我们首先初始化mListAdapter并调用可回收视图的setAdapter()方法来将其设置为listView的适配器。然后初始化mLoadingDialog以显示消息。
此外,实现以下两个方法来显示和隐藏mLoadingDialog对话框:

private void showProgressDialog() {
    runOnUiThread(new Runnable() {
        public void run() {
            if (mLoadingDialog != null) {
                mLoadingDialog.show();
            }
        }
    });
}

private void hideProgressDialog() {
    runOnUiThread(new Runnable() {
        public void run() {
            if (null != mLoadingDialog && mLoadingDialog.isShowing()) {
                mLoadingDialog.dismiss();
            }
        }
    });
}

最后,继续实施以下方法:

private MediaManager.FileListStateListener updateFileListStateListener = new MediaManager.FileListStateListener() {
    @Override
    public void onFileListStateChange(MediaManager.FileListState state) {
        currentFileListState = state;
    }
};

private void initMediaManager() {
    if (DemoApplication.getProductInstance() == null) {
        mediaFileList.clear();
        mListAdapter.notifyDataSetChanged();
        DJILog.e(TAG, "Product disconnected");
        return;
    } else {
        if (null != DemoApplication.getCameraInstance() && DemoApplication.getCameraInstance().isMediaDownloadModeSupported()) {
            mMediaManager = DemoApplication.getCameraInstance().getMediaManager();
        } else if (null != DemoApplication.getCameraInstance()
                && !DemoApplication.getCameraInstance().isMediaDownloadModeSupported()) {
            setResultToToast("Media Download Mode not Supported");
        }
    }
    return;
}

在上述代码中,我们实现了以下功能:

  1. 初始化updateFileListStateListener,并在onFileListStateChange回调方法中更新currentFileListState变量的值。
  2. 接下来,在initMediaManager()方法中,检查产品是否连接,如果没有,则重置mediaFileList并调用FileListAdapter的notifyDataSetChanged()方法来更新listView。
  3. 如果产品已连接,则通过调用Camera的getMediaManager()方法初始化mMediaManager。

获取媒体文件列表

一旦我们完成了上述步骤,我们可以开始从相机SD卡获取媒体文件列表,并在listView上显示它们。
实现如下方法:

private void getFileList() {
    mMediaManager = DemoApplication.getCameraInstance().getMediaManager();
    if (mMediaManager != null) {

        if ((currentFileListState == MediaManager.FileListState.SYNCING) || (currentFileListState == MediaManager.FileListState.DELETING)){
            DJILog.e(TAG, "Media Manager is busy.");
        }else{

            mMediaManager.refreshFileListOfStorageLocation(SettingsDefinitions.StorageLocation.SDCARD, new CommonCallbacks.CompletionCallback() {

                @Override
                public void onResult(DJIError djiError) {
                    if (null == djiError) {
                        hideProgressDialog();

                        //Reset data
                        if (currentFileListState != MediaManager.FileListState.INCOMPLETE) {
                            mediaFileList.clear();
                            lastClickViewIndex = -1;
                            lastClickView = null;
                        }

                        mediaFileList = mMediaManager.getSDCardFileListSnapshot();
                        Collections.sort(mediaFileList, new Comparator() {
                            @Override
                            public int compare(MediaFile lhs, MediaFile rhs) {
                                if (lhs.getTimeCreated() < rhs.getTimeCreated()) {
                                    return 1;
                                } else if (lhs.getTimeCreated() > rhs.getTimeCreated()) {
                                    return -1;
                                }
                                return 0;
                            }
                        });
                        scheduler.resume(new CommonCallbacks.CompletionCallback() {
                            @Override
                            public void onResult(DJIError error) {
                                if (error == null) {
                                    getThumbnails();
                                }
                            }
                        });
                    } else {
                        hideProgressDialog();
                        setResultToToast("Get Media File List Failed:" + djiError.getDescription());
                    }
                }
            });
        }
    }
}

private void getThumbnailByIndex(final int index) {
    FetchMediaTask task = new FetchMediaTask(mediaFileList.get(index), FetchMediaTaskContent.THUMBNAIL, taskCallback);
    scheduler.moveTaskToEnd(task);
}

private void getThumbnails() {
    if (mediaFileList.size() <= 0) {
        setResultToToast("No File info for downloading thumbnails");
        return;
    }
    for (int i = 0; i < mediaFileList.size(); i++) {
        getThumbnailByIndex(i);
    }
}

private FetchMediaTask.Callback taskCallback = new FetchMediaTask.Callback() {
    @Override
    public void onUpdate(MediaFile file, FetchMediaTaskContent option, DJIError error) {
        if (null == error) {
            if (option == FetchMediaTaskContent.PREVIEW) {
                runOnUiThread(new Runnable() {
                    public void run() {
                        mListAdapter.notifyDataSetChanged();
                    }
                });
            }
            if (option == FetchMediaTaskContent.THUMBNAIL) {
                runOnUiThread(new Runnable() {
                    public void run() {
                        mListAdapter.notifyDataSetChanged();
                    }
                });
            }
        } else {
            DJILog.e(TAG, "Fetch Media Task Failed" + error.getDescription());
        }
    }
};

在上面的代码中,我们实现了以下特性:

  1. 在getFileList()方法中,我们获取最新的mMediaManager对象并检查它是否为空。然后检查currentFileListState变量的值。如果状态既不同步也不删除,那么调用MediaManager refreshFileListOfStorageLocation()方法来刷新SD卡上的文件列表。
  2. 在onResult()回调方法中,如果没有错误,那么检查currentFileListState值是否不等于MediaManager.FileListState.INCOMPILE并重新设置mediaFileList列表、lastClickViewIndex和lastClickView变量。
  3. 调用MediaManager的getSDCardFileListSnapshot() 方法来获取当前文件列表并将其存储在mediaFileList变量中。根据创建的时间对mediaFileList中的媒体文件进行排序。
  4. 然后调用FetchMediaTaskScheduler的resume()方法来恢复调度器,并调用onResult()回调方法中的getThumbnails()方法。如果出现错误,调用hideProgressDialog()方法来隐藏进度对话框。
  5. 接下来,创建getThumbnailByIndex()方法来为FetchMediaTaskContent初始化FetchMediaTask任务。然后将任务移动到FetchMediaTaskScheduler的末尾。
  6. 然后,创建getThumbnails()方法来遍历mediaFileList中的文件,并调用getThumbnailByIndex()方法来初始化FetchMediaTask任务。
  7. 最后,初始化taskCallback变量并实现onUpdate()回调方法。如果没有错误,检查选项变量的值。如果该值等于FetchMediaTaskContent.PREVIEW 或者FetchMediaTaskContent.THUMBNAIL,在UI线程中调用FileListAdapter的notifyDataSetChanged()方法来更新listView。
    完成以上步骤后,继续在mMediaManager = DemoApplication.getCameraInstance().getMediaManager()下面;在initMediaManager()方法中插入以下代码
if (null != mMediaManager) {
    mMediaManager.addUpdateFileListStateListener(this.updateFileListStateListener);
    DemoApplication.getCameraInstance().setMode(SettingsDefinitions.CameraMode.MEDIA_DOWNLOAD, new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            if (error == null) {
                DJILog.e(TAG, "Set cameraMode success");
                showProgressDialog();
                getFileList();
            } else {
                setResultToToast("Set cameraMode failed");
            }
        }
    });
    if (mMediaManager.isVideoPlaybackSupported()) {
        DJILog.e(TAG, "Camera support video playback!");
    } else {
        setResultToToast("Camera does not support video playback!");
    }
    scheduler = mMediaManager.getScheduler();
}

在上面的代码中,我们实现了以下特性:

  1. 检查mMediaManager是否不为空,然后调用mMediaManager的addUpdateFileListStateListener()方法来为文件列表状态更新添加监听器。
  2. 调用Camera的setMode()方法并将CameraMode设置为MEDIA_DOWNLOAD。在完成块中,如果没有错误,则调用showProgressDialog()方法来显示获取文件的进度,并调用getFileList()方法来获取媒体文件列表。最后,初始化FetchMediaTaskScheduler来调度fetch媒体文件任务。
    此外,创建一个新的XML布局文件并将其命名为“media_info_item”。在布局文件夹中,用以下代码替换代码:



    

    

    

    

    


在上面的代码中,我们在listView中定义了ItemHolder的布局。在左侧添加一个ImageView,在右侧添加四个textview,如下图所示:
大疆文档-Android教程-MediaManager功能实现_第2张图片最后,继续实现以下方法在listView中显示获取的媒体文件:

private class ItemHolder extends RecyclerView.ViewHolder {
    ImageView thumbnail_img;
    TextView file_name;
    TextView file_type;
    TextView file_size;
    TextView file_time;

    public ItemHolder(View itemView) {
        super(itemView);
        this.thumbnail_img = (ImageView) itemView.findViewById(R.id.filethumbnail);
        this.file_name = (TextView) itemView.findViewById(R.id.filename);
        this.file_type = (TextView) itemView.findViewById(R.id.filetype);
        this.file_size = (TextView) itemView.findViewById(R.id.fileSize);
        this.file_time = (TextView) itemView.findViewById(R.id.filetime);
    }
}

private class FileListAdapter extends RecyclerView.Adapter {
    @Override
    public int getItemCount() {
        if (mediaFileList != null) {
            return mediaFileList.size();
        }
        return 0;
    }

    @Override
    public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.media_info_item, parent, false);
        return new ItemHolder(view);
    }

    @Override
    public void onBindViewHolder(ItemHolder mItemHolder, final int index) {

        final MediaFile mediaFile = mediaFileList.get(index);
        if (mediaFile != null) {
            if (mediaFile.getMediaType() != MediaFile.MediaType.MOV && mediaFile.getMediaType() != MediaFile.MediaType.MP4) {
                mItemHolder.file_time.setVisibility(View.GONE);
            } else {
                mItemHolder.file_time.setVisibility(View.VISIBLE);
                mItemHolder.file_time.setText(mediaFile.getDurationInSeconds() + " s");
            }
            mItemHolder.file_name.setText(mediaFile.getFileName());
            mItemHolder.file_type.setText(mediaFile.getMediaType().name());
            mItemHolder.file_size.setText(mediaFile.getFileSize() + " Bytes");
            mItemHolder.thumbnail_img.setImageBitmap(mediaFile.getThumbnail());
            mItemHolder.thumbnail_img.setOnClickListener(ImgOnClickListener);
            mItemHolder.thumbnail_img.setTag(mediaFile);
            mItemHolder.itemView.setTag(index);

            if (lastClickViewIndex == index) {
                mItemHolder.itemView.setSelected(true);
            } else {
                mItemHolder.itemView.setSelected(false);
            }
            mItemHolder.itemView.setOnClickListener(itemViewOnClickListener);

        }
    }
}

private View.OnClickListener itemViewOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        lastClickViewIndex = (int) (v.getTag());

        if (lastClickView != null && lastClickView != v) {
            lastClickView.setSelected(false);
        }
        v.setSelected(true);
        lastClickView = v;
    }
};

private View.OnClickListener ImgOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        MediaFile selectedMedia = (MediaFile) v.getTag();
        if (selectedMedia != null && mMediaManager != null) {
            addMediaTask(selectedMedia);
        }
    }
};

private void addMediaTask(final MediaFile mediaFile) {
    final FetchMediaTaskScheduler scheduler = mMediaManager.getScheduler();
    final FetchMediaTask task =
            new FetchMediaTask(mediaFile, FetchMediaTaskContent.PREVIEW, new FetchMediaTask.Callback() {
                @Override
                public void onUpdate(final MediaFile mediaFile, FetchMediaTaskContent fetchMediaTaskContent, DJIError error) {
                    if (null == error) {
                        if (mediaFile.getPreview() != null) {
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    final Bitmap previewBitmap = mediaFile.getPreview();
                                    mDisplayImageView.setVisibility(View.VISIBLE);
                                    mDisplayImageView.setImageBitmap(previewBitmap);
                                }
                            });
                        } else {
                            setResultToToast("null bitmap!");
                        }
                    } else {
                        setResultToToast("fetch preview image failed: " + error.getDescription());
                    }
                }
            });

    scheduler.resume(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            if (error == null) {
                scheduler.moveTaskToNext(task);
            } else {
                setResultToToast("resume scheduler failed: " + error.getDescription());
            }
        }
    });
}

上面的代码实现了:

  1. 定义ItemHolder类,它从Recyclerview . viewholder扩展而来。在类内部,定义一个ImageView和四个textview,并通过调用findViewById()方法初始化它们。
  2. 定义FileListAdapter类,继承于Recyclerview . adapter . adapter扩展它。在这个类中,重写getItemCount()方法并返回mediaFileList的大小。
  3. 此外,在onCreateViewHolder方法中,我们使用“media_info_item”在listView中定义ItemHolder的布局。xml”文件。
  4. 在onBindViewHolder方法中,通过使用索引值从mediaFileList获取mediaFile变量。然后使用该媒体文件更新ItemHolder的信息,如file_name、file_type、thumbnail_img等。将mediaFile设置为thumbnail_img的标记,将itemView的标记设置为索引值。我们稍后会用到它们。另外,调用ImageView的setOnClickListener()方法来注册在单击thumbnail_img时要调用的回调。
  5. 此外,如果选择了当前的ItemHolder,则调用其itemView变量的setSelected()方法,并将true传递给它。然后,调用setOnClickListener()方法并传递itemViewOnClickListener变量来注册要在单击itemView时调用的回调。
  6. 接下来,初始化itemViewOnClickListener和ImgOnClickListener变量并覆盖它们的onClick()方法。当项目视图被点击时,更新lastClickViewIndex的值和lastClickView的选择状态。单击thumbnail_img时,通过调用所选thumbnail_img的getTag()方法创建selectedMedia变量,然后检查selectedMedia和mMediaManager变量是否为空。如果没有,则调用addMediaTask()方法并传递selectedMedia变量以获得预览图像。
  7. 最后,实现addMediaTask()方法来获取MediaFile并在mDisplayImageView变量中显示其预览图像。在onUpdate()回调方法中,调用MediaFile的getPreview()方法来获得预览图像。有关实现的更多细节,请在Github上查看本教程的示例代码。
    到目前为止,我们已经完成了对媒体文件列表的刷新,并将它们显示在clerview listView中。此外,您还可以选择特定的媒体文件并预览图像。现在,构建并运行该项目,并将其安装到您的Android设备上。如果一切顺利,你应该会看到类似下面的gif动画(但没有动画)
    大疆文档-Android教程-MediaManager功能实现_第3张图片

下载和编辑媒体文件

完成上述步骤后,继续在MainActivity类的开头添加以下代码:

private ProgressDialog mDownloadDialog;
File destDir = new File(Environment.getExternalStorageDirectory().getPath() + "/MediaManagerDemo/");
private int currentProgress = -1;

在上面的代码中,我们定义了用于媒体文件下载的mDownloadDialog、destDir和currentProgress变量。
在initUI()方法中添加以下代码:

//Init Download Dialog
mDownloadDialog = new ProgressDialog(MainActivity.this);
mDownloadDialog.setTitle("Downloading file");
mDownloadDialog.setIcon(android.R.drawable.ic_dialog_info);
mDownloadDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDownloadDialog.setCanceledOnTouchOutside(false);
mDownloadDialog.setCancelable(true);
mDownloadDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    @Override
    public void onCancel(DialogInterface dialog) {
        if (mMediaManager != null) {
            mMediaManager.exitMediaDownloading();
        }
    }
});

在这里,我们初始化mDownloadDialog并为它配置不同的设置。另外,覆盖OnCancelListener的onCancel()回调方法,并调用MediaManager的exitMediaDownloading()方法,以在按下cancel按钮时停止媒体下载过程。
接下来,实现以下方法来显示和隐藏download mDownloadDialog:

private void ShowDownloadProgressDialog() {
    if (mDownloadDialog != null) {
        runOnUiThread(new Runnable() {
            public void run() {
                mDownloadDialog.incrementProgressBy(-mDownloadDialog.getProgress());
                mDownloadDialog.show();
            }
        });
    }
}

private void HideDownloadProgressDialog() {

    if (null != mDownloadDialog && mDownloadDialog.isShowing()) {
        runOnUiThread(new Runnable() {
            public void run() {
                mDownloadDialog.dismiss();
            }
        });
    }
}

完成以上工作后,继续实现以下两种方法:

private void downloadFileByIndex(final int index){
    if ((mediaFileList.get(index).getMediaType() == MediaFile.MediaType.PANORAMA)
            || (mediaFileList.get(index).getMediaType() == MediaFile.MediaType.SHALLOW_FOCUS)) {
        return;
    }

    mediaFileList.get(index).fetchFileData(destDir, null, new DownloadListener() {
        @Override
        public void onFailure(DJIError error) {
            HideDownloadProgressDialog();
            setResultToToast("Download File Failed" + error.getDescription());
            currentProgress = -1;
        }

        @Override
        public void onProgress(long total, long current) {
        }

        @Override
        public void onRateUpdate(long total, long current, long persize) {
            int tmpProgress = (int) (1.0 * current / total * 100);
            if (tmpProgress != currentProgress) {
                mDownloadDialog.setProgress(tmpProgress);
                currentProgress = tmpProgress;
            }
        }

        @Override
        public void onStart() {
            currentProgress = -1;
            ShowDownloadProgressDialog();
        }

        @Override
        public void onSuccess(String filePath) {
            HideDownloadProgressDialog();
            setResultToToast("Download File Success" + ":" + filePath);
            currentProgress = -1;
        }
    });
}

private void deleteFileByIndex(final int index) {
    ArrayList fileToDelete = new ArrayList();
    if (mediaFileList.size() > index) {
        fileToDelete.add(mediaFileList.get(index));
        mMediaManager.deleteFiles(fileToDelete, new CommonCallbacks.CompletionCallbackWithTwoParam, DJICameraError>() {
            @Override
            public void onSuccess(List x, DJICameraError y) {
                DJILog.e(TAG, "Delete file success");
                runOnUiThread(new Runnable() {
                    public void run() {
                        MediaFile file = mediaFileList.remove(index);

                        //Reset select view
                        lastClickViewIndex = -1;
                        lastClickView = null;

                        //Update recyclerView
                        mListAdapter.notifyItemRemoved(index);
                    }
                });
            }

            @Override
            public void onFailure(DJIError error) {
                setResultToToast("Delete file failed");
            }
        });
    }
}

在上面的代码中,我们实现了以下特性:

  1. 在downloadFileByIndex()方法中,我们首先通过调用MediaFile的getMediaType()方法来检查媒体类型是PANORAMA还是SHALLOW_FOCUS,如果不是,则继续执行。
  2. 调用MediaFile的fetchFileData()方法从SD卡获取媒体文件的全分辨率数据。在onFailure()方法中,调用HideDownloadProgressDialog()方法来隐藏mDownloadDialog,还将currentProgress变量的值重置为-1。
  3. 在onRateUpdate()方法中,我们计算当前的下载进度并将其保存到tmpProgress变量中。然后根据这个变量更新mDownloadDialog和currentProgress。在onStart()方法中,重置currentProgress变量并调用ShowDownloadProgressDialog()方法来显示mDownloadDialog。
  4. 在onSuccess()方法中,调用HideDownloadProgressDialog()方法来隐藏mDownloadDialog并重置currentProgress变量。
  5. 此外,在deleteFileByIndex()方法中,我们首先创建一个ArrayList变量fileToDelete,然后检查mediaFileList的大小是否大于索引。接下来,调用ArrayList的add()方法并添加要删除的选定媒体文件。调用MediaManager()的deleteFiles()方法,并传递fileToDelete变量来从SD卡中删除媒体文件。在完成块中,我们覆盖onSuccess()方法来重置选中的视图,并使用删除的项更新listView。
    最后,实现delete_btn、reload_btn和download_btn按钮的onClick()方法,如下所示
case R.id.delete_btn:{
    deleteFileByIndex(lastClickViewIndex);
    break;
}
case R.id.reload_btn: {
    getFileList();
    break;
}
case R.id.download_btn: {
    downloadFileByIndex(lastClickViewIndex);
    break;
}

有关实现的更多细节,请在Github上查看本教程的示例代码。
现在,我们可以测试到目前为止已经实现的特性。构建并运行该项目,并将其安装到您的Android设备上。如果一切顺利,你应该看到类似于下面的gif动画:
大疆文档-Android教程-MediaManager功能实现_第4张图片# 完成视频回放
现在,继续实现MediaManager的视频回放功能。在onDestroy()方法中,在lastClickView = null下面插入以下代码;

if (mMediaManager != null) {
    mMediaManager.stop(null);
    mMediaManager.removeFileListStateCallback(this.updateFileListStateListener);
    mMediaManager.removeMediaUpdatedVideoPlaybackStateListener(updatedVideoPlaybackStateListener);
    mMediaManager.exitMediaDownloading();
    if (scheduler!=null) {
      scheduler.removeAllTasks();
    }
}

在这里,我们调用MediaManager的stop()方法来停止播放视频。然后调用removeMediaUpdatedVideoPlaybackStateListener()方法来删除侦听器。此外,调用removeFileListStateCallback()方法来删除文件列表状态回调。接下来,调用exitMediaDownloading()方法来退出MEDIA_DOWNLOAD模式并进入SHOOT_PHOTO模式。最后,如果调度器不为空,则调用removeAllTasks()方法来删除所有现有的媒体任务。
接下来,在mMediaManager.addUpdateFileListStateListener(this.updateFileLi)下面插入以下代码:

mMediaManager.addMediaUpdatedVideoPlaybackStateListener(this.updatedVideoPlaybackStateListener);

在上面的代码中,调用addMediaUpdatedVideoPlaybackStateListener()方法,并传递updatedVideoPlaybackStateListener变量来添加用于视频播放状态更新的侦听器。
此外,初始化updatedVideoPlaybackStateListener变量并实现updateStatusTextView()和addLineToSB()方法,如下所示:

private MediaManager.VideoPlaybackStateListener updatedVideoPlaybackStateListener =
        new MediaManager.VideoPlaybackStateListener() {
            @Override
            public void onUpdate(MediaManager.VideoPlaybackState videoPlaybackState) {
                updateStatusTextView(videoPlaybackState);
            }
        };

private void updateStatusTextView(MediaManager.VideoPlaybackState videoPlaybackState) {
    final StringBuffer pushInfo = new StringBuffer();

    addLineToSB(pushInfo, "Video Playback State", null);
    if (videoPlaybackState != null) {
        if (videoPlaybackState.getPlayingMediaFile() != null) {
            addLineToSB(pushInfo, "media index", videoPlaybackState.getPlayingMediaFile().getIndex());
            addLineToSB(pushInfo, "media size", videoPlaybackState.getPlayingMediaFile().getFileSize());
            addLineToSB(pushInfo,
                    "media duration",
                    videoPlaybackState.getPlayingMediaFile().getDurationInSeconds());
            addLineToSB(pushInfo, "media created date", videoPlaybackState.getPlayingMediaFile().getDateCreated());
            addLineToSB(pushInfo,
                    "media orientation",
                    videoPlaybackState.getPlayingMediaFile().getVideoOrientation());
        } else {
            addLineToSB(pushInfo, "media index", "None");
        }
        addLineToSB(pushInfo, "media current position", videoPlaybackState.getPlayingPosition());
        addLineToSB(pushInfo, "media current status", videoPlaybackState.getPlaybackStatus());
        addLineToSB(pushInfo, "media cached percentage", videoPlaybackState.getCachedPercentage());
        addLineToSB(pushInfo, "media cached position", videoPlaybackState.getCachedPosition());
        pushInfo.append("\n");
        setResultToText(pushInfo.toString());
    }
}

private void addLineToSB(StringBuffer sb, String name, Object value) {
    if (sb == null) return;
    sb.
            append((name == null || "".equals(name)) ? "" : name + ": ").
            append(value == null ? "" : value + "").
            append("\n");
}

private void setResultToText(final String string) {
    if (mPushTv == null) {
        setResultToToast("Push info tv has not be init...");
    }
    MainActivity.this.runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mPushTv.setText(string);
        }
    });
}

在这里,我们实现了以下功能:

  1. 当初始化updatedVideoPlaybackStateListener时,我们覆盖onUpdate()方法。然后调用updateStatusTextView()方法,将videoPlaybackState变量作为参数传递,以更新mPushTv TextView中的视频播放状态信息。
  2. 在updateStatusTextView()方法中,我们首先创建pushInfo变量,然后调用addLineToSB()方法来附加视频播放状态信息。然后调用setResultToText()方法向它显示mPushTv TextView。
    此外,继续实施以下方法:
private void playVideo() {
    mDisplayImageView.setVisibility(View.INVISIBLE);
    MediaFile selectedMediaFile = mediaFileList.get(lastClickViewIndex);
    if ((selectedMediaFile.getMediaType() == MediaFile.MediaType.MOV) || (selectedMediaFile.getMediaType() == MediaFile.MediaType.MP4)) {
        mMediaManager.playVideoMediaFile(selectedMediaFile, new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError error) {
                if (null != error) {
                    setResultToToast("Play Video Failed" + error.getDescription());
                } else {
                    DJILog.e(TAG, "Play Video Success");
                }
            }
        });
    }
}

private void moveToPosition(){

    LayoutInflater li = LayoutInflater.from(this);
    View promptsView = li.inflate(R.layout.prompt_input_position, null);
    AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
    alertDialogBuilder.setView(promptsView);
    final EditText userInput = (EditText) promptsView.findViewById(R.id.editTextDialogUserInput);
    alertDialogBuilder.setCancelable(false).setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int id) {
            String ms = userInput.getText().toString();
            mMediaManager.moveToPosition(Integer.parseInt(ms),
                    new CommonCallbacks.CompletionCallback() {
                        @Override
                        public void onResult(DJIError error) {
                            if (null != error) {
                                setResultToToast("Move to video position failed" + error.getDescription());
                            } else {
                                DJILog.e(TAG, "Move to video position successfully.");
                            }
                        }
                    });
        }
    })
            .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                }
            });
    AlertDialog alertDialog = alertDialogBuilder.create();
    alertDialog.show();

}

在这里,我们实现了以下功能:

  1. 在playVideo()方法中,我们首先隐藏mDisplayImageView图像视图。然后初始化selectedMediaFile变量,并检查媒体类型是MOV还是MP4。如果是这样,调用MediaManager的playVideoMediaFile()方法,并传递selectedMediaFile变量作为参数来启动视频播放。在完成块中,覆盖onResult()方法来显示toast消息,以通知用户是否有任何错误。
  2. 在moveToPosition()方法中,我们首先从prompt_input_position的布局创建promptsView。然后初始化alertDialogBuilder并将其视图设置为promptsView。之后,从promptsView初始化userInput变量。调用setCancelable()方法将对话框设置为不可取消。还可以调用setPositiveButton()方法来设置在按下对话框的positive按钮时调用的侦听器。此外,覆盖onClick()方法并调用MediaManager的moveToPosition()方法,以在视频开始的几秒钟内跳到新位置。
    此外,创建一个新的XML布局文件并将其命名为“prompt_input_position”。在布局文件夹中,用以下代码替换代码:



    

    

        

    


在上面的代码中,我们创建了一个TextView和一个EditText,如下所示
在这里插入图片描述最后,我们实现status_btn、play_btn、resume_btn、pause_btn、stop_btn、moveTo_btn的onClick()方法,如下图所示:

case R.id.status_btn: {
    if (mPushDrawerSd.isOpened()) {
        mPushDrawerSd.animateClose();
    } else {
        mPushDrawerSd.animateOpen();
    }
    break;
}
case R.id.play_btn: {
    playVideo();
    break;
}
case R.id.resume_btn: {
    mMediaManager.resume(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            if (null != error) {
                setResultToToast("Resume Video Failed" + error.getDescription());
            } else {
                DJILog.e(TAG, "Resume Video Success");
            }
        }
    });
    break;
}
case R.id.pause_btn: {
    mMediaManager.pause(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            if (null != error) {
                setResultToToast("Pause Video Failed" + error.getDescription());
            } else {
                DJILog.e(TAG, "Pause Video Success");
            }
        }
    });
    break;
}
case R.id.stop_btn: {
    mMediaManager.stop(new CommonCallbacks.CompletionCallback() {
        @Override
        public void onResult(DJIError error) {
            if (null != error) {
                setResultToToast("Stop Video Failed" + error.getDescription());
            } else {
                DJILog.e(TAG, "Stop Video Success");
            }
        }
    });
    break;
}
case R.id.moveTo_btn: {
    moveToPosition();
    break;
}

在上面的代码中,我们实现了以下特性:

  1. 在status_btn按钮的情况下,调用mPushDrawerSd变量的isOpened()方法来检查它是否打开,如果打开,则调用它的animateClose()方法来用动画关闭抽屉。否则,调用它的animateOpen()方法,用动画打开折叠项。
  2. 对于play_btn按钮,调用playVideo()方法来启动视频播放。在resume_btn按钮的情况下,调用MediaManager的resume()方法来恢复暂停的视频并覆盖onResult()方法,并显示toast消息来通知用户是否有任何错误。
  3. 在pause_btn按钮的情况下,调用MediaManager的pause()方法来暂停播放视频并覆盖onResult()方法,并显示toast消息来通知用户是否有任何错误。
  4. 在stop_btn按钮的情况下,调用MediaManager的stop()方法来停止播放视频并覆盖onResult()方法,并显示toast消息来通知用户是否有任何错误。
  5. 最后,对于moveTo_btn按钮,调用moveToPosition()方法,在视频开始的几秒钟内跳到新位置。
    在本教程中,我们已经经历了很长一段时间,现在让我们构建并运行这个项目,将演示应用程序连接到您的Mavic Pro(请查看运行应用程序以获得更多详细信息),并检查到目前为止我们实现的所有功能。如果一切顺利,你应该会看到类似下面这样的gif动画
    大疆文档-Android教程-MediaManager功能实现_第5张图片

总结

在本教程中,您已经学习了如何使用MediaManager预览照片、播放视频、下载或删除文件,还学习了如何获取和显示视频播放状态信息。通过使用MediaManager,用户可以获得所有多媒体文件的元数据,并可以访问每个单独的多媒体文件。希望你喜欢!

你可能感兴趣的:(android)