Android开发——相册的访问、上传以及服务端对接

2023-10-26


    一般Android开发需要涉及到本地相册的上传以及文件下载到相册。

1.访问相册并上传到服务器

// 系统默认的图片选择程序
    private void OpenFile(View view) {
        Intent galleryIntent = new Intent(Intent.ACTION_PICK); 
        galleryIntent.setType("image/*");
        startActivityForResult(galleryIntent, REQUEST_GALLERY);
    }
    //完成图片的选择
      @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        Uri uri = data.getData();
        //这里的REQUEST_GALLERY 是一个常量,我也没深究过
        //private static final int REQUEST_GALLERY = 100;
        saveUriToFile(uri, REQUEST_GALLERY);
    }
    private void saveUriToFile(Uri uri, int from) {
        Bitmap bitmap = null;
        if (uri != null) {
            try {
            //将本地已经选择的图片利用bitmap渲染出来
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2; // 图片宽高都为原来的二分之一,即图片为原来的四分之一
                bitmap = BitmapFactory.decodeStream(getContext().getContentResolver().openInputStream(uri), null, options);
                upload_image.setImageBitmap(bitmap);
                //处理文件上传
                String filePath = FileUtils.getRealFilePath(getContext(), uri);
                file_add_name.setText(filePath.substring(filePath.lastIndexOf("/") + 1));
                sendRequest(filePath);
            } catch (Exception e) {
                Toast.makeText(getActivity(), "上传文件失败~", Toast.LENGTH_SHORT).show();
            }
        }
    }

    给出我这里使用到的FileUtils工具类(直接使用大佬提供的源代码),目的是获取到图片的绝对存储路径。

public class FileUtils {

    /**
     * 通过Uri获取图片的路径以及文件名
     *
     * @param context
     * @param uri
     * @return
     */
    public static String getRealFilePath(final Context context, final Uri uri) {
        if (null == uri) return null;
        final String scheme = uri.getScheme();
        String data = null;
        if (scheme == null)
            data = uri.getPath();
        else if (ContentResolver.SCHEME_FILE.equals(scheme)) {
            data = uri.getPath();
        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
            Cursor cursor = context.getContentResolver().query(uri, new String[]{MediaStore.Images.ImageColumns.DATA}, null, null, null);
            if (null != cursor) {
                if (cursor.moveToFirst()) {
                    int index = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
                    if (index > -1) {
                        data = cursor.getString(index);
                    }
                }
                cursor.close();
            }
        }
        return data;
    }
}

给出图片上传函数:

//根据获取到的图片路径上传文件流到服务端
private void sendRequest(String filePath) {
        File file = new File(filePath);
        //在前端实现了文件名称的唯一化,其实更建议在后端实现
        String newFileName = UUID.randomUUID().toString().replace("-", "") + ".jpg";//这里可能写的不太好,锁定了文件类型
        Retrofit retrofit = new Retrofit.Builder().baseUrl(Config.serverUrl).build();
        UploadService uploadService = retrofit.create(UploadService.class);
        MediaType mediaType = MediaType.parse("multipart/form-data");
        RequestBody fileBody = RequestBody.create(mediaType, file);
        MultipartBody.Part part = MultipartBody.Part.createFormData("file", newFileName, fileBody);
        Call<ResponseBody> call = uploadService.upload(part);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                if (response.body() != null) {
                    try {
                        String result = response.body().string();
                        Log.d("nightowl", "onResponse(file): " + result);
                        JsonObject returnData = new JsonParser().parse(result).getAsJsonObject();
                        if (!returnData.get("code").toString().equals("200")) {
                            Toast.makeText(getContext(), "服务端错误~", Toast.LENGTH_SHORT).show();
                        } else {
                            uploadFileUrl = returnData.get("data").toString();//记录上传返回之后的图片路径
                            Toast.makeText(getContext(), "文件上传成功!!", Toast.LENGTH_SHORT).show();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    Log.d("nightowl", "onResponse -- > " + "返回数据为空");
                }

            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.d("nightowl", "onFailure -- > " + t.toString());
            }
        });
    }

2.下载网络图片到相册

    由于我学的实在是不够深入,因此这里总结分享一种可行性方法,导入大佬开源的Download工具类(能够显示下载进度):

public class Download {

    private String fileSavePath = "";//保存文件的本地路径
    private String fileDownLoad_path = "";//下载的URL
    private String fileName = "";//下载的文件名字
    private boolean mIsCancel = false;
    private int mProgress;
    private ProgressBar mProgressBar;
    private TextView text;
    private Dialog mDownloadDialog;
    private final Context context;

    private static final int DOWNLOADING = 1;
    private static final int DOWNLOAD_FINISH = 2;

    @SuppressLint("HandlerLeak")
    private final Handler mUpdateProgressHandler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DOWNLOADING:
                    // 设置进度条
                    mProgressBar.setProgress(mProgress);
                    text.setText(String.valueOf(mProgress));
                    break;
                case DOWNLOAD_FINISH:
                    // 隐藏当前下载对话框
                    mDownloadDialog.dismiss();
            }
        }
    };

    /**
     * 下载初始化
     *
     * @param context           上下文
     * @param fileDownLoad_path 下载的URL
     * @param fileName          下载的文件名字
     * @param fileSavePath      保存文件的本地路径
     */
    public Download(Context context, String fileDownLoad_path, String fileSavePath, String fileName) {
        this.context = context;
        this.fileDownLoad_path = fileDownLoad_path;
        this.fileName = fileName;
        this.fileSavePath = Environment.getExternalStorageDirectory() + "/" + fileSavePath;
        showDownloadDialog();
    }

    /**
     * 显示正在下载的对话框
     */
    protected void showDownloadDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("下载中");
        View view = LayoutInflater.from(context).inflate(R.layout.dialog_progress, null);
        mProgressBar = (ProgressBar) view.findViewById(R.id.id_progress);
        text = view.findViewById(R.id.id_text);
        builder.setView(view);

        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 隐藏当前对话框
                dialog.dismiss();
                // 设置下载状态为取消
                mIsCancel = true;
            }
        });

        mDownloadDialog = builder.create();
        mDownloadDialog.show();
        downloadFile();
    }

    public static ContentValues getImageContentValues(Context paramContext, File paramFile, long paramLong) {
        ContentValues localContentValues = new ContentValues();
        localContentValues.put("title", paramFile.getName());
        localContentValues.put("_display_name", paramFile.getName());
        localContentValues.put("mime_type", "image/jpeg");
        localContentValues.put("datetaken", Long.valueOf(paramLong));
        localContentValues.put("date_modified", Long.valueOf(paramLong));
        localContentValues.put("date_added", Long.valueOf(paramLong));
        localContentValues.put("orientation", Integer.valueOf(0));
        localContentValues.put("_data", paramFile.getAbsolutePath());
        localContentValues.put("_size", Long.valueOf(paramFile.length()));
        return localContentValues;
    }

    /**
     * 下载文件
     */
    private void downloadFile() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                        File dir = new File(fileSavePath);
                        if (!dir.exists()) {
                            dir.mkdirs();
                        }
                        HttpURLConnection conn = (HttpURLConnection) new URL(fileDownLoad_path).openConnection();
                        conn.connect();
                        InputStream is = conn.getInputStream();
                        int length = conn.getContentLength();

                        File imageFile = new File(fileSavePath, fileName);
                        FileOutputStream fos = new FileOutputStream(imageFile);

                        int count = 0;
                        byte[] buffer = new byte[1024];
                        while (!mIsCancel) {
                            int numread = is.read(buffer);
                            count += numread;
                            // 计算进度条当前位置
                            mProgress = (int) (((float) count / length) * 100);
                            // 更新进度条
                            mUpdateProgressHandler.sendEmptyMessage(DOWNLOADING);

                            // 下载完成
                            if (numread < 0) {
                                mUpdateProgressHandler.sendEmptyMessage(DOWNLOAD_FINISH);
                                break;
                            }
                            fos.write(buffer, 0, numread);
                        }

                        //将文件写入相册
                        ContentResolver localContentResolver = context.getContentResolver();
                        ContentValues localContentValues = getImageContentValues(context, imageFile, System.currentTimeMillis());
                        localContentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, localContentValues);

                        Intent localIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
                        final Uri localUri = Uri.fromFile(imageFile);
                        localIntent.setData(localUri);
                        context.sendBroadcast(localIntent);
                        Log.d("nightowl:", "run: " + "文件下载完成," + fileSavePath + fileName);
                        fos.close();
                        is.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

具体使用如下:

public void downloadFile(String targetUrl) {
    String suffixName = targetUrl.substring(targetUrl.lastIndexOf("."));
    String dirName = "campus_notice/";//指定文件的存储目录
    String fileName = UUID.randomUUID().toString().replace("-", "") + suffixName;
    Download download = new Download(this, targetUrl, dirName, fileName);
    //这个DetailsActivity是我自己的下载页面,可以使用getActivity()代替并通用化
    //这波属于预先展示下载完成,如果为了友好,可以将download设计成内部类,下载完成之后提示,当降低了重用性,也可以进一步探索异步函数的使用,在download设计一个需要被继承的方法等等。
    Toast.makeText(DetailsActivity.this, "已存储到相册!", Toast.LENGTH_SHORT).show();
}

3.这里顺便分享一手后端的对接方法

    代码是基于Springboot的,其实就是将前端传过来的文件写入服务器中。

@CrossOrigin
@EnableAsync
@RestController
public class FileController {
    private static String storePath =System.getProperty("user.dir")+"/static/";
    private static final String serverUrl = "https://android.nightowl.top/static/";
    @RequestMapping(value = "/upload", method = {RequestMethod.POST})
    public ResultData fileUpload(@RequestParam(value = "file", required = true) MultipartFile file) {
        if (file.isEmpty()) {
            return ResultData.error("上传图片不存在~");
        } else {
            String fileName = file.getOriginalFilename();  // 文件名
            String suffixName = fileName.substring(fileName.lastIndexOf("."));//只支持JPG、JPEG、PNG
            // 验证上传的文件是否图片
            if (!".jpg".equalsIgnoreCase(suffixName)
                    && !".jpeg".equalsIgnoreCase(suffixName)
                    && !".png".equalsIgnoreCase(suffixName)) {
                return ResultData.error("只支持JPG、JPEG、PNG三种类型~");
            }
            File dest = new File(storePath + fileName);
            if (fileName.startsWith("/") && !dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            try {
                file.transferTo(dest);
                System.out.println("输出文件路径:" + serverUrl + fileName);
                return ResultData.success("上传成功~", 0, serverUrl + fileName);
            } catch (IOException e) {
                e.printStackTrace();
                return ResultData.error("图片上传失败~");
            }
        }
    }
}

4.生产环境资源配置

    注意,这里在生产环境部署的时候如需要加以调整(因为项目被打成jar包了,所以无法再访问对应路径,需要重新规定静态资源目录),需要额外做一些静态资源配置application.yaml,否则只能在测试环境中完成文件读写,具体的配置方法如下(主要是配置静态资源访问文件):

server:
  servlet:
    context-path: /
  port: 8000
  #前后只做位置参考,因为yaml配置利用的是缩进
spring:
  application:
    name: spring-android
  mvc:
  #主要是这里
    static-path-pattern: /static/**
  #前后只做位置参考,因为yaml配置利用的是缩进
  #mysql数据库
  #...

    最后请加上WebSecurityConfig类确保资源注册类能够生效。

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebSecurityConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/","file:static/");
    }
}

给出宝塔面板部署的效果(主要是为了体现这里的相对资源路径static):
在这里插入图片描述

5.后端项目打包

    因为我主要是负责前端开发的,对于springboot框架知之甚少,因此只负责了项目部署等少量工作,部署的话需要首先将项目打包,打包的maven配置如下(本质上是使用了maven-surefire-plugin打包工具):

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.2</version>
                <!--忽略测试-->
                <configuration>
                    <skipTests>true</skipTests>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    最后建议将打包时候使用的JavaJDK版本修改成1.8(否则容易因版本不一样导致不能运行项目):

<properties>
    <java.version>8</java.version>
</properties>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android开发——相册的访问、上传以及服务端对接 的相关文章

  • 如何在 Android 中将一种跨度类型更改为另一种跨度类型?

    我想将一种类型的所有跨度放入一个CharSequence并将它们转换为不同的类型 例如 将所有粗体跨度转换为下划线跨度 我该怎么做呢 这是我今天遇到的问题 既然我现在已经解决了 我在这里添加一个问答对 我的答案如下 如何将跨度从一种类型更改
  • 在 gridLayout 中从右向左放置项目

    我有一个GridLayout在我的其中一个布局中 我想从右到左放置项目 这意味着我希望将单元格 1 1 放在布局的右上角 我已经测试了这些代码GridView so far 1 android gravity right and andro
  • 无法跳过某项活动

    我的 Android 应用程序有一个登录屏幕 用户登录到他的仪表板 但我不希望用户每次关闭应用程序并启动它时都登录 除非他们从仪表板注销 因此 我创建了一个类来检查用户是否登录 检查登录 java public class CheckLog
  • 尽管 CRC 错误,仍强制 gzip 解压缩

    我认为有办法做到这一点 但我不确定如何做 基本上 我正在编写一个压缩程序 当我尝试解压缩压缩数据时 该程序导致了 crc 错误 通常 这意味着解压缩器实际上将我的数据识别为正确的格式并将其解压缩 但是当它将结果与 CRC 指示的预期长度进行
  • Android:如何按下软键盘上方的按钮

    我有一个 保存 按钮 我想将其与软键盘一起按下 因此 当用户单击布局中的 EditText 时 按钮必须保持在键盘上方 现在该按钮隐藏在键盘下方 你怎么做到这一点 提前致谢 您需要将键盘的输入模式设置为adjustResize 您可以通过将
  • 在 Android 中读取蓝牙 RSSI 以获取 BLE 邻近配置文件

    我目前正在为 Android 开发低功耗蓝牙接近配置文件 并且偶然发现了有关 RSSI 的问题 为了使邻近配置文件起作用 我必须每隔很短的时间就通过已连接的设备接收 RSSI 数据 正如我所做的一些研究 我了解到在设备发现过程中可以获得蓝牙
  • Jsoup遍历DOM树时节点哈希码冲突

    我正在使用 java jsoup 构建 HTML DOM 树 其中Node hashCode 用来 但我发现在遍历DOM树时存在很多哈希码冲突 使用以下代码 doc traverse new NodeVisitor Override pub
  • 设置正则表达式中的最小和最大字符

    我写了一个正则表达式 http en wikipedia org wiki Regular expression匹配任意数量的字母 字母之间有任意数量的单个空格 我希望该正则表达式也强制执行最小和最大字符数 但我不确定如何做到这一点 或者是
  • Java 中变量可能未初始化错误

    import java util Random public class dice private int times private int roll private int side Random roller new Random p
  • Android 堆栈溢出错误

    以下是我的堆栈跟踪 我浏览了它 但它只显示了一堆视图 坦率地说 我不太确定 stackoverflow 错误到底是什么 我读到了一些其他问题 有些人通过迭代解决了他们的问题 同样 不知道这些是什么 对于应用程序的基本布局 这是来自崩溃时 T
  • 为什么以下带有循环泛型的代码无法编译?

    以下是我的代码 class A
  • Android:如果我将serialVersionUID 添加到旧的可序列化对象中,会发生什么?

    如果您采用从未显式指定过serialVersionUID的旧可序列化对象 并将serialVersionUID添加到该对象 会发生什么情况 在我看来 下次最终用户更新应用程序时 它会尝试反序列化光盘中的数据 发现serialVersionU
  • 检查列表视图中的复选框也会检查其他随机复选框

    每当我在列表视图中选中一个复选框时 其他随机复选框也会被选中 这可能是由于列表视图回收项目所致 我也尝试过设置android focusable false 按照某些地方的建议 添加到我的布局中的复选框 但是当选中其复选框时 仍然不会调用
  • 无法解析类型 android.support.v4.app.Fragment。它是从所需的 .class 文件间接引用的,Facebook [重复]

    这个问题在这里已经有答案了 我想在 Facebook 中发布照片和文本 为此我使用了来自 Facebook 参考站点的以下代码 https developers facebook com docs android link to your
  • 如何将 java.util.Optional 与 REST API 一起使用?

    我有一堂课看起来像 public class ActiveDirectorySetup implements Serializable private ActiveDirectoryDataSource activeDirectoryDat
  • JSF:如何通过 bean 验证来验证字段并返回错误消息?

    我有一个联系表单 并且有一些通过 Bean 验证进行验证的字段 提交后如何返回 Bean 验证错误消息 例如
  • 在不同的任务中启动一个新的 Android Activity

    这是一个有点复杂的故事 我有一个Activity A Activity A使用意图打开浏览器来进行一些身份验证 完成此操作后 网页将重定向到 URL Activity B使用意图过滤器将其设置为可浏览 并且 URL 使得浏览器启动Activ
  • 线程安全框架

    以下类不是线程安全的 如证明以下代码不是线程安全的 https stackoverflow com questions 2410499 proving the following code not thread safe 是否有一个框架可以
  • 使用 ADB 或 java 代码更改默认的 Android 键盘

    我正在构建一个使用特定键盘的自定义应用程序 因此当用户运行该应用程序时 默认键盘应更改为我的特定键盘 名称为黑客键盘 我如何使用java代码或从java代码调用adb命令来做到这一点 我的设备已获得 root 权限 这又是特定的应用程序 而
  • 指针问题! (安卓)

    我在 onTouch 方法中遇到多个指针的问题 所有指针都与一个布尔值相关联 如果向下则为 true 如果向上则为 false 非常重要的是 如果一个指针从 true 变为 false 它不会影响其他布尔值 我遇到的问题是 例如 当指针 1

随机推荐

  • 学习笔记-Matlab算法篇-动态规划

    动态规划 01介绍 介绍 动态规划 dynamic programming 是运筹学的一个分支 是求解决策过程 decision process 最优化的数学方法 动态规划是求解某类问题的一种方法 是考察问题的一种途径 而不是一种特殊算法
  • weex实践初探

    weex是阿里2016年开源的项目 号称通过撰写HTML CSS JavaScript来开发原生android ios的UI界面 并且接近原生的性能体验 写一次 多端编译 一直是无线移动追求的目标 既然阿里牛皮吹得这么大 本人也非常迫切体验
  • EncodedResource类解读

    EncodedResource类解读 EncodedResource介绍 EncodedResource是spring中Resource编码相关的封装类 EncodedResource里面封装了一个Resource成员属性 其实主要功能就是
  • MySQL索引类型与索引原理

    1 索引类型 索引可以提升查询速度 会影响where查询 以及order by排序 MySQL索引类型如下 从索引存储结构划分 B Tree索引 Hash索引 FULLTEXT全文索引 R Tree索引 从应用层次划分 普通索引 唯一索引
  • Uncaught ReferenceError: xxx is not defined at HTMLInputElement.onclick已解决

    触发标签的onclick事件报错如下 Uncaught ReferenceError http is not defined at HTMLInputElement onclick list do pageType initialize 2
  • Flutter1.0入门基础

    Flutter1 0入门基础 注 原课程视频是基于Flutter1的 目标 开发入门 工具 环境搭建 入门必备 开发技巧 导航框架 常用功能 开发流程 网络 数据存储 列表 Flutter与Native混编 工程封装 模块开发 AI结合 项
  • java初始化map的四种方式

    第一种 最常见的方式 新建Map对象 public class Demo private static final Map
  • extern指针和数组的用法

    对extern我们先来一段直白的告白 extern是计算机语言中的一个函数 可置于变量或者函数前 以表示变量或者函数的定义在别的文件中 提示编译器遇到此变量或函数时 在其它模块中寻找其定义 另外 extern也可用来进行链接指定 来自百度百
  • 毕业设计:电子/通信/物联网/计算机专业选题目参考(嵌入式linux/单片机STM32/web/图像)

    本文推荐的毕业设计题目涉及以下技术 嵌入式Linux 单片机STM32 Opencv Qt Web 百度AI YOLO 目标检测 深度学习 等 适用于 电子信息 通信 物联网 计算机 等专业的毕业设计题目 支持服务 题目定制 选题答疑 代做
  • Android自定义View实现图片裁剪功能(本地选择图片进行裁剪)

    使用安卓自带的裁剪工具 发现有版本兼容问题 而且图片模糊问题也不好解决 于是自己动手绘制一个裁剪工具 先看效果 最终效果 自定义截图 实现思路 打开本地相册 获得图片Uri Uri转为Bitmap 用自定义View绘制可拖动选框 获得用户的
  • PhotonServer游戏服务器学习一

    步骤一 1 PhotonServe的官方网站https www photonengine com zh CN Photon 进入到官网后点击SDKs 选择Server 工程 点击SeverSDK ON PREMISES进行下载 需要注册一个
  • JDBC连接Access数据库的几种方式介绍

    接下来总结一下常用的几种连接方式 例如有如下的Access数据库student 表basic 以及6条记录 现在通过几种方式在Jsp中将他们的数据显示出来 如图所示 对于几种连接Access数据库的方式 基本上都是基于JDBC ODBC方式
  • 关于pytorch、torch_geometric安装 22.12.25

    系统坏了 重装系统 一开始以为电脑只能装cuda9 2版本一下 装了之后 显卡驱动自动更新了 然后显示可以装CUDA11 7版本一下 cuda 9 2 torch geometric 1 61 pytorch 1 6 0 python3 8
  • Linux 根目录爆掉,怎么办?

    极力推荐文章 欢迎收藏Android 干货分享 本篇文章主要介绍 Linux 开发中的部分知识点 通过阅读本篇文章 您将收获以下内容 一 cannot create temp file for here document No space
  • WebStorm 2023 下载、安装、汉化

    1 下载WebStorm 1 1 官网下载地址 https www jetbrains com webstorm https www jetbrains com webstorm download download thanks html
  • 问题解决:DatabaseMetaData.getTables()方法,返回了所有库中的表

    一 问题描述 DatabaseMetaData getTables 方法常常用来获取数据库中的所有表信息 但我想要获取我的本地数据库db test中的表信息 出现了错误 try Connection conn DBManager getCo
  • BigDecimal保留小数

    Java中BigDecimal取整方法 BigDecimal bd new BigDecimal 12 1 long l bd setScale 0 BigDecimal ROUND UP longValue 向上取整 long l bd
  • 【Docker存储】Docker容器的数据持久化

    Docker存储 Docker容器的数据持久化 一 Docker数据持久化方式 二 本次实践介绍 2 1 本次实践简介 2 2 本次实践环境介绍 三 容器的挂载目录 3 1 创建测试容器web01 3 2 查看容器信息 3 3 编辑测试文件
  • 单片机C语言中while(1)的问题

    单片机C语言的主程序 通常要用一个while 1 语句来让程序进入一个无限循环 目的是为了让程序一直保持在我们需要运行的情况下 虽然这种做法毋庸置疑 在网上还是有不少朋友有疑问 如果程序不加while 1 会出现什么情况 对于这种好学精神
  • Android开发——相册的访问、上传以及服务端对接

    相册的访问与图片保存 1 访问相册并上传到服务器 2 下载网络图片到相册 3 这里顺便分享一手后端的对接方法 4 生产环境资源配置 5 后端项目打包 一般Android开发需要涉及到本地相册的上传以及文件下载到相册 1 访问相册并上传到服务