该项目是一个Android项目,适合新手,运用了很多的常见组件和布局。
项目亮点在于运用了百度网盘的API,通过授权可以在APP中展示授权账号的百度网盘里面的内容,展示的效果如文中图片所示。除此之外还有登录页运用缓存登录,还有历史记录页等等。
适用范围:
1.用于完成学校Android作业的朋友。(代码量大,逼格拉满)
2.需要一个Android项目来学习技术的朋友。
3.想要写一个网盘之类软件但是自己不想写界面的朋友,可以再此之上继续自己添加内容。
4.想要使用百度网盘API,但是具体不知道怎么操作的朋友。

前言

写这个项目是为了继续打打android的基础,另外还了解到了一些新方法和小技巧所以想来用用练练手,比如调用百度api来访问个人百度网盘中的头像名称项目文件等等,继续深入还可以在App中修改个人百度网盘中的文件。

项目结构

结构是

登录界面

只是主观简单的模仿了一下,可能有点丑。
activity_main

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".activity.MainActivity"><TextViewapp:layout_constraintTop_toTopOf="parent"android:id="@+id/txt_title1"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="登录"android:gravity="center"android:textSize="30sp"android:textColor="#fff"android:background="@color/colorBtnEnable"android:padding="5dp"/><EditTextandroid:padding="10dp"android:id="@+id/et_login_user"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/txt_title"android:hint="请输入手机号/用户名/邮箱"android:background="@drawable/bac_1"android:layout_margin="@dimen/marginSize"tools:ignore="MissingConstraints"
/><EditTextandroid:padding="10dp"android:id="@+id/et_login_psw"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="密码"android:background="@drawable/bac_1"android:layout_margin="@dimen/marginSize"app:layout_constraintTop_toBottomOf="@+id/et_login_user"tools:ignore="MissingConstraints" /><Buttonandroid:id="@+id/btn_login"android:layout_width="match_parent"android:layout_height="48dp"android:enabled="false"android:text="登录"android:background="@drawable/bac_2"android:layout_margin="@dimen/marginSize"app:layout_constraintTop_toBottomOf="@+id/et_login_psw"tools:ignore="MissingConstraints" /><ImageButtonandroid:foregroundGravity="center"android:id="@+id/ib_login_psw_visible"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintTop_toBottomOf="@id/et_login_user"app:layout_constraintBottom_toBottomOf="@+id/et_login_psw"app:layout_constraintRight_toRightOf="@id/et_login_psw" /><ImageViewandroid:id="@+id/img"android:src="@mipmap/baidu_resultlogo"app:layout_constraintTop_toBottomOf="@+id/txt_title1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_margin="@dimen/marginSize"tools:ignore="MissingConstraints" />
<TextViewandroid:id="@+id/txt_title"android:layout_width="wrap_content"app:layout_constraintTop_toBottomOf="@id/img"android:layout_height="wrap_content"android:text="欢迎登录百度账号"android:textColor="#000"android:textSize="35sp"android:layout_margin="@dimen/marginSize"tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>


然后在这个界面中做一些设置。

在这里插入代码片import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;import com.example.baidudisk.R;public class MainActivity extends AppCompatActivity implements View.OnClickListener{EditText mUserEt,mPswEt;
Button mLoginBtn;
private ImageButton mPswVisibleBtn;
private boolean mPswVisible=false;
private static final String SP_IS_LOGIN="is_login";
private static final String USER="user";
private static final String PSW="psw";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);setStatusBarFullTransparent();mPswVisibleBtn=findViewById(R.id.ib_login_psw_visible);mLoginBtn=findViewById(R.id.btn_login);mUserEt=findViewById(R.id.et_login_user);mPswEt=findViewById(R.id.et_login_psw);setPswVisible();mUserEt.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {setBtnBg(s);}});mPswEt.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {setBtnBg(s);}});mLoginBtn.setOnClickListener(this);mPswVisibleBtn.setOnClickListener(this);}private void setPswVisible() {mPswVisibleBtn.setBackgroundResource(mPswVisible?R.mipmap.open:R.mipmap.hide);mPswEt.setTransformationMethod(mPswVisible? HideReturnsTransformationMethod.getInstance(): PasswordTransformationMethod.getInstance());mPswEt.setSelection(mPswEt.getText().toString().length());mPswVisible=!mPswVisible;}private void setBtnBg(Editable s) {if(mUserEt.getText().length()>0&&mPswEt.getText().length()>0){mLoginBtn.setEnabled(true);mLoginBtn.setBackgroundColor(getResources().getColor(R.color.colorBtnEnable));mLoginBtn.setTextColor(Color.WHITE);}else{mLoginBtn.setEnabled(false);mLoginBtn.setBackgroundColor(getResources().getColor(R.color.colorBtnDissablr));mLoginBtn.setTextColor(getResources().getColor(R.color.colorTextDisable));}}//状态栏透明protected void setStatusBarFullTransparent() {if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){Window window=getWindow();window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LAYOUT_STABLE);window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.setStatusBarColor(Color.TRANSPARENT);}else if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);}}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.btn_login:if("swust".equals(mPswEt.getText().toString().trim())&&"swust".equals(mUserEt.getText().toString().trim())){saveUserNameAndPsw();Toast.makeText(MainActivity.this,"登录成功",Toast.LENGTH_SHORT).show();Intent intent =new Intent(MainActivity.this,HomeActivity.class);intent.putExtra("str1",mUserEt.getText().toString());startActivity(intent);}elseToast.makeText(MainActivity.this,"登录失败",Toast.LENGTH_SHORT).show();break;case R.id.ib_login_psw_visible:setPswVisible();break;}}/*** 保存用户名和密码*/private void saveUserNameAndPsw(){getSharedPreferences(SP_IS_LOGIN, Context.MODE_PRIVATE).edit().putString(USER,mUserEt.getText().toString()).putString(PSW,mPswEt.getText().toString()).apply();}/*** 填充用户名和密码*/private void fillUserNameAndPsw(){String user= getSharedPreferences(SP_IS_LOGIN,MODE_PRIVATE).getString(USER,"");String psw =getSharedPreferences(SP_IS_LOGIN,MODE_PRIVATE).getString(PSW,"");mUserEt.setText(user);mPswEt.setText(psw);mUserEt.setSelection(mUserEt.getText().length());}@Overrideprotected void onStart() {super.onStart();fillUserNameAndPsw();}
}

实现的一些功能

该页面中实现的功能有:
1.当账号和密码都有内容时按钮会变成蓝色。
2.点击密码右侧的眼睛按钮可以实现密码可见与隐藏的切换。
3.使用SharedPreferences实现对账号和密码的存储并在下次启动时直接填充在文本框中。这次并没有实现注册功能,在上个项目中已经有例子了。

主界面

在这个项目主页面只实现两个子页面,上个项目中运用的是viewpager+fragment的方法,在这个项目中,为了简单起见只采用两个fragment实现页面即可。

一个是文件列表,一个是个人中心。
登录成功之后跳转到HomeActivity

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;import android.os.Bundle;
import android.view.View;import com.example.baidudisk.R;public class HomeActivity extends AppCompatActivity{FileFragment fileFragment=new FileFragment();ProFileFragment profileFragment=new ProFileFragment();FragmentManager fragmentManager=getSupportFragmentManager();FragmentTransaction transaction =fragmentManager.beginTransaction();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_home);transaction.add(R.id.fragment,fileFragment);transaction.commit();}public void mePage(View view) {changeFragment(R.id.fragment,profileFragment);}public void filePage(View view) {changeFragment(R.id.fragment,fileFragment);}void changeFragment(int resource,Fragment fragment){FragmentManager fragmentManager=getSupportFragmentManager();FragmentTransaction transaction =fragmentManager.beginTransaction();transaction.replace(resource,fragment);transaction.commit();}
}

实现了两个fragment之间的切换。(我认为这算是最简单的子界面的切换方式)
然后是他的布局文件
activity_home

<?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:id="@+id/re_1"android:layout_width="match_parent"android:layout_height="match_parent">
<FrameLayoutandroid:id="@+id/fragment"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_above="@+id/daohang">
</FrameLayout><LinearLayoutandroid:id="@+id/daohang"android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_gravity="bottom"><LinearLayoutandroid:id="@+id/ll_file"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:orientation="vertical"android:onClick="filePage"android:foreground="?attr/selectableItemBackground"><ImageViewandroid:id="@+id/iv_bottom_file"android:layout_width="24dp"android:layout_height="24dp"android:layout_gravity="center_horizontal"android:layout_marginTop="8dp"android:src="@mipmap/bottombar_btn_file_pre"/><TextViewandroid:id="@+id/tv_bottom_file"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="文件"android:layout_gravity="center_horizontal"android:layout_marginBottom="2dp"android:textSize="12sp"android:textColor="@color/colorBtnEnable"/></LinearLayout><LinearLayoutandroid:id="@+id/ll_me"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:orientation="vertical"android:foreground="?attr/selectableItemBackground"android:onClick="mePage"><ImageViewandroid:id="@+id/iv_bottom_me"android:layout_width="24dp"android:layout_height="24dp"android:layout_gravity="center_horizontal"android:layout_marginTop="8dp"android:src="@mipmap/swan_app_user_portrait_pressed"/><TextViewandroid:id="@+id/tv_bottom_me"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="我的"android:layout_gravity="center_horizontal"android:layout_marginBottom="2dp"android:textSize="12sp"android:textColor="@color/colorBtnEnable"/></LinearLayout></LinearLayout>
</RelativeLayout>

这个帧布局就作为fragment放的地方。

文件页面

接下来就要写这两个布局
先是文件碎片
FileFragment
在这个碎片中需要实现的是一个recycleview视图显示文件,在最开始我只是简单模拟一下几个文件,但后面感觉太单调了就改成了读取并显示本机的文件了。读取本机的文件需要注意的是要获取相关的权限:

    private void requestPermissions() {if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN && getActivity()!= null) {if (ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED){//获取权限后的操作}else{requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},0);}}}

通过mCurrPath=Environment.getExternalStorageDirectory().getAbsolutePath();获取本机的文件的绝对路径

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.example.baidudisk.R;
import com.example.baidudisk.adapter.FileAdapter;
import com.example.baidudisk.adapter.MyFileAdapter;
import com.example.baidudisk.enity.FileEntity;
import com.example.baidudisk.enity.FileListEntity;
import com.example.baidudisk.intent.NetworkInterfaces;
import com.google.gson.Gson;import org.jetbrains.annotations.NotNull;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;public class FileFragment extends Fragment implements View.OnClickListener{int mLevel=0;LinearLayout linearLayout;private Handler mHandler;private  List<FileEntity> fileEntityList=new ArrayList<>();private List<FileListEntity.ListBean> mFiles=new ArrayList<FileListEntity.ListBean>();FileAdapter mAdapter;String mCurrPath;MyFileAdapter myFileAdapter;private TextView mTip;Stack<String> mPathStack=new Stack<>();RecyclerView mFilesRV;SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view=inflater.inflate(R.layout.fragment_file,container,false);mHandler=new Handler();mFilesRV =view.findViewById(R.id.rv_files);mAdapter=new FileAdapter(fileEntityList);myFileAdapter=new MyFileAdapter(mFiles);mTip=view.findViewById(R.id.mTipTv);linearLayout =view.findViewById(R.id.ll_1);linearLayout.setOnClickListener(this);LinearLayoutManager layoutManager=new LinearLayoutManager(getContext());mFilesRV.setLayoutManager(layoutManager);mFilesRV.setAdapter(mAdapter);showExternalFiles();requestPermissions();mAdapter.setListener(new FileAdapter.setOnClickListener() {@Overridepublic void onClick(int position) {if (getActivity()!=null&&fileEntityList.get(position).type!=R.mipmap.file){mLevel++;mCurrPath=mCurrPath+"/"+fileEntityList.get(position).name;showSubFiles();}}});view.setFocusableInTouchMode(true);view.requestFocus();/*** 后面需要注释*/view.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (event.getAction()== KeyEvent.ACTION_DOWN&&keyCode==KeyEvent.KEYCODE_BACK&&mLevel>0){File file =new File(mCurrPath).getParentFile();if(file!=null){mCurrPath=file.getAbsolutePath();mLevel--;showSubFiles();return true;}}return false;}});/*** 后面需要显示*//*myFileAdapter.setListener(new MyFileAdapter.setOnClickListener() {@Overridepublic void onClick(int position) {if (mFiles.get(position).getIsdir()==1){forward(mFiles.get(position).getPath());}}});view.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (event.getAction()== KeyEvent.ACTION_DOWN&&keyCode==KeyEvent.KEYCODE_BACK){if (!mPathStack.empty()){back();return true;}}return false;}});getFileList("/");*/return view;}/*** 获取权限*/private void requestPermissions() {if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.JELLY_BEAN && getActivity()!= null) {if (ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED){//获取权限后的操作}else{requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},0);}}}@Overridepublic void onClick(View v) {switch (v.getId()){case R.id.ll_1:startActivity(new Intent(getContext(),SearchActivity.class));break;}}private void showExternalFiles(){mCurrPath=Environment.getExternalStorageDirectory().getAbsolutePath();showSubFiles();}private void showSubFiles(){File file =new File(mCurrPath);if (file.exists() && file.isDirectory()) {File[] sub =file.listFiles();if (sub!=null){fileEntityList.clear();for(File f:sub){fileEntityList.add(new FileEntity(f.isDirectory()?R.mipmap.ic_gc_main_empty_folder:R.mipmap.file,f.getName(),simpleDateFormat.format(new Date(f.lastModified()))));}}else{fileEntityList.clear();}mAdapter.notifyDataSetChanged();}}//下面的代码在后面需要显示/*private void showLoading(){mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.GONE);mTip.setText("正在加载.......");mTip.setVisibility(View.VISIBLE);}});}private void showResult(){mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.VISIBLE);mTip.setVisibility(View.INVISIBLE);myFileAdapter.notifyDataSetChanged();}});}private void showError(){mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.GONE);mTip.setVisibility(View.VISIBLE);mTip.setText("获取文件失败");}});}private void getFileList(String path){showLoading();new NetworkInterfaces().getFileListALL(path, new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {showError();}@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {FileListEntity entity=new Gson().fromJson(response.body().string(),FileListEntity.class);if(entity.getErrno()==0){showFileList(entity.getList());}else {showError();System.out.println(entity.getErrmsg());}}});}private void showFileList(List<FileListEntity.ListBean> beans) {mFiles.clear();mFiles.addAll(beans);mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setAdapter(myFileAdapter);myFileAdapter.notifyDataSetChanged();if (mFiles.isEmpty()){Toast.makeText(getContext(),"没有文件!",Toast.LENGTH_SHORT).show();}else{showResult();}}});}private void forward(String path){mCurrPath=path;mPathStack.push(path);getFileList(mCurrPath);}private void back(){mPathStack.pop();if (!mPathStack.empty()){mCurrPath=mPathStack.peek();mPathStack.pop();}else{mCurrPath="/";}getFileList(mCurrPath);}*/}

FileAdapter

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import com.example.baidudisk.enity.FileEntity;
import com.example.baidudisk.R;import java.util.List;
public class FileAdapter extends RecyclerView.Adapter<FileAdapter.ViewHolder> {public interface setOnClickListener {void onClick(int position);}private List<FileEntity> mFileList;public setOnClickListener myClickListener;public void setListener(setOnClickListener s) {myClickListener = s;}static class ViewHolder extends RecyclerView.ViewHolder {ImageView mFileTypePic;TextView mFileName;TextView mFileCreationDate;LinearLayout mRootLl;public ViewHolder(@NonNull View itemView) {super(itemView);mFileTypePic = itemView.findViewById(R.id.re_pic);mFileName = itemView.findViewById(R.id.re_name);mFileCreationDate = itemView.findViewById(R.id.re_creation_time);mRootLl = itemView.findViewById(R.id.ll_mRootLl);}}public FileAdapter(List<FileEntity> filelist) {mFileList = filelist;}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_file, parent, false);final ViewHolder holder = new ViewHolder(view);return holder;}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, final int position) {FileEntity fileEntity = mFileList.get(position);holder.mFileTypePic.setImageResource(fileEntity.getType());holder.mFileName.setText(fileEntity.getName());holder.mFileCreationDate.setText(fileEntity.getDate());holder.itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myClickListener.onClick(position);}});}@Overridepublic int getItemCount() {return mFileList.size();}}


不同的手机所显示的文件应该不同,但是实现文件通过level实现前进倒退的逻辑在代码中也很清晰,这里不再赘述。
因为代码中有些是后面运用百度api展示文件列表的代码所以就先注释掉了。

然后就是大概的一个布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><LinearLayoutandroid:id="@+id/ll_1"android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="32dp"android:layout_marginBottom="16dp"android:background="@drawable/bac_1"android:layout_marginLeft="16dp"android:layout_marginRight="16dp">
<ImageButtonandroid:layout_width="24dp"android:layout_height="24dp"android:layout_margin="8dp"android:src="@mipmap/search"android:layout_gravity="center_vertical"/><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_marginRight="16dp"android:text="搜索我的网盘文件"android:textSize="16sp" />
</LinearLayout><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_files"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="16sp"android:layout_marginRight="16sp"/><TextViewandroid:id="@+id/mTipTv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:visibility="gone"android:text="正在加载......."/>
</LinearLayout>

搜索页面

在这个页面中还存在一个搜索框,点击搜索框会进入搜索页面。搜索页面也是又两部分组成,一是搜索框,必须具备一键删除文本的功能。
而是列表视图用来显示搜索历史,在下方也必须要有一键清除历史记录的功能。
梳理一下逻辑就是:
当文本框中有内容时,取消二字要能变成搜索二字,如果点击旁边的叉叉就一键删除文本内容。当没有文本时不会显示叉叉。
如果是点击搜索文字之后,文本框中的文本记录要能更新到下方的视图中。(还没有实现真的定位到所搜索的文件)
采用的是sqlite存储和删除记录。之所以采用数据库的原因是为了,后面再次进入应用时之前的记录依然存在,否则就没有实现的必要了。
点击碎片上方搜索框进入搜索页面

SearchActivity

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;import com.example.baidudisk.db.DBHelper;
import com.example.baidudisk.R;
import com.example.baidudisk.adapter.SearchAdapter;import java.util.ArrayList;
import java.util.List;public class SearchActivity extends AppCompatActivity implements View.OnTouchListener {private final static String TABLE_NAME="search_history";private final static String COLUMN_NAME="name";private static  String DB_NAME ="history.db";private static  int DB_VERSION =1 ;TextView cancel_serach;EditText mEtSearch;SearchAdapter searchAdapter;RecyclerView recyclerView;TextView deleteAll;Drawable delete;private List<String> historyList;SQLiteDatabase mDB;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_search);recyclerView=findViewById(R.id.rv_search);cancel_serach=findViewById(R.id.cancel_search);mEtSearch=findViewById(R.id.et_search);historyList=new ArrayList<>();deleteAll=findViewById(R.id.deleteAll);searchAdapter=new SearchAdapter(historyList);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(searchAdapter);queryAllHistory();delete= ContextCompat.getDrawable(this,R.mipmap.deleteall);delete.setBounds(0,0,delete.getIntrinsicWidth()*3/4,delete.getIntrinsicHeight()*3/4);searchAdapter.setClick(new SearchAdapter.Click() {@Overridepublic void Delete(int position) {deleteHistory(historyList.get(position));historyList.remove(historyList.get(position));searchAdapter.notifyDataSetChanged();}@Overridepublic void AddText(int position) {mEtSearch.setText(historyList.get(position));mEtSearch.setSelection(mEtSearch.getText().length());}});deleteAll.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {deleteALLHistory();historyList.clear(); //清除记录searchAdapter.notifyDataSetChanged();}});mEtSearch.setImeOptions(EditorInfo.IME_ACTION_SEARCH);cancel_serach.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String str= cancel_serach.getText().toString();if(str.equals("搜索")){search();// historyList.add(new SearchEnity(mEtSearch.getText().toString()));searchAdapter.notifyDataSetChanged();}else{finish();}}});mEtSearch.setOnTouchListener(this);mEtSearch.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {setDelete();}});}public void queryAllHistory(){mDB=new DBHelper(this,DB_NAME,null,DB_VERSION).getWritableDatabase();Cursor cursor=mDB.query(TABLE_NAME,new String[]{COLUMN_NAME},null,null,null,null,null);while (cursor.moveToNext()){historyList.add(cursor.getString(cursor.getColumnIndex(COLUMN_NAME)));}cursor.close();searchAdapter.notifyDataSetChanged();}/**** @param name 需要插入的字符串*/private void insertHistory(String name){//通过键值对插入数据项ContentValues values=new ContentValues();values.put(COLUMN_NAME,name);mDB.insert(TABLE_NAME,null,values);}/**** @param name 需要删除的字符串*/private void deleteHistory(String name){mDB.delete(TABLE_NAME,COLUMN_NAME+"=?",new String[]{name});}private void deleteALLHistory(){mDB.execSQL("delete from "+TABLE_NAME);}/*** 搜索* 向搜索历史添加数据*/private void search(){String content =mEtSearch.getText().toString();if (content.length()>0&&!historyList.contains(content)){historyList.add(content);searchAdapter.notifyDataSetChanged();insertHistory(content);}}private void setDelete() {if(mEtSearch.getText().length()>0) {mEtSearch.setCompoundDrawables(null, null, delete, null);cancel_serach.setText("搜索");}else{mEtSearch.setCompoundDrawables(null,null,null,null);cancel_serach.setText("取消");}}@Overridepublic boolean onTouch(View v, MotionEvent event) {if  (event.getAction()==MotionEvent.ACTION_DOWN){if(event.getRawX()>v.getWidth()-v.getPaddingRight()-delete.getIntrinsicWidth()){mEtSearch.setText("");}}return false;}}

activity_search

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"xmlns:android="http://schemas.android.com/apk/res/android"><LinearLayoutandroid:orientation="horizontal"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="32dp"android:layout_marginBottom="16dp"android:background="@drawable/bac_1"android:layout_marginLeft="16dp"android:layout_marginRight="16dp"><ImageButtonandroid:layout_width="24dp"android:layout_height="24dp"android:layout_margin="8dp"android:src="@mipmap/search"android:layout_gravity="center_vertical"/><EditTextandroid:id="@+id/et_search"android:background="@null"android:layout_width="0dp"android:layout_weight="4"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:layout_marginRight="16dp"android:hint="搜索我的网盘文件"android:textColor="#000"android:textSize="16sp" /><TextViewandroid:id="@+id/cancel_search"android:layout_width="0dp"android:clickable="true"android:layout_weight="1"android:layout_height="wrap_content"android:layout_gravity="center_vertical"android:text="取消"android:gravity="center"android:textStyle="bold"android:textSize="20sp"android:textColor="#0968F7"/></LinearLayout><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="搜索标题"android:textStyle="bold"android:textSize="25sp"/><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/rv_search"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="5dp" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"><TextViewandroid:id="@+id/deleteAll"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="清除所有历史记录"android:gravity="center"android:textSize="20sp"android:layout_gravity="bottom"android:textColor="@color/colorAccent"/></LinearLayout>
</LinearLayout>

在实现点击小叉叉消除文本时采用的是重写Ontouch,当所按下的位置处于小叉的位置时,清空文本。
搜索记录所需要的用到的适配器

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.baidudisk.R;import java.util.List;
public class SearchAdapter extends RecyclerView.Adapter<SearchAdapter.ViewHolder>{public interface Click{void Delete(int position);void AddText(int position);}Click click;public void setClick(Click click) {this.click = click;}private List<String> historyList;public SearchAdapter(List<String> historyList){this.historyList=historyList;}static class ViewHolder extends RecyclerView.ViewHolder{ImageButton imageDelete;ImageView imageTime;TextView textName;public ViewHolder(@NonNull View itemView) {super(itemView);imageDelete=itemView.findViewById(R.id.delete);imageTime =itemView.findViewById(R.id.re_time);textName=itemView.findViewById(R.id.search_name);}}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.search_item,parent,false);ViewHolder viewHolder =new ViewHolder(view);return viewHolder;}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, final int position) {String str =historyList.get(position);holder.textName.setText(str);holder.imageTime.setImageResource(R.mipmap.time);holder.imageDelete.setImageResource(R.mipmap.deleteall);holder.itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {click.AddText(position);}});holder.imageDelete.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {click.Delete(position);}});}@Overridepublic int getItemCount() {return historyList.size();}
}

创建接口,传入position,从而在实现接口时,更新搜索记录视图。在相应的位置同时做好数据库的相关操作。


再次进入app,这些记录也不会消失因为已经进入到了数据库中。另外点击这些搜索记录能够直接将文本快速显示到搜索框中。
这样搜索页面算是大功告成。

个人页面

接下来就是个人页面,我写的相当简单。没什么好说的。
简单布局+简单控件+网格视图
这代码就没什么发的。如图:


直到这里,一个简单的雏形也就形成了。因为还是没有涉及到网络,所以就又加了一个功能,就是通过百度网盘的api将自己网盘中的头像,名称,存储容量显示在个人页面中。把网盘的文件显示在文件列表中,同时也实现文件的前进与后退。

使用百度云盘API

要使用百度云盘的api就要先成为百度开发者,注册一个就可以了。
在百度开发者的应用管理中创建应用从而获得一个api key。
例如

然后通过浏览器进入下面这个网址
https://openapi.baidu.com/oauth/2.0/authorize?response_type=token&client_id=这里填你的api key&redirect_uri=oob&scope=netdisk

然后会有授权信息,授权之后网址栏上的网址会发生变化。

这时候需要保存好access_token=后面的那一小段,这个也就是拿到的令牌。有了这个授权令牌之后就不在需要通过账号密码访问网盘了直接就可以通过令牌访问百度网盘。

具体情况可以看官方文档百度网盘官方技术文档https://pan.baidu.com/union/document/entrance

拿到令牌之后就可以继续进行下面的操作了
创建一个接口类,定义一些请求方法。
NetworkInterfaces

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;public class NetworkInterfaces {private static final int CONNECT_TIME_OUT=8;private OkHttpClient mClient;private final static String ACCESS_TOKEN="这里填入你的令牌";//下面这些请求地址都是可以在官方文档中查到的private final static String HOST="https://pan.baidu.com";private final static String SYNC_INFO="/rest/2.0/xpan/nas?method=uinfo";private final static String SPACE="/api/quota";private final static String FILE_LIST_ALL="/rest/2.0/xpan/multimedia?method=listall";private OkHttpClient getOkHttpClient(){if (mClient==null){mClient=new OkHttpClient.Builder().connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS).build();}return mClient;}public void sendGetHttpRequest(String url, Map<String,String> params, Callback callback){HttpUrl.Builder builder=HttpUrl.get(url).newBuilder();for (String key :params.keySet()){builder.addQueryParameter(key,params.get(key));}Request request=new Request.Builder().url(builder.build()).get().build();getOkHttpClient().newCall(request).enqueue(callback);}//获取用户信息public void syncUserInfo(Callback callback){Map<String,String> param =new HashMap<>();param.put("access_token",ACCESS_TOKEN);sendGetHttpRequest(HOST+SYNC_INFO,param,callback);}
//获取网盘容量public void syncUserSpace(Callback callback){Map<String,String> param =new HashMap<>();param.put("access_token",ACCESS_TOKEN);sendGetHttpRequest(HOST+SPACE,param,callback);}//获取文件列表public void getFileListALL(String path,Callback callback){Map<String,String> param =new HashMap<>();param.put("access_token",ACCESS_TOKEN);param.put("path",path);sendGetHttpRequest(HOST+FILE_LIST_ALL,param,callback);
}
}

需要注意的是,需要用到的请求地址都是可以再官方文档中查到的。例如像获取用户信息,官方给出的要求是这样子的:

我们使用他的接口地址和格式请求网络,他会返回给我们一些数据,我们所需要的部分就在这些数据中。
官方文档也给出了响应实例:

根据响应实例我们需要创建相应的实体类的对象来保存返回的数据,从而显示在我们的应用上。
例如这个用户实例我们就需要创建实体类

public class UserInfoEnity {/**来自百度官方的示例* avatar_url : https://dss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/netdisk.1.3d20c095.phlucxvny00WCx9W4kLifw.jpg* baidu_name : 啊呀呀* errmsg : succ* errno : 0* netdisk_name : abcdefff* request_id : 674030589892501935* uk : 208281036* vip_type : 0*/private String avatar_url;private String baidu_name;private String errmsg;private int errno;private String netdisk_name;private String request_id;private double uk;private int vip_type;public String getAvatar_url() {return avatar_url;}public void setAvatar_url(String avatar_url) {this.avatar_url = avatar_url;}public String getBaidu_name() {return baidu_name;}public void setBaidu_name(String baidu_name) {this.baidu_name = baidu_name;}public String getErrmsg() {return errmsg;}public void setErrmsg(String errmsg) {this.errmsg = errmsg;}public int getErrno() {return errno;}public void setErrno(int errno) {this.errno = errno;}public String getNetdisk_name() {return netdisk_name;}public void setNetdisk_name(String netdisk_name) {this.netdisk_name = netdisk_name;}public String getRequest_id() {return request_id;}public void setRequest_id(String request_id) {this.request_id = request_id;}public double getUk() {return uk;}public void setUk(int uk) {this.uk = uk;}public int getVip_type() {return vip_type;}public void setVip_type(int vip_type) {this.vip_type = vip_type;}
}

具体的通过json串快速创建实体类可以通过一个插件GsonFormat,他可以通过json串自动创建对应的实体类

具体实现可自行百度。

这里踩了一个坑,就是当时按照文档的要求,uk属性的数据类型是设置的是int,但是始终报错,原因是因为越界了,所以考虑到可能是因为账户比较新,用户在增加,可能是因为我的uk值太大了,int表示不了就换成了double,然后就能正确运行了。

这里面就有了基本的用户信息。用GSON把它解析出来更新在界面上就好了。
ProFileFragment

import android.os.Bundle;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.example.baidudisk.R;
import com.example.baidudisk.adapter.GridviewAdapter;
import com.example.baidudisk.enity.Icon;
import com.example.baidudisk.enity.SpaceEntity;
import com.example.baidudisk.enity.UserInfoEnity;
import com.example.baidudisk.intent.NetworkInterfaces;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;import org.jetbrains.annotations.NotNull;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;public class ProFileFragment extends Fragment {GridView gridView;TextView user_id;private GridviewAdapter adapter;private ArrayList<Icon> Data;private Handler mHandler;private TextView mSpace;private RecyclerView mFilesRV;private ProgressBar mProgress;ImageView mVip,touxiang;@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view=inflater.inflate(R.layout.activity_me_acitivity,container,false);gridView=view.findViewById(R.id.grid_view);user_id=view.findViewById(R.id.user_id);touxiang=view.findViewById(R.id.touxiang);mFilesRV=view.findViewById(R.id.rv_files);mProgress=view.findViewById(R.id.pro);mSpace=view.findViewById(R.id.mSpace);String data=getActivity().getIntent().getStringExtra("str1");mVip=view.findViewById(R.id.mVip);user_id.setText(data);Data=new ArrayList<>();mHandler=new Handler();Data.add(new Icon(R.mipmap.file_add_btn_file,"上传文档"));Data.add(new Icon(R.mipmap.file_add_btn_folder,"新建文件夹"));Data.add(new Icon(R.mipmap.file_add_btn_music,"上传音乐"));Data.add(new Icon(R.mipmap.file_add_btn_note,"新建笔记"));Data.add(new Icon(R.mipmap.file_add_btn_other,"上传其他文件"));Data.add(new Icon(R.mipmap.file_add_btn_photo,"上传照片"));Data.add(new Icon(R.mipmap.file_add_btn_scan,"扫一扫"));Data.add(new Icon(R.mipmap.file_add_btn_video,"上传视频"));adapter=new GridviewAdapter(getContext(),R.layout.item_grid_icon,Data);gridView.setAdapter(adapter);syncUserInfo();syncSpace();return view;}private void syncUserInfo(){new NetworkInterfaces().syncUserInfo(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {Toast.makeText(getContext(),"获取用户信息失败!",Toast.LENGTH_SHORT).show();}@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {UserInfoEnity entity=new Gson().fromJson(response.body().string(),UserInfoEnity.class);if(entity.getErrno()==0){showUserInfo(entity);}else {Toast.makeText(getContext(),"获取失败",Toast.LENGTH_SHORT).show();}}});}private void showUserInfo(final UserInfoEnity entity) {mHandler.post(new Runnable() {@Overridepublic void run() {Glide.with(ProFileFragment.this).load(entity.getAvatar_url()).centerCrop().placeholder(R.mipmap.swan_app_user_portrait_pressed).apply(RequestOptions.circleCropTransform()).into(touxiang);user_id.setText(entity.getBaidu_name());switch (entity.getVip_type()){case 0: mVip.setImageResource(R.mipmap.home_identity_common);break;case 1: mVip.setImageResource(R.mipmap.home_identity_member);break;case 2: mVip.setImageResource(R.mipmap.home_identity_super);break;}}});}public void syncSpace(){new NetworkInterfaces().syncUserSpace(new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {Toast.makeText(getContext(),"获取容量失败",Toast.LENGTH_SHORT).show();}@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {SpaceEntity entity=new Gson().fromJson(response.body().string(),SpaceEntity.class);if(entity.getErrno()==0){showSpace(entity);}else {Toast.makeText(getContext(),"获取失败",Toast.LENGTH_SHORT).show();}}});}private void showSpace(final SpaceEntity entity) {mHandler.post(new Runnable() {@Overridepublic void run() {long total=entity.getTotal()/(1024*1024*1024);long used =entity.getUsed()/(1024*1024*1024);int process=(int)(used*100/total);mSpace.setText(used+"GB/"+total+"GB");mProgress.setProgress(process);}});}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"><ImageViewandroid:id="@+id/touxiang"android:layout_width="100dp"android:layout_height="78dp"android:src="@mipmap/swan_app_user_portrait_pressed"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintTop_toTopOf="parent"/><TextViewandroid:id="@+id/user_id"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="5dp"android:text="移动开发"android:textColor="#000"android:textSize="20sp"app:layout_constraintTop_toTopOf="parent"app:layout_constraintLeft_toRightOf="@+id/touxiang"/><ImageViewandroid:id="@+id/mVip"android:layout_width="wrap_content"android:layout_height="wrap_content"app:layout_constraintTop_toTopOf="parent"app:layout_constraintLeft_toRightOf="@+id/user_id"android:src="@mipmap/home_identity_common" /><ProgressBarandroid:id="@+id/pro"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_marginLeft="10dp"app:layout_constraintLeft_toRightOf="@+id/touxiang"app:layout_constraintTop_toBottomOf="@id/user_id"app:layout_constraintRight_toRightOf="parent"style="@style/Widget.AppCompat.ProgressBar.Horizontal"/><TextViewandroid:id="@+id/mSpace"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="10dp"android:text="668GB/3220GB"app:layout_constraintLeft_toRightOf="@+id/touxiang"app:layout_constraintTop_toBottomOf="@+id/pro"/><GridViewandroid:id="@+id/grid_view"android:layout_width="match_parent"android:layout_height="0dp"android:numColumns="4"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintTop_toBottomOf="@+id/touxiang"app:layout_constraintVertical_bias="0.0"tools:layout_editor_absoluteX="1dp" /></androidx.constraintlayout.widget.ConstraintLayout>

如:

从上面的代码可以知道
网盘容量的获取方法与用户相同。(请求正确网址+创建正确实体类+更新ui)

先是文件列表的实体类

import java.util.List;public class FileListEntity {/*** cursor : 5* errmsg : succ* errno : 0* has_more : 1* list : [{"category":4,"fs_id":30995775581277,"isdir":0,"local_ctime":1547097900,"local_mtime":1547097900,"md5":"540b49455n2f04f55c3929eb8b0c0445","path":"/测试目录/20160820.txt","server_ctime":1578310087,"server_filename":"20160820.txt","server_mtime":1596078161,"size":1120,"thumbs":{"url1":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c140_u90&quality=100","url2":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c360_u270&quality=100","url3":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c850_u580&quality=100"}},{"category":4,"fs_id":85001194198278,"isdir":0,"local_ctime":1547097899,"local_mtime":1547097899,"md5":"25319465flf30b76c4032ef358446f91","path":"/测试目录/20160907.txt","server_ctime":1578309734,"server_filename":"20160907.txt","server_mtime":1596078163,"size":3480,"thumbs":{"url1":"https://thumbnail0.baidupcs.com/thumbnail/25319465flf30b76c4032ef358446f91?fid=2082810368-250528-85001194198278&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-q5Zan3NIaWpCaD6Qq6kyaiuVMZ4%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316600199584700&dp-callid=0&time=1596092400&size=c140_u90&quality=100","url2":"https://thumbnail0.baidupcs.com/thumbnail/25319465flf30b76c4032ef358446f91?fid=2082810368-250528-85001194198278&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-q5Zan3NIaWpCaD6Qq6kyaiuVMZ4%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316600199584700&dp-callid=0&time=1596092400&size=c360_u270&quality=100","url3":"https://thumbnail0.baidupcs.com/thumbnail/25319465flf30b76c4032ef358446f91?fid=2082810368-250528-85001194198278&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-q5Zan3NIaWpCaD6Qq6kyaiuVMZ4%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316600199584700&dp-callid=0&time=1596092400&size=c850_u580&quality=100"}},{"category":4,"fs_id":231830464480934,"isdir":0,"local_ctime":1547097898,"local_mtime":1547097898,"md5":"08f596c15n1bd3fa383af69d4a0b677f","path":"/测试目录/20160906.txt","server_ctime":1578309734,"server_filename":"20160906.txt","server_mtime":1596078162,"size":5568,"thumbs":{"url1":"https://thumbnail0.baidupcs.com/thumbnail/08f596c15n1bd3fa383af69d4a0b677f?fid=2082810368-250528-231830464480934&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-rxqXy8qFeG7VFWj0B%2B1v8%2BeKfss%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316660217540833&dp-callid=0&time=1596092400&size=c140_u90&quality=100","url2":"https://thumbnail0.baidupcs.com/thumbnail/08f596c15n1bd3fa383af69d4a0b677f?fid=2082810368-250528-231830464480934&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-rxqXy8qFeG7VFWj0B%2B1v8%2BeKfss%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316660217540833&dp-callid=0&time=1596092400&size=c360_u270&quality=100","url3":"https://thumbnail0.baidupcs.com/thumbnail/08f596c15n1bd3fa383af69d4a0b677f?fid=2082810368-250528-231830464480934&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-rxqXy8qFeG7VFWj0B%2B1v8%2BeKfss%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316660217540833&dp-callid=0&time=1596092400&size=c850_u580&quality=100"}},{"category":1,"fs_id":372974889986706,"isdir":0,"local_ctime":1472733116,"local_mtime":1472729122,"md5":"addc44e2d26154ba44a41915d2b4270f","path":"/测试目录/test.mp4","server_ctime":1472733116,"server_filename":"test.mp4","server_mtime":1595921251,"size":47761278,"thumbs":{"icon":"https://thumbnail0.baidupcs.com/thumbnail/addc44e2d26154ba44a41915d2b4270f?fid=2082810368-250528-372974889986706&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-oQ6l5FPEK8mSVzyU21BN%2F6e0bwg%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316708114546127&dp-callid=0&time=1596092400&size=c60_u60&quality=100&vuk=2082810368&ft=video","url1":"https://thumbnail0.baidupcs.com/thumbnail/addc44e2d26154ba44a41915d2b4270f?fid=2082810368-250528-372974889986706&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-oQ6l5FPEK8mSVzyU21BN%2F6e0bwg%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316708114546127&dp-callid=0&time=1596092400&size=c140_u90&quality=100&vuk=2082810368&ft=video","url2":"https://thumbnail0.baidupcs.com/thumbnail/addc44e2d26154ba44a41915d2b4270f?fid=2082810368-250528-372974889986706&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-oQ6l5FPEK8mSVzyU21BN%2F6e0bwg%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316708114546127&dp-callid=0&time=1596092400&size=c360_u270&quality=100&vuk=2082810368&ft=video","url3":"https://thumbnail0.baidupcs.com/thumbnail/addc44e2d26154ba44a41915d2b4270f?fid=2082810368-250528-372974889986706&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-oQ6l5FPEK8mSVzyU21BN%2F6e0bwg%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316708114546127&dp-callid=0&time=1596092400&size=c850_u580&quality=100&vuk=2082810368&ft=video"}},{"category":4,"fs_id":376509117714123,"isdir":0,"local_ctime":1547097902,"local_mtime":1547097902,"md5":"b048a8fb7mfdfafbf1fba286228c4dc6","path":"/测试目录/20160825.txt","server_ctime":1578310092,"server_filename":"20160825.txt","server_mtime":1596077685,"size":3480,"thumbs":{"url1":"https://thumbnail0.baidupcs.com/thumbnail/b048a8fb7mfdfafbf1fba286228c4dc6?fid=2082810368-250528-376509117714123&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-HW3JtBFisIj8n8f8p52pJVxFCcM%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316759458944734&dp-callid=0&time=1596092400&size=c140_u90&quality=100","url2":"https://thumbnail0.baidupcs.com/thumbnail/b048a8fb7mfdfafbf1fba286228c4dc6?fid=2082810368-250528-376509117714123&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-HW3JtBFisIj8n8f8p52pJVxFCcM%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316759458944734&dp-callid=0&time=1596092400&size=c360_u270&quality=100","url3":"https://thumbnail0.baidupcs.com/thumbnail/b048a8fb7mfdfafbf1fba286228c4dc6?fid=2082810368-250528-376509117714123&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-HW3JtBFisIj8n8f8p52pJVxFCcM%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316759458944734&dp-callid=0&time=1596092400&size=c850_u580&quality=100"}}]* request_id : 4194083114842583994*/private int cursor;private String errmsg;private int errno;private int has_more;private String request_id;private List<ListBean> list;public int getCursor() {return cursor;}public void setCursor(int cursor) {this.cursor = cursor;}public String getErrmsg() {return errmsg;}public void setErrmsg(String errmsg) {this.errmsg = errmsg;}public int getErrno() {return errno;}public void setErrno(int errno) {this.errno = errno;}public int getHas_more() {return has_more;}public void setHas_more(int has_more) {this.has_more = has_more;}public String getRequest_id() {return request_id;}public void setRequest_id(String request_id) {this.request_id = request_id;}public List<ListBean> getList() {return list;}public void setList(List<ListBean> list) {this.list = list;}public static class ListBean {/*** category : 4* fs_id : 30995775581277* isdir : 0* local_ctime : 1547097900* local_mtime : 1547097900* md5 : 540b49455n2f04f55c3929eb8b0c0445* path : /测试目录/20160820.txt* server_ctime : 1578310087* server_filename : 20160820.txt* server_mtime : 1596078161* size : 1120* thumbs : {"url1":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c140_u90&quality=100","url2":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c360_u270&quality=100","url3":"https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c850_u580&quality=100"}*/private int category;private long fs_id;private int isdir;private int local_ctime;private int local_mtime;private String md5;private String path;private int server_ctime;private String server_filename;private int server_mtime;private int size;private ThumbsBean thumbs;public int getCategory() {return category;}public void setCategory(int category) {this.category = category;}public long getFs_id() {return fs_id;}public void setFs_id(long fs_id) {this.fs_id = fs_id;}public int getIsdir() {return isdir;}public void setIsdir(int isdir) {this.isdir = isdir;}public int getLocal_ctime() {return local_ctime;}public void setLocal_ctime(int local_ctime) {this.local_ctime = local_ctime;}public int getLocal_mtime() {return local_mtime;}public void setLocal_mtime(int local_mtime) {this.local_mtime = local_mtime;}public String getMd5() {return md5;}public void setMd5(String md5) {this.md5 = md5;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public int getServer_ctime() {return server_ctime;}public void setServer_ctime(int server_ctime) {this.server_ctime = server_ctime;}public String getServer_filename() {return server_filename;}public void setServer_filename(String server_filename) {this.server_filename = server_filename;}public int getServer_mtime() {return server_mtime;}public void setServer_mtime(int server_mtime) {this.server_mtime = server_mtime;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public ThumbsBean getThumbs() {return thumbs;}public void setThumbs(ThumbsBean thumbs) {this.thumbs = thumbs;}public static class ThumbsBean {/*** url1 : https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c140_u90&quality=100* url2 : https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c360_u270&quality=100* url3 : https://thumbnail0.baidupcs.com/thumbnail/540b49455n2f04f55c3929eb8b0c0445?fid=2082810368-250528-30995775581277&rt=pr&sign=FDTAER-DCb740ccc5511e5e8fedcff06b081203-VDkr1qdq%2BXPk79PIL5SHCADhEnk%3D&expires=8h&chkbd=0&chkv=0&dp-logid=4193316540243014694&dp-callid=0&time=1596092400&size=c850_u580&quality=100*/private String url1;private String url2;private String url3;public String getUrl1() {return url1;}public void setUrl1(String url1) {this.url1 = url1;}public String getUrl2() {return url2;}public void setUrl2(String url2) {this.url2 = url2;}public String getUrl3() {return url3;}public void setUrl3(String url3) {this.url3 = url3;}}}
}

然后是修改之前文件页面的一些注释

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.example.baidudisk.R;
import com.example.baidudisk.adapter.FileAdapter;
import com.example.baidudisk.adapter.MyFileAdapter;
import com.example.baidudisk.enity.FileEntity;
import com.example.baidudisk.enity.FileListEntity;
import com.example.baidudisk.intent.NetworkInterfaces;
import com.google.gson.Gson;import org.jetbrains.annotations.NotNull;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;public class FileFragment extends Fragment implements View.OnClickListener {int mLevel = 0;LinearLayout linearLayout;private Handler mHandler;private List<FileEntity> fileEntityList = new ArrayList<>();private List<FileListEntity.ListBean> mFiles = new ArrayList<FileListEntity.ListBean>();FileAdapter mAdapter;String mCurrPath;MyFileAdapter myFileAdapter;private TextView mTip;Stack<String> mPathStack = new Stack<>();RecyclerView mFilesRV;SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");@Nullable@Overridepublic View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_file, container, false);//initFile();mHandler = new Handler();mFilesRV = view.findViewById(R.id.rv_files);mAdapter = new FileAdapter(fileEntityList);myFileAdapter = new MyFileAdapter(mFiles);mTip = view.findViewById(R.id.mTipTv);linearLayout = view.findViewById(R.id.ll_1);linearLayout.setOnClickListener(this);LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());mFilesRV.setLayoutManager(layoutManager);mFilesRV.setAdapter(mAdapter);showExternalFiles();requestPermissions();mAdapter.setListener(new FileAdapter.setOnClickListener() {@Overridepublic void onClick(int position) {if (getActivity() != null && fileEntityList.get(position).type != R.mipmap.file) {mLevel++;mCurrPath = mCurrPath + "/" + fileEntityList.get(position).name;showSubFiles();}}});view.setFocusableInTouchMode(true);view.requestFocus();/*view.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (event.getAction()== KeyEvent.ACTION_DOWN&&keyCode==KeyEvent.KEYCODE_BACK&&mLevel>0){File file =new File(mCurrPath).getParentFile();if(file!=null){mCurrPath=file.getAbsolutePath();mLevel--;showSubFiles();return true;}}return false;}});*/myFileAdapter.setListener(new MyFileAdapter.setOnClickListener() {@Overridepublic void onClick(int position) {if (mFiles.get(position).getIsdir() == 1) {forward(mFiles.get(position).getPath());}}});view.setOnKeyListener(new View.OnKeyListener() {@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) {if (!mPathStack.empty()) {back();return true;}}return false;}});getFileList("/");return view;}/*** 获取权限*/private void requestPermissions() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && getActivity() != null) {if (ContextCompat.checkSelfPermission(getActivity(),Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {//获取权限后的操作} else {requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 0);}}}/*private void initFile() {for (int i=0;i<20;i++){fileEntityList.add(new FileEntity(R.mipmap.ic_gc_main_empty_folder,"新建文件夹"+i,"2020-10-01 00:00"));}}*/@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.ll_1:startActivity(new Intent(getContext(), SearchActivity.class));break;}}private void showExternalFiles() {mCurrPath = Environment.getExternalStorageDirectory().getAbsolutePath();showSubFiles();}private void showSubFiles() {File file = new File(mCurrPath);if (file.exists() && file.isDirectory()) {File[] sub = file.listFiles();if (sub != null) {fileEntityList.clear();for (File f : sub) {fileEntityList.add(new FileEntity(f.isDirectory() ? R.mipmap.ic_gc_main_empty_folder : R.mipmap.file, f.getName(), simpleDateFormat.format(new Date(f.lastModified()))));}} else {fileEntityList.clear();}mAdapter.notifyDataSetChanged();}}private void showLoading() {mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.GONE);mTip.setText("正在加载.......");mTip.setVisibility(View.VISIBLE);}});}private void showResult() {mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.VISIBLE);mTip.setVisibility(View.INVISIBLE);myFileAdapter.notifyDataSetChanged();}});}private void showError() {mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setVisibility(View.GONE);mTip.setVisibility(View.VISIBLE);mTip.setText("获取文件失败");}});}private void getFileList(String path) {showLoading();new NetworkInterfaces().getFileListALL(path, new Callback() {@Overridepublic void onFailure(@NotNull Call call, @NotNull IOException e) {showError();}@Overridepublic void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {FileListEntity entity = new Gson().fromJson(response.body().string(), FileListEntity.class);if (entity.getErrno() == 0) {showFileList(entity.getList());} else {showError();System.out.println(entity.getErrmsg());}}});}private void showFileList(List<FileListEntity.ListBean> beans) {mFiles.clear();mFiles.addAll(beans);mHandler.post(new Runnable() {@Overridepublic void run() {mFilesRV.setAdapter(myFileAdapter);myFileAdapter.notifyDataSetChanged();if (mFiles.isEmpty()) {Toast.makeText(getContext(), "没有文件!", Toast.LENGTH_SHORT).show();} else {showResult();}}});}private void forward(String path) {mCurrPath = path;mPathStack.push(path);getFileList(mCurrPath);}private void back() {mPathStack.pop();if (!mPathStack.empty()) {mCurrPath = mPathStack.peek();mPathStack.pop();} else {mCurrPath = "/";}getFileList(mCurrPath);}}

MyFileAdapter

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;import com.example.baidudisk.R;
import com.example.baidudisk.enity.FileEntity;
import com.example.baidudisk.enity.FileListEntity;import java.util.List;public class MyFileAdapter extends RecyclerView.Adapter<MyFileAdapter.ViewHolder> {public interface setOnClickListener {void onClick(int position);}private List<FileListEntity.ListBean> mFileList;public setOnClickListener myClickListener;public void setListener(setOnClickListener s) {myClickListener = s;}static class ViewHolder extends RecyclerView.ViewHolder {ImageView mFileTypePic;TextView mFileName;TextView mFileCreationDate;LinearLayout mRootLl;public ViewHolder(@NonNull View itemView) {super(itemView);mFileTypePic = itemView.findViewById(R.id.re_pic);mFileName = itemView.findViewById(R.id.re_name);mFileCreationDate = itemView.findViewById(R.id.re_creation_time);mRootLl = itemView.findViewById(R.id.ll_mRootLl);}}public MyFileAdapter(List<FileListEntity.ListBean> filelist) {mFileList = filelist;}@NonNull@Overridepublic ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, int viewType) {View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_file, parent, false);final ViewHolder holder = new ViewHolder(view);return holder;}@Overridepublic void onBindViewHolder(@NonNull ViewHolder holder, final int position) {FileListEntity.ListBean fileEntity = mFileList.get(position);holder.mFileTypePic.setImageResource(R.mipmap.ic_gc_main_empty_folder);holder.mFileName.setText(fileEntity.getServer_filename());holder.mFileCreationDate.setText(""+fileEntity.getLocal_ctime());holder.itemView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {myClickListener.onClick(position);}});}@Overridepublic int getItemCount() {return mFileList.size();}
}

最后就是文件列表的获取,大致方法相同。只是需要注意的是,文件目录的前进与后退,这里我采用了栈来实现。
当是文件时可以进入时,将该文件的路径值进栈,同时在此显示当前文件路径下的内容,后面的也是同理。当退出时,将路径出栈之后,再返回栈顶的元素即是上一级的路径,然后显示,实现一级一级的返回。退到第一级目录时如果再按back键则会退出。

就目前为止,简单的百度api的使用也算完成了。可以继续根据官方文档继续深入研究,通过应用实现百度网盘的内容修改,管理,上传。
我的这篇文章差不多就在这里结束。 over :)

Android实现百度网盘一些功能相关推荐

  1. 大文件下载断点续传后台功能,模仿百度网盘下载功能

    最近项目遇到断点续传下载大文件的需求,网上百度了一下,找到了解决方式,感谢大帝的无私奉献. 为了将网盘下载的效果模仿的更真实,特将原作者的代码完善,本着为小白省下完善代码的时间考虑,写了这篇文章. 原 ...

  2. 百度云android平板,百度网盘hd版本下载-百度网盘hd平板版本下载v11.6.3 安卓官方版-2265安卓网...

    百度网盘hd平板版本是一款由百度推出的网络云盘软件,可以将大家的资料全部上传到云端,不用担心出现文档丢失的情况,而且还能同步手机重要数据,海量的免费空间,让各位可以轻松享受云盘存储的方便之处,而且在平 ...

  3. android系统百度网盘传文件怎么打开,如何将手机百度网盘中下载的文件转移至电脑内...

    如何将手机百度网盘中下载的文件转移至电脑内 当我们在使用手机百度网盘的时候,如果想要将网盘内下载的文件上传至电脑中的话,应如何操作呢?接下来就由小编来告诉大家. 具体如下: 1. 第一步,确认手机和电 ...

  4. 百度网盘VIP功能免费用!官方出品的这个文件管理App,太赞了!

    点击上方"涛哥聊Python",选择"星标"公众号 重磅干货,第一时间送达 小北之前买了个iPad,但不习惯苹果的文件管理,自带的实在是太不好用了. 于是就想起 ...

  5. ThinkPHP实现百度网盘下载功能,必备!

    很多小站应该有需要让用户下载一些东西,比如报名表什么的,前两天看过一个教程,就有利用百度网盘实现自己网站下载的方法,今天就分享出来给大家 <?php/*将本代码保存为bd.php 即可 利用 f ...

  6. 百度网盘 | 爱奇艺万能播放器与百度网盘的功能关联体验

    文章目录 百度网盘与爱奇艺万能播放器 百度网盘 爱奇艺万能播放器 关联使用 百度网盘与爱奇艺万能播放器 可能大家心中都有一个疑问,百度网盘与爱奇艺万能播放器这两个能有啥关系? 这就不得不提一下 百度 ...

  7. php 百度网盘功能,ThinkPHP实现百度网盘下载功能,必备!

    很多小站应该有需要让用户下载一些东西,比如报名表什么的,前两天看过一个教程,就有利用百度网盘实现自己网站下载的方法,今天就分享出来给大家 /*将本代码保存为bd.php 即可 利用 file_get_ ...

  8. 软件测试,面试题——百度网盘基本功能测试用例

  9. C语言线程池实现并行下载上传,匹配百度网盘功能

    1:数据库的设计与框架大纲 百度网盘的功能实现,肯定是需要借助数据库存储文件信息,和用户信息的,以及多点下载和反向代理.负载均衡.打算手撕一波百度网盘,来作为我的毕设项目. 设计的主要关键点在于数据库 ...

最新文章

  1. matlab 全局变量
  2. 软件项目开发计划书【申明:来源于网络】
  3. linux 压缩和解压缩(zip/unzip)
  4. mac os x10.9.2 查看进程对应端口
  5. golismero web扫描器
  6. Java 蓝桥杯 数列特征
  7. P2:图像分类:KNN与线性分类器
  8. Spring Boot 框架介绍和使用
  9. 使用PING判断TCP/IP故障
  10. TCP协议中的三次握手和四次挥手(图解)【转】
  11. CPC客户端编写新申请时报错异常来自 HRESULT:0x80040154 (REGDB_E_CLASSNOTREG))
  12. 一维搜索算法——黄金分割法原理与实现
  13. 生成 8 / 16 / 32 位的UUID
  14. 博弈论 斯坦福game theory stanford week 2.0_
  15. mybatis拦截器实现数据脱敏拦截器使用
  16. linux shell tr命令,shell脚本中的tr用法
  17. ROS发布静态tf变换
  18. 如何调用API接口在线生成在微信可用的网址二维码
  19. NTC热敏电阻采集温度
  20. 由失恋而想到的......---飘题万里

热门文章

  1. [leetcode] 213. House Robber II 解题报告
  2. java测试复盘2(2019.8.21)
  3. 减缓衰老,让T细胞染色体“变长”就行,还能提高免疫力|Nature子刊
  4. dicom 脱敏_一种对医疗影像数据进行脱敏处理的方法及系统与流程
  5. GPU图形图像渲染原理
  6. nginx 301 将不带www域名,重定向到www域名
  7. 神经网络与深度学习学习笔记(一)——基本概念
  8. 操作教程:大华摄像头通过GB28181协议注册EasyCVR平台的详细配置
  9. D7100 调节白平衡
  10. 作为一本书,“卷”赢竞争对手的最佳姿势是?