Android Studio 下载视频到本地

最近在研究视频下载到本地的问题,像爱奇艺,腾讯视频,迅雷看看等等一些视频播放器,如果在一个播放器里面视频下载到一半用户退出App之后,再次登录从头开始,那么就太可悲了,所以在做视频音频类的项目时,要实现的一个功能就是断点续传,就是将用户下载的视频或者音频等以字节流的形式存入数据库,下次用户再次下载时,将继续上次数据库的接着下载,这样用户体验就会很好,也大大节省了成本.

好了废话不多说,开始今天的正题.

一、先上效果图

二、使用GreenDao我们需要导入依赖

1.以下在项目gradle依赖中添加

compile 'org.greenrobot:greendao:3.2.2'//依赖 在最后一行插入
apply plugin: 'org.greenrobot.greendao' //greenDao在第二行插入
greendao {//在依赖导入汇总添加一个自动添加数据库表名的配置依赖
 schemaVersion 1 //数据库版本号
 daoPackage 'com.example.greendaodemo.database' //设置时生成代码的目录
 targetGenDir 'src/main/java' //设置DaoMaster、DaoSession、Dao目录
}

2.以下在工程gradle依赖中添加

classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'

3.既然我们要联网下载,读写权限肯定不能忘记了

<uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" /> 

三、当然还要有实体类写入实体类后,build下make project一下,让他自动生成GreenDao的三个类

import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Generated;
/**
 * author:Created by ZhangPengFei.
 * Email: 1271396448@qq.com
 * data: 2018/1/18
 */
@Entity
public class User {
 @Id
 private Long id;
 private Integer thread_id;
 private Integer start_pos;
 private Integer end_pos;
 private Integer compelete_size;
 private String url;
 @Generated(hash = 2041931179)
 public User(Long id, Integer thread_id, Integer start_pos, Integer end_pos,
   Integer compelete_size, String url) {
  this.id = id;
  this.thread_id = thread_id;
  this.start_pos = start_pos;
  this.end_pos = end_pos;
  this.compelete_size = compelete_size;
  this.url = url;
 }
 @Generated(hash = 586692638)
 public User() {
 }
 public Long getId() {
  return this.id;
 }
 public void setId(Long id) {
  this.id = id;
 }
 public Integer getThread_id() {
  return this.thread_id;
 }
 public void setThread_id(Integer thread_id) {
  this.thread_id = thread_id;
 }
 public Integer getStart_pos() {
  return this.start_pos;
 }
 public void setStart_pos(Integer start_pos) {
  this.start_pos = start_pos;
 }
 public Integer getEnd_pos() {
  return this.end_pos;
 }
 public void setEnd_pos(Integer end_pos) {
  this.end_pos = end_pos;
 }
 public Integer getCompelete_size() {
  return this.compelete_size;
 }
 public void setCompelete_size(Integer compelete_size) {
  this.compelete_size = compelete_size;
 }
 public String getUrl() {
  return this.url;
 }
 public void setUrl(String url) {
  this.url = url;
 }
} 

四、本人使用了单例模式,所以在全局配置里初始化了数据库的操作

import android.app.Application;
import com.example.greendaodemo.database.DaoMaster;
import com.example.greendaodemo.database.DaoSession;
import com.example.greendaodemo.database.UserDao;
/**
 * author:Created by ZhangPengFei.
 * Email: 1271396448@qq.com
 * data: 2018/1/18
 */
public class App extends Application {
 public static UserDao userDao;
 @Override
 public void onCreate() {
  super.onCreate();
  DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "zpf.db", null);
  DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb());
  DaoSession daoSession = daoMaster.newSession();
  userDao = daoSession.getUserDao();
 }
} 

五、因为我们是多线程,所以写一个保存每个线程下载信息的类

public class DownLoadInfo {
 /**
  * 保存每个下载线程下载信息类
  *
  */
 private int threadId;// 下载器id
 private int startPos;// 开始点
 private int endPos;// 结束点
 private int compeleteSize;// 完成度
 private String url;// 下载文件的URL地址
 public DownLoadInfo(int threadId, int startPos, int endPos,
      int compeleteSize, String url) {
  this.threadId = threadId;
  this.startPos = startPos;
  this.endPos = endPos;
  this.compeleteSize = compeleteSize;
  this.url = url;
 }
 public DownLoadInfo() {
 }
 public String getUrl() {
  return url;
 }
 public void setUrl(String url) {
  this.url = url;
 }
 public int getThreadId() {
  return threadId;
 }
 public void setThreadId(int threadId) {
  this.threadId = threadId;
 }
 public int getStartPos() {
  return startPos;
 }
 public void setStartPos(int startPos) {
  this.startPos = startPos;
 }
 public int getEndPos() {
  return endPos;
 }
 public void setEndPos(int endPos) {
  this.endPos = endPos;
 }
 public int getCompeleteSize() {
  return compeleteSize;
 }
 public void setCompeleteSize(int compeleteSize) {
  this.compeleteSize = compeleteSize;
 }
 @Override
 public String toString() {
  return "DownloadInfo [threadId=" + threadId + ", startPos=" + startPos
    + ", endPos=" + endPos + ", compeleteSize=" + compeleteSize
    + "]";
 }
} 

六、写一个用来记录的类,修改,添加和下载完清空数据库的操作

import android.util.Log;
import com.example.greendaodemo.database.UserDao;
import java.util.ArrayList;
import java.util.List;
import static com.bwie.mtd.App.userDao;
/**
 * author:Created by ZhangPengFei.
 * Email: 1271396448@qq.com
 * data: 2018/1/18
 */
public class DownLoadSqlTool {
 /**
  * 创建下载的具体信息
  */
 public void insertInfos(List<DownLoadInfo> infos) {
  for (DownLoadInfo info : infos) {
   User user = new User(null, info.getThreadId(), info.getStartPos(), info.getEndPos(), info.getCompeleteSize(), info.getUrl());
   userDao.insert(user);
  }
 }
 /**
  * 得到下载具体信息
  */
 public List<DownLoadInfo> getInfos(String urlstr) {
  List<DownLoadInfo> list = new ArrayList<DownLoadInfo>();
  List<User> list1 = userDao.queryBuilder().where(UserDao.Properties.Url.eq(urlstr)).build().list();
  for (User user : list1) {
   DownLoadInfo infoss = new DownLoadInfo(
     user.getThread_id(), user.getStart_pos(), user.getEnd_pos(),
     user.getCompelete_size(), user.getUrl());
   Log.d("main-----", infoss.toString());
   list.add(infoss);
  }
  return list;
 }
 /**
  * 更新数据库中的下载信息
  */
 public void updataInfos(int threadId, int compeleteSize, String urlstr) {
  User user = userDao.queryBuilder()
    .where(UserDao.Properties.Thread_id.eq(threadId), UserDao.Properties.Url.eq(urlstr)).build().unique();
  user.setCompelete_size(compeleteSize);
  userDao.update(user);
 }
 /**
  * 下载完成后删除数据库中的数据
  */
 public void delete(String url) {
  userDao.deleteAll();
 }
} 

七、多线程下载的实践类

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
 * author:Created by ZhangPengFei.
 * Email: 1271396448@qq.com
 * data: 2018/1/18
 */
public class DownloadHttpTool {
 /**
  * 利用Http协议进行多线程下载具体实践类
  */
 private static final String TAG = DownloadHttpTool.class.getSimpleName();
 private int threadCount;//线程数量
 private String urlstr;//URL地址
 private Context mContext;
 private Handler mHandler;
 private List<DownLoadInfo> downloadInfos;//保存下载信息的类
 private String localPath;//目录
 private String fileName;//文件名
 private int fileSize;
 private DownLoadSqlTool sqlTool;//文件信息保存的数据库操作类
 private enum Download_State {
  Downloading, Pause, Ready;//利用枚举表示下载的三种状态
 }
 private Download_State state = Download_State.Ready;//当前下载状态
 private int globalCompelete = 0;//所有线程下载的总数
 public DownloadHttpTool(int threadCount, String urlString,
       String localPath, String fileName, Context context, Handler handler) {
  super();
  this.threadCount = threadCount;
  this.urlstr = urlString;
  this.localPath = localPath;
  this.mContext = context;
  this.mHandler = handler;
  this.fileName = fileName;
  sqlTool = new DownLoadSqlTool();
 }
 //在开始下载之前需要调用ready方法进行配置
 public void ready() {
  Log.w(TAG, "ready");
  globalCompelete = 0;
  downloadInfos = sqlTool.getInfos(urlstr);
  if (downloadInfos.size() == 0) {
   initFirst();
  } else {
   File file = new File(localPath + "/" + fileName);
   if (!file.exists()) {
    sqlTool.delete(urlstr);
    initFirst();
   } else {
    fileSize = downloadInfos.get(downloadInfos.size() - 1)
      .getEndPos();
    for (DownLoadInfo info : downloadInfos) {
     globalCompelete += info.getCompeleteSize();
    }
    Log.w(TAG, "globalCompelete:::" + globalCompelete);
   }
  }
 }
 public void start() {
  Log.w(TAG, "start");
  if (downloadInfos != null) {
   if (state == Download_State.Downloading) {
    return;
   }
   state = Download_State.Downloading;
   for (DownLoadInfo info : downloadInfos) {
    Log.v(TAG, "startThread");
    new DownloadThread(info.getThreadId(), info.getStartPos(),
      info.getEndPos(), info.getCompeleteSize(),
      info.getUrl()).start();
   }
  }
 }
 public void pause() {
  state = Download_State.Pause;
 }
 public void delete() {
  compelete();
  File file = new File(localPath + "/" + fileName);
  file.delete();
 }
 public void compelete() {
  sqlTool.delete(urlstr);
 }
 public int getFileSize() {
  return fileSize;
 }
 public int getCompeleteSize() {
  return globalCompelete;
 }
 //第一次下载初始化
 private void initFirst() {
  Log.w(TAG, "initFirst");
  try {
   URL url = new URL(urlstr);
   HttpURLConnection connection = (HttpURLConnection) url
     .openConnection();
   connection.setConnectTimeout(5000);
   connection.setRequestMethod("GET");
   fileSize = connection.getContentLength();
   Log.w(TAG, "fileSize::" + fileSize);
   File fileParent = new File(localPath);
   if (!fileParent.exists()) {
    fileParent.mkdir();
   }
   File file = new File(fileParent, fileName);
   if (!file.exists()) {
    file.createNewFile();
   }
   // 本地访问文件
   RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
   accessFile.setLength(fileSize);
   accessFile.close();
   connection.disconnect();
  } catch (Exception e) {
   e.printStackTrace();
  }
  int range = fileSize / threadCount;
  downloadInfos = new ArrayList<DownLoadInfo>();
  for (int i = 0; i < threadCount - 1; i++) {
   DownLoadInfo info = new DownLoadInfo(i, i * range, (i + 1) * range
     - 1, 0, urlstr);
   downloadInfos.add(info);
  }
  DownLoadInfo info = new DownLoadInfo(threadCount - 1, (threadCount - 1)
    * range, fileSize - 1, 0, urlstr);
  downloadInfos.add(info);
  sqlTool.insertInfos(downloadInfos);
 }
 //自定义下载线程
 private class DownloadThread extends Thread {
  private int threadId;
  private int startPos;
  private int endPos;
  private int compeleteSize;
  private String urlstr;
  private int totalThreadSize;
  public DownloadThread(int threadId, int startPos, int endPos,
        int compeleteSize, String urlstr) {
   this.threadId = threadId;
   this.startPos = startPos;
   this.endPos = endPos;
   totalThreadSize = endPos - startPos + 1;
   this.urlstr = urlstr;
   this.compeleteSize = compeleteSize;
  }
  @Override
  public void run() {
   HttpURLConnection connection = null;
   RandomAccessFile randomAccessFile = null;
   InputStream is = null;
   try {
    randomAccessFile = new RandomAccessFile(localPath + "/"
      + fileName, "rwd");
    randomAccessFile.seek(startPos + compeleteSize);
    URL url = new URL(urlstr);
    connection = (HttpURLConnection) url.openConnection();
    connection.setConnectTimeout(5000);
    connection.setRequestMethod("GET");
    connection.setRequestProperty("Range", "bytes="
      + (startPos + compeleteSize) + "-" + endPos);
    is = connection.getInputStream();
    byte[] buffer = new byte[1024];
    int length = -1;
    while ((length = is.read(buffer)) != -1) {
     randomAccessFile.write(buffer, 0, length);
     compeleteSize += length;
     Message message = Message.obtain();
     message.what = threadId;
     message.obj = urlstr;
     message.arg1 = length;
     mHandler.sendMessage(message);
     sqlTool.updataInfos(threadId, compeleteSize, urlstr);
     Log.w(TAG, "Threadid::" + threadId + " compelete::"
       + compeleteSize + " total::" + totalThreadSize);
     if (compeleteSize >= totalThreadSize) {
      break;
     }
     if (state != Download_State.Downloading) {
      break;
     }
    }
   } catch (Exception e) {
    e.printStackTrace();
   } finally {
    try {
     if (is != null) {
      is.close();
     }
     randomAccessFile.close();
     connection.disconnect();
    } catch (Exception e) {
     e.printStackTrace();
    }
   }
  }
 }
} 

八、再写一个接口类

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
 * author:Created by ZhangPengFei.
 * Email: 1271396448@qq.com
 * data: 2018/1/18
 */
public class DownloadUtil {
 private DownloadHttpTool mDownloadHttpTool;
 private OnDownloadListener onDownloadListener;
 private int fileSize;
 private int downloadedSize = 0;
 @SuppressLint("HandlerLeak")
 private Handler mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
   // TODO Auto-generated method stub
   super.handleMessage(msg);
   int length = msg.arg1;
   synchronized (this) {//加锁保证已下载的正确性
    downloadedSize += length;
   }
   if (onDownloadListener != null) {
    onDownloadListener.downloadProgress(downloadedSize);
   }
   if (downloadedSize >= fileSize) {
    mDownloadHttpTool.compelete();
    if (onDownloadListener != null) {
     onDownloadListener.downloadEnd();
    }
   }
  }
 };
 public DownloadUtil(int threadCount, String filePath, String filename,
      String urlString, Context context) {
  mDownloadHttpTool = new DownloadHttpTool(threadCount, urlString,
    filePath, filename, context, mHandler);
 }
 //下载之前首先异步线程调用ready方法获得文件大小信息,之后调用开始方法
 public void start() {
  new AsyncTask<Void,Void,Void>() {
   @Override
   protected Void doInBackground(Void... arg0) {
    // TODO Auto-generated method stub
    mDownloadHttpTool.ready();
    return null;
   }
   @Override
   protected void onPostExecute(Void result) {
    // TODO Auto-generated method stub
    super.onPostExecute(result);
    fileSize = mDownloadHttpTool.getFileSize();
    downloadedSize = mDownloadHttpTool.getCompeleteSize();
    Log.w("Tag", "downloadedSize::" + downloadedSize);
    if (onDownloadListener != null) {
     onDownloadListener.downloadStart(fileSize);
    }
    mDownloadHttpTool.start();
   }
  }.execute();
 }
 public void pause() {
  mDownloadHttpTool.pause();
 }
 public void delete(){
  mDownloadHttpTool.delete();
 }
 public void reset(){
  mDownloadHttpTool.delete();
  start();
 }
 public void setOnDownloadListener(OnDownloadListener onDownloadListener) {
  this.onDownloadListener = onDownloadListener;
 }
 //下载回调接口
 public interface OnDownloadListener {
  public void downloadStart(int fileSize);
  public void downloadProgress(int downloadedSize);//记录当前所有线程下总和
  public void downloadEnd();
 }
} 

九、写一下自己的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="com.mtd.MainActivity">
 <ProgressBar
  android:id="@+id/progressBar"
  style="?android:attr/progressBarStyleHorizontal"
  android:layout_width="fill_parent"
  android:layout_height="7.5dp"
  android:layout_centerInParent="true"
  android:layout_marginRight="8dp"
  android:max="100"
  android:progress="100"
  android:visibility="visible" />
 <TextView
  android:id="@+id/tv_Progress"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_below="@id/progressBar"
  android:layout_centerHorizontal="true"
  android:layout_marginLeft="23dp"
  android:layout_marginStart="23dp"
  android:layout_marginTop="18dp"
  android:text="" />
 <Button
  android:id="@+id/downLoad"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_marginLeft="100dp"
  android:text="下载" />
 <Button
  android:id="@+id/pause"
  android:layout_toRightOf="@id/downLoad"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignParentBottom="true"
  android:layout_marginLeft="48dp"
  android:layout_marginStart="48dp"
  android:text="暂停" />
</RelativeLayout> 

十、奉上自己的Java代码MainActivity类

import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
 private final String videoUrl = "http://2449.vod.myqcloud.com/2449_22ca37a6ea9011e5acaaf51d105342e3.f20.mp4";
 private TextView tv_progress;//进度显示
 private ProgressBar progressBar;//进度条
 private Button downLoad;//下载按钮
 private Button pause;//暂停按钮
 private String path;//下载路径
 private int max;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  tv_progress = (TextView) findViewById(R.id.tv_Progress);
  progressBar = (ProgressBar) findViewById(R.id.progressBar);
  downLoad = (Button) findViewById(R.id.downLoad);
  pause = (Button) findViewById(R.id.pause);
  path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/local";
  final DownloadUtil downloadUtil = new DownloadUtil(4, path, "drum.mp4", videoUrl, this);
  downloadUtil.setOnDownloadListener(new DownloadUtil.OnDownloadListener() {
   @Override
   public void downloadStart(int fileSize) {
    Log.i("TAG---fileSize", fileSize + "");
    max = fileSize;//文件总长度
    progressBar.setMax(fileSize);
   }
   @Override
   public void downloadProgress(int downloadedSize) {
    Log.i("TAG---downloadedSize", downloadedSize + "");
    progressBar.setProgress(downloadedSize);
    tv_progress.setText((int) downloadedSize * 100 / max + "%");
   }
   @Override
   public void downloadEnd() {
    Log.i("TAG---end", "End");
   }
  });
  /**
   * 下载的点击事件
   */
  downLoad.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    downloadUtil.start();
   }
  });
  /**
   * 暂停的点击事件
   */
  pause.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
    downloadUtil.pause();
   }
  });
 }
} 

您可能感兴趣的文章:

  • Android Studio 3.0的下载安装教程
  • mac系统下载、安装、使用AndroidStudio
  • Android Studio下载更新Android SDK网络异常或无法下载
  • Android Studio使用教程(一):下载与安装及创建HelloWorld项目
(0)

相关推荐

  • Android Studio使用教程(一):下载与安装及创建HelloWorld项目

    背景 相信大家对Android Studio已经不陌生了,Android Studio是Google于2013 I/O大会针对Android开发推出的新的开发工具,目前很多开源项目都已经在采用,Google的更新速度也很快,明显能感觉到这是Android开发的未来,那么我们还有什么理由不去拥抱未来呢? 虽然推出了很久,但是国内貌似普及的程度并不高,鉴于很多朋友求studio的详细教程,那么今天我就手把手教大家下载.安装.使用,Studio之路从这里开始. Android Studio VS Ec

  • Android Studio 3.0的下载安装教程

    本人没有接触android开发,由于想学习一下,所以自学,接下来是我学习路线,希望我走过的路能给你提供帮助. 下载 首先我们需要下载 Android Studio 3.0  官方下载  本站下载 然后学习Kotlin的语法,我推荐去Kotlin官方中文网在线学习,或者下载 PDF的中文文档  官方下载   本站下载 Android基础入门 Android基础入门教程目录 接下来介绍项目实战了,学习最好边做边发现问题. 补充如果安装 Android Studio 3.0 安装时候下载工具比较慢,D

  • mac系统下载、安装、使用AndroidStudio

    1.下载AndroidStudio AndroidStudio官网下载地址: http://developer.android.com/intl/zh-cn/sdk/index.html AndroidStudio非官网下载地址: http://www.android-studio.org java8下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 注:以下安装软件计

  • Android Studio下载更新Android SDK网络异常或无法下载

    Android Studio下载更新Android SDK网络异常或无法下载 今天重新安装了下Android Studio,在安装SDK时老是提示网络异常,于是上网查了下, 解决方法如下:HTTP Proxy中Host name设置为mirrors.neusoft.edu.cn 再勾选 这样设置就好了,试了下下载速度很快,感谢好心人提供的方法 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

  • Android Studio 下载视频到本地

    最近在研究视频下载到本地的问题,像爱奇艺,腾讯视频,迅雷看看等等一些视频播放器,如果在一个播放器里面视频下载到一半用户退出App之后,再次登录从头开始,那么就太可悲了,所以在做视频音频类的项目时,要实现的一个功能就是断点续传,就是将用户下载的视频或者音频等以字节流的形式存入数据库,下次用户再次下载时,将继续上次数据库的接着下载,这样用户体验就会很好,也大大节省了成本. 好了废话不多说,开始今天的正题. 一.先上效果图 二.使用GreenDao我们需要导入依赖 1.以下在项目gradle依赖中添加

  • Android Studio通过Artifactory搭建本地仓库优化编译速度的方法

    Android Studio 编译速度慢,一般来说,原因有下面几个. Gradle下载慢 依赖库下载慢 依赖库使用"+"(使用最新的),每次都需要去查找新的(尽量不适用这种方式) 这里,大部分的库,我们可以通过阿里云代理仓库. 但是,如果有我们自己的私有库或者插件的话.肯定不希望放到阿里云上了. 这个时候,我们就需要建立,我们自己的本地仓库,让私有仓库,依赖阿里云的私有仓库. 依赖关系,如下图 这样,既保证了我们私有库的安全性,又让我们的依赖库也享受到了阿里云代理仓库的便利. 通过Ar

  • Android Studio配合WampServer完成本地Web服务器访问的问题

    前言 初入Android Studio,在访问Web服务器时遇到的一些问题,特写此篇记录一下错误的解决. 一.WampServer服务器 初入Android Studio,在进行Web服务器的访问时要用到本地的Web服务器,通过WampServer实现. 本次使用的是WampServer 2.2版本,下载链接附在下方: 链接: https://pan.baidu.com/s/1STRuXrol0ZXCFkMTpmSOZw 提取码: 5x22 (有32位以及64位两个版本) 二.问题解析 1.图标

  • Android studio 将字符串写入本地的操作方法

    File 类的操作: 1.首先需要添加相关权限: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 注意6.0以上需要动态申请: private void checkPermission(){

  • Android Studio下载与安装简易教程

    本文为大家分享了Android Studio下载与安装的具体步骤,供大家参考,具体内容如下 1.Android Studio下载地址:点击打开链接 进入界面:如图所示,点击绿色框,下载 ANDROID STUDIO: 如图所示,找好下载的安装文件,双击Android studio的安装文件: 进入安装界面:下图,直接点击 Next 就可以了: 进入下一个界面,如图,选择安装的插件,勾上android virtual device ,点击Next. 这里的话要说明一下,以前2.多版本的时候是需要在

  • Android studio 项目手动在本地磁盘中删除module后,残留文件夹无法删除的问题解决方法

    Android studio 项目手动在本地磁盘中删除module后,残留文件夹无法删除问题 如标题所述,本人在本地磁盘删除project中的module后(好吧,是我太菜了),仍然残留着一个文件夹,但是又无法右键之后又无法删除,(强迫症得我觉得很难受),每次打开时候还Android studio还报了一个错误,如下: .Unsupported Modules Detected: Compilation is not supported for following modules: testfo

  • Android Studio下载、安装和配置+SDK+tools下载(无敌超级详细版本)

    下载: Anderson Studio是Google为Android提供的官方IDE工具,下载地址:http://www.android-studio.org/ 下载3.4.1.0版本地址:ctrl+f 查找3.4.1.0 直接下载3.4.1.0的下载地址:https://dl.google.com/dl/android/studio/install/3.4.1.0/android-studio-ide-183.5522156-windows.exe 安装环境要求 : 其中JDK的最低版本是1.

  • Android Studio 3.0 Gradle 配置变更

    多渠道打包变更 flavorDimensions "default" productFlavors { xxxx { dimension "default" } } productFlavors.all { flavor -> flavor.manifestPlaceholders = [CHANNEL_VALUE: name] } 更改打包命名及路径 android.applicationVariants.all { variant -> if (va

  • Eclipse NDK迁移到Android Studio的方法示例

    最近看一个NDK项目,因为源码使用Eclipse IDE写的,想把代码导入Android Studio使用,毕竟好用很多,使用AS导入后,第一个问题就是编码问题,项目之前竟然使用的是GBK编码.首先就是改变编码问题.我先在设置中将项目编码改为UTF-8,build结果显示一堆错误的乱码,在网上逛了一圈,找到解决方案. 编码 将AS右下角的UTF-8换成GBK. 跳出提示选择"reload",此时注释之类的乱码会显示正确. 右下角再选择UTF-8 跳出提示选择"convert&

随机推荐