android实现本地图片上传至服务端,只需几步操作即可实现,下面一起看看。
首先看下效果:
主要代码:
package com.kevin.imageuploadclient.fragment;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.kevin.imageuploadclient.R;
import com.kevin.imageuploadclient.fragment.basic.PictureSelectFragment;
import com.kevin.imageuploadclient.util.Constant;
import java.io.File;
import butterknife.Bind;
import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* 图片上传
*/
public class MainFragment extends PictureSelectFragment {
/** Toolbar */
@Bind(R.id.toolbar)
Toolbar toolbar;
@Bind(R.id.main_frag_picture_iv)
ImageView mPictureIv;
public static MainFragment newInstance() {
return new MainFragment();
}
@Override
protected int getContentViewId() {
return R.layout.fragment_main;
}
@Override
public void initViews(View view) {
initToolbar(toolbar);
}
@Override
public void initEvents() {
// 设置图片点击监听
mPictureIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectPicture();
}
});
// 设置裁剪图片结果监听
setOnPictureSelectedListener(new OnPictureSelectedListener() {
@Override
public void onPictureSelected(Uri fileUri, Bitmap bitmap) {
// mPictureIv.setImageBitmap(bitmap);
String filePath = fileUri.getEncodedPath();
final String imagePath = Uri.decode(filePath);
uploadImage(imagePath);
}
});
}
/**
* 上传图片
* @param imagePath
*/
private void uploadImage(String imagePath) {
new NetworkTask().execute(imagePath);
}
/**
* 访问网络AsyncTask,访问网络在子线程进行并返回主线程通知访问的结果
*/
class NetworkTask extends AsyncTask<String, Integer, String> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected String doInBackground(String... params) {
return doPost(params[0]);
}
@Override
protected void onPostExecute(String result) {
if(!"error".equals(result)) {
Log.i(TAG, "图片地址 " + Constant.BASE_URL + result);
Glide.with(mContext)
.load(Constant.BASE_URL + result)
.into(mPictureIv);
}
}
}
private String doPost(String imagePath) {
OkHttpClient mOkHttpClient = new OkHttpClient();
String result = "error";
MultipartBody.Builder builder = new MultipartBody.Builder();
// 这里演示添加用户ID
// builder.addFormDataPart("userId", "20160519142605");
builder.addFormDataPart("image", imagePath,
RequestBody.create(MediaType.parse("image/jpeg"), new File(imagePath)));
RequestBody requestBody = builder.build();
Request.Builder reqBuilder = new Request.Builder();
Request request = reqBuilder
.url(Constant.BASE_URL + "/uploadimage")
.post(requestBody)
.build();
Log.d(TAG, "请求地址 " + Constant.BASE_URL + "/uploadimage");
try{
Response response = mOkHttpClient.newCall(request).execute();
Log.d(TAG, "响应码 " + response.code());
if (response.isSuccessful()) {
String resultValue = response.body().string();
Log.d(TAG, "响应体 " + resultValue);
return resultValue;
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
MainFragment继承的PictureSelectFragment是一个带有图片的按钮选择器,该类如下:
PictureSelectFragment类:
package com.kevin.imageuploadclient.fragment.basic;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import com.kevin.crop.UCrop;
import com.kevin.imageuploadclient.R;
import com.kevin.imageuploadclient.activity.CropActivity;
import com.kevin.imageuploadclient.view.SelectPicturePopupWindow;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
/**
* 带有图片的选择器按钮
*/
public abstract class PictureSelectFragment extends BaseFragment implements SelectPicturePopupWindow.OnSelectedListener {
private static final int GALLERY_REQUEST_CODE = 0; // 相册选图标记
private static final int CAMERA_REQUEST_CODE = 1; // 相机拍照标记
// 拍照临时图片
private String mTempPhotoPath;
// 剪切后图像文件
private Uri mDestinationUri;
/**
* 选择提示 PopupWindow
*/
private SelectPicturePopupWindow mSelectPicturePopupWindow;
/**
* 图片选择的监听回调
*/
private OnPictureSelectedListener mOnPictureSelectedListener;
/**
* 剪切图片
*/
protected void selectPicture() {
mSelectPicturePopupWindow.showPopupWindow(mActivity);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mDestinationUri = Uri.fromFile(new File(activity.getCacheDir(), "cropImage.jpeg"));
mTempPhotoPath = Environment.getExternalStorageDirectory() + File.separator + "photo.jpeg";//临时相片
mSelectPicturePopupWindow = new SelectPicturePopupWindow(mContext);
mSelectPicturePopupWindow.setOnSelectedListener(this);
}
@Override
public void OnSelected(View v, int position) {
switch (position) {
case 0:
// "拍照"按钮被点击了
takePhoto();
break;
case 1:
// "从相册选择"按钮被点击了
pickFromGallery();
break;
case 2:
// "取消"按钮被点击了
mSelectPicturePopupWindow.dismissPopupWindow();
break;
}
}
/**
* 已完成权限请求时收到的回调。
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_STORAGE_READ_ACCESS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
pickFromGallery();//从相册选择
}
break;
case REQUEST_STORAGE_WRITE_ACCESS_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takePhoto();//拍照
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
/**
* 调起手机拍照功能
*/
private void takePhoto() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN // api16开始添加的权限
&& ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {//权限不够,提示
requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
getString(R.string.permission_write_storage_rationale),
REQUEST_STORAGE_WRITE_ACCESS_PERMISSION);
} else {//有权限则调拍照功能
mSelectPicturePopupWindow.dismissPopupWindow();
Intent takeIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//下面这句指定调用相机拍照后的照片存储的路径
takeIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mTempPhotoPath)));
startActivityForResult(takeIntent, CAMERA_REQUEST_CODE);
}
}
/**
* 选择手机相册的照片
*/
private void pickFromGallery() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN // api16之后需要权限
&& ActivityCompat.checkSelfPermission(mActivity, Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {//权限不够时,提示
requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
getString(R.string.permission_read_storage_rationale),
REQUEST_STORAGE_READ_ACCESS_PERMISSION);
} else {//权限足够,打开手机图库
mSelectPicturePopupWindow.dismissPopupWindow();
Intent pickIntent = new Intent(Intent.ACTION_PICK, null);
// 如果限制上传到服务器的图片类型时可以直接写如:"image/jpeg 、 image/png等的类型"
pickIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(pickIntent, GALLERY_REQUEST_CODE);
}
}
/**
* 回调
* @param requestCode
* @param resultCode
* @param data
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == mActivity.RESULT_OK) {
switch (requestCode) {
case CAMERA_REQUEST_CODE: // 调用相机拍照
File temp = new File(mTempPhotoPath);
startCropActivity(Uri.fromFile(temp));//传入临时相片进行剪切
break;
case GALLERY_REQUEST_CODE: // 直接从相册获取
startCropActivity(data.getData());
break;
case UCrop.REQUEST_CROP: // 裁剪图片结果
handleCropResult(data);
break;
case UCrop.RESULT_ERROR: // 裁剪图片错误
handleCropError(data);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* 裁剪图片方法实现
*
* @param uri
*/
public void startCropActivity(Uri uri) {
UCrop.of(uri, mDestinationUri)
.withAspectRatio(1, 1)
.withMaxResultSize(512, 512)//剪切尺寸
.withTargetActivity(CropActivity.class)
.start(mActivity, this);
}
/**
* 处理剪切成功的返回值
*
* @param result
*/
private void handleCropResult(Intent result) {
deleteTempPhotoFile();
final Uri resultUri = UCrop.getOutput(result);
if (null != resultUri && null != mOnPictureSelectedListener) {
Bitmap bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(mActivity.getContentResolver(), resultUri);//获取剪切后的图片
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
mOnPictureSelectedListener.onPictureSelected(resultUri, bitmap);
} else {
Toast.makeText(mContext, "无法剪切选择图片", Toast.LENGTH_SHORT).show();
}
}
/**
* 处理剪切失败的返回值
*
* @param result
*/
private void handleCropError(Intent result) {
deleteTempPhotoFile();
final Throwable cropError = UCrop.getError(result);
if (cropError != null) {
Log.e(TAG, "handleCropError: ", cropError);
Toast.makeText(mContext, cropError.getMessage(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(mContext, "无法剪切选择图片", Toast.LENGTH_SHORT).show();
}
}
/**
* 删除拍照临时文件
*/
private void deleteTempPhotoFile() {
File tempFile = new File(mTempPhotoPath);
if (tempFile.exists() && tempFile.isFile()) {
tempFile.delete();
}
}
/**
* 设置图片选择的回调监听
*
* @param l
*/
public void setOnPictureSelectedListener(OnPictureSelectedListener l) {
this.mOnPictureSelectedListener = l;
}
/**
* 图片选择的回调接口
*/
public interface OnPictureSelectedListener {
/**
* 图片选择的监听回调
*
* @param fileUri
* @param bitmap
*/
void onPictureSelected(Uri fileUri, Bitmap bitmap);
}
}
BaseFragment是继承Fragment类,在BaseFragment中做了请求权限,还有几个抽象方法:
BaseFragment类:
package com.kevin.imageuploadclient.fragment.basic;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.kevin.imageuploadclient.R;
import butterknife.ButterKnife;
public abstract class BaseFragment extends Fragment {
/** 类标签 */
protected static String TAG = "";
/** 上下文 */
protected Context mContext = null;
/** 依附的Activity */
protected Activity mActivity= null;
private AlertDialog mAlertDialog;
protected static final int REQUEST_STORAGE_READ_ACCESS_PERMISSION = 101;
protected static final int REQUEST_STORAGE_WRITE_ACCESS_PERMISSION = 102;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
TAG = this.getClass().getSimpleName();
mContext = activity;
mActivity = activity;
// LogUtils.i(getFragmentName() + " onAttach()");
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// LogUtils.i(getFragmentName() + " onCreate()");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// LogUtils.i(getFragmentName() + " onCreateView()");
if (getContentViewId() != 0) {
return inflater.inflate(getContentViewId(), null);
} else {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// LogUtils.i(getFragmentName() + " onViewCreated()");
ButterKnife.bind(this, view);
init();
initViews(view);
initData();
initEvents();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// LogUtils.i(getFragmentName() + " onActivityCreated()");
}
@Override
public void onStart() {
super.onStart();
// LogUtils.i(getFragmentName() + " onStart()");
}
@Override
public void onResume() {
super.onResume();
// LogUtils.i(getFragmentName() + " onResume()");
}
@Override
public void onPause() {
super.onPause();
// LogUtils.i(getFragmentName() + " onPause()");
}
@Override
public void onStop() {
super.onStop();
// LogUtils.i(getFragmentName() + " onStop()");
}
@Override
public void onDestroyView() {
super.onDestroyView();
// LogUtils.i(getFragmentName() + " onDestroyView()");
ButterKnife.unbind(this);
}
@Override
public void onDestroy() {
super.onDestroy();
// LogUtils.i(getFragmentName() + " onDestroy()");
}
@Override
public void onDetach() {
super.onDetach();
// LogUtils.i(getFragmentName() + " onDetach()");
}
/**
* 使用Toolbar代替ActionBar
*
* @return void
*/
protected void initToolbar(Toolbar toolbar) {
((AppCompatActivity)mActivity).setSupportActionBar(toolbar);
}
/**
* 使用Toolbar代替ActionBar
*
* @return void
*/
protected void initToolbar(Toolbar toolbar, String title) {
toolbar.setTitle(title);
initToolbar(toolbar);
}
/**
* 请求权限
*
* 如果权限被拒绝过,则提示用户需要权限
*/
protected void requestPermission(final String permission, String rationale, final int requestCode) {
if (shouldShowRequestPermissionRationale(permission)) {
showAlertDialog(getString(R.string.permission_title_rationale), rationale,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermissions(new String[]{permission}, requestCode);
}
}, getString(R.string.label_ok), null, getString(R.string.label_cancel));
} else {
requestPermissions(new String[]{permission}, requestCode);
}
}
/**
* 显示指定标题和信息的对话框
*
* @param title - 标题
* @param message - 信息
* @param onPositiveButtonClickListener - 肯定按钮监听
* @param positiveText - 肯定按钮信息
* @param onNegativeButtonClickListener - 否定按钮监听
* @param negativeText - 否定按钮信息
*/
protected void showAlertDialog(@Nullable String title, @Nullable String message,
@Nullable DialogInterface.OnClickListener onPositiveButtonClickListener,
@NonNull String positiveText,
@Nullable DialogInterface.OnClickListener onNegativeButtonClickListener,
@NonNull String negativeText) {
AlertDialog.Builder builder = new AlertDialog.Builder(mActivity);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton(positiveText, onPositiveButtonClickListener);
builder.setNegativeButton(negativeText, onNegativeButtonClickListener);
mAlertDialog = builder.show();
}
/**
* 获取当前Fragment的名称
* @return
*/
public String getFragmentName(){
return TAG;
}
/** 初始化方法 */
public void init() {}
/** 设置布局 */
protected abstract int getContentViewId();
/** 初始化View的抽象方法 */
public abstract void initViews(View view);
/** 初始化数据 */
protected void initData() {}
/** 初始化事件的抽象方法 */
public abstract void initEvents();
}
同样,图片剪切一样是继承了自己写的,前面图片剪切的方法中的CropActivity类:
package com.kevin.imageuploadclient.activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.Uri;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import com.kevin.crop.UCrop;
import com.kevin.crop.util.BitmapLoadUtils;
import com.kevin.crop.view.CropImageView;
import com.kevin.crop.view.GestureCropImageView;
import com.kevin.crop.view.OverlayView;
import com.kevin.crop.view.TransformImageView;
import com.kevin.crop.view.UCropView;
import com.kevin.imageuploadclient.R;
import com.kevin.imageuploadclient.activity.basic.BaseActivity;
import java.io.OutputStream;
import butterknife.Bind;
public class CropActivity extends BaseActivity {
private static final String TAG = "CropActivity";
@Bind(R.id.toolbar)
Toolbar mToolBar;
@Bind(R.id.weixin_act_ucrop)
UCropView mUCropView;
GestureCropImageView mGestureCropImageView;
OverlayView mOverlayView;
@Bind(R.id.crop_act_save_fab)
FloatingActionButton mSaveFab;
private Uri mOutputUri;
@Override
protected void initContentView() {
setContentView(R.layout.activity_crop);
}
@Override
protected void initViews() {
initToolBar();
mGestureCropImageView = mUCropView.getCropImageView();
mOverlayView = mUCropView.getOverlayView();
// 设置允许缩放
mGestureCropImageView.setScaleEnabled(true);
// 设置禁止旋转
mGestureCropImageView.setRotateEnabled(false);
// 设置剪切后的最大宽度
// mGestureCropImageView.setMaxResultImageSizeX(300);
// 设置剪切后的最大高度
// mGestureCropImageView.setMaxResultImageSizeY(300);
// 设置外部阴影颜色
mOverlayView.setDimmedColor(Color.parseColor("#AA000000"));
// 设置周围阴影是否为椭圆(如果false则为矩形)
mOverlayView.setOvalDimmedLayer(false);
// 设置显示裁剪边框
mOverlayView.setShowCropFrame(true);
// 设置不显示裁剪网格
mOverlayView.setShowCropGrid(false);
final Intent intent = getIntent();
setImageData(intent);
}
/**
* 初始化ToolBar
*/
private void initToolBar() {
mToolBar.setTitle("裁剪图片");
setSupportActionBar(mToolBar);
mToolBar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
}
@Override
protected void initEvents() {
mGestureCropImageView.setTransformImageListener(mImageListener);
mSaveFab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cropAndSaveImage();
}
});
}
private void setImageData(Intent intent) {
Uri inputUri = intent.getParcelableExtra(UCrop.EXTRA_INPUT_URI);
mOutputUri = intent.getParcelableExtra(UCrop.EXTRA_OUTPUT_URI);
if (inputUri != null && mOutputUri != null) {
try {
mGestureCropImageView.setImageUri(inputUri);
} catch (Exception e) {
setResultException(e);
finish();
}
} else {
setResultException(new NullPointerException("Both input and output Uri must be specified"));
finish();
}
// 设置裁剪宽高比
if (intent.getBooleanExtra(UCrop.EXTRA_ASPECT_RATIO_SET, false)) {
float aspectRatioX = intent.getFloatExtra(UCrop.EXTRA_ASPECT_RATIO_X, 0);
float aspectRatioY = intent.getFloatExtra(UCrop.EXTRA_ASPECT_RATIO_Y, 0);
if (aspectRatioX > 0 && aspectRatioY > 0) {
mGestureCropImageView.setTargetAspectRatio(aspectRatioX / aspectRatioY);
} else {
mGestureCropImageView.setTargetAspectRatio(CropImageView.SOURCE_IMAGE_ASPECT_RATIO);
}
}
// 设置裁剪的最大宽高
if (intent.getBooleanExtra(UCrop.EXTRA_MAX_SIZE_SET, false)) {
int maxSizeX = intent.getIntExtra(UCrop.EXTRA_MAX_SIZE_X, 0);
int maxSizeY = intent.getIntExtra(UCrop.EXTRA_MAX_SIZE_Y, 0);
if (maxSizeX > 0 && maxSizeY > 0) {
mGestureCropImageView.setMaxResultImageSizeX(maxSizeX);
mGestureCropImageView.setMaxResultImageSizeY(maxSizeY);
} else {
Log.w(TAG, "EXTRA_MAX_SIZE_X and EXTRA_MAX_SIZE_Y must be greater than 0");
}
}
}
private void cropAndSaveImage() {
OutputStream outputStream = null;
try {
final Bitmap croppedBitmap = mGestureCropImageView.cropImage();
if (croppedBitmap != null) {
outputStream = getContentResolver().openOutputStream(mOutputUri);
croppedBitmap.compress(Bitmap.CompressFormat.JPEG, 85, outputStream);
croppedBitmap.recycle();
setResultUri(mOutputUri, mGestureCropImageView.getTargetAspectRatio());
finish();
} else {
setResultException(new NullPointerException("CropImageView.cropImage() returned null."));
}
} catch (Exception e) {
setResultException(e);
finish();
} finally {
BitmapLoadUtils.close(outputStream);
}
}
private TransformImageView.TransformImageListener mImageListener = new TransformImageView.TransformImageListener() {
@Override
public void onRotate(float currentAngle) {
// setAngleText(currentAngle);
}
@Override
public void onScale(float currentScale) {
// setScaleText(currentScale);
}
@Override
public void onLoadComplete() {
Animation fadeInAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.crop_fade_in);
fadeInAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mUCropView.setVisibility(View.VISIBLE);
mGestureCropImageView.setImageToWrapCropBounds();
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mUCropView.startAnimation(fadeInAnimation);
}
@Override
public void onLoadFailure(Exception e) {
setResultException(e);
finish();
}
};
private void setResultUri(Uri uri, float resultAspectRatio) {
setResult(RESULT_OK, new Intent()
.putExtra(UCrop.EXTRA_OUTPUT_URI, uri)
.putExtra(UCrop.EXTRA_OUTPUT_CROP_ASPECT_RATIO, resultAspectRatio));
}
private void setResultException(Throwable throwable) {
setResult(UCrop.RESULT_ERROR, new Intent().putExtra(UCrop.EXTRA_ERROR, throwable));
}
}
BaseActivity类:
package com.kevin.imageuploadclient.activity.basic;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.ViewConfiguration;
import com.kevin.imageuploadclient.KevinApplication;
import java.lang.reflect.Field;
import butterknife.ButterKnife;
public abstract class BaseActivity extends ActionBarActivity {
protected Context mContext = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
mContext = this;
KevinApplication.getInstance().mActivityStack.addActivity(this);
setOverflowShowingAlways();
super.onCreate(savedInstanceState);
initContentView();
ButterKnife.bind(this);
init();
initViews();
initEvents();
}
/**
* 设置总是显示溢出菜单
*/
private void setOverflowShowingAlways() {
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void onStart() {
super.onStart();
}
@Override
protected void onDestroy() {
super.onDestroy();
ButterKnife.unbind(this);
}
public void finish() {
super.finish();
KevinApplication.getInstance().mActivityStack.removeActivity(this);
}
/**
* 初始化布局
*/
protected abstract void initContentView();
/**
* 初始化
*/
protected void init() {
}
/**
* 初始化View
*/
protected abstract void initViews();
/**
* 初始化事件
*/
protected abstract void initEvents();
}
大家需要的话下面是下载地址,提醒一点,如果你想在客户端跑起来上传图片,必须要启动服务端,服务端的文章在这里,在上一篇的最下面一样附上了下载地址,只需要在客户端修改服务器地址就可以了。