仿微信用户反馈功能实现

来源:互联网 发布:淘宝售后服务内容 编辑:程序博客网 时间:2024/05/21 19:45

现在的项目要增加一个用户反馈功能,由于是临时提出的需求也没有UI设计,就想到参照微信的设计来实现。
先看微信的效果:
这里写图片描述
在web端实现的,开始也想过做在web端这样更灵活,但目前的架构还是传统的纯native应用,这么搞太麻烦,估计要捣鼓一段时间,还是就用android端实现。

功能分析

用户点击添加图片按钮后在手机图片库中选择照片,选定后展示出来,最多选择4张,水平排列,一行不够排两行,就想到GridView结合startActivityForResult+ 线程池来实现。因为是上传图片,最好转变为webp格式,再加上像素压缩处理,可以大大的节省用户流量。

流程:
输入文字->startActivityForResult选择照片->onActivityResult中更新GridView->点击提交->弹出等待提示框->创建文件List,文字保存为txt格式,从GridView中取出图片保存为webp格式->线程池上传文件->上传结束关闭等待提示框。

功能实现

想起来简单做起来的时候才发现很多问题,上传图片时想弹出一个含旋转动画的等待提示框(继承DialogFragment),每个线程执行完后得到执行结果,根据结果设置等待提示框的文字,采用ExecutorService.submit() + future.get()实现时发现一个奇怪的现象:从点击提交到上传结束没有看到等待提示框,后来一步步排查问题发现,ExecutorService.submit()之后就会进入future.get(),get()方法会阻塞UI线程,导致无法弹出提示框;当线程池结束才回到UI线程,此时会先处理之前的任务(弹出等待提示框),但由于线程池结束又调用了DialogFragment的dissmiss()方法,等待提示框很快出现又很快消失了。
好吧,由于没有搞懂线程池浪费了大把时间,代码也白写了,但也让我对线程池加深了认识,这一特性大概几年都不会忘了,于是又重新考虑实现方式。

最终的实现方式是自定义一个线程池,用一个循环执行Runnable。
自定义线程池:

    class MyThreadPool extends ThreadPoolExecutor {        private List<File> fileList;        private MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,                             BlockingQueue<Runnable> workQueue, List<File> files) {            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);            fileList = files;        }        @Override        protected void beforeExecute(Thread t, Runnable r) {            super.beforeExecute(t, r);        }        @Override        protected void afterExecute(Runnable r, Throwable t) {            super.afterExecute(r, t);        }        @Override        protected void terminated() {            super.terminated();            //当调用shutDown()或者shutDownNow()时会触发该方法,关掉等待框            waitingDialog.dismissAllowingStateLoss();            for (File file:fileList){                deleteOldLogcatFile(getApplicationContext(), file.getName());            }            //必须用looper才能在线程中用toast            Looper.prepare();            if (uploadSucc){                Toast.makeText(getApplicationContext(), "上传完成", Toast.LENGTH_LONG).show();            } else{                Toast.makeText(getApplicationContext(), "上传失败!", Toast.LENGTH_LONG).show();            }            Looper.loop();        }    }

自定义的好处是在线程池结束后可以自定义提示信息,在terminated()中删除了旧文件,并根据每个线程结果提示上传成功还是失败。
调用自定义线程

MyThreadPool myThreadPool = new MyThreadPool(2, 4, 1,                TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(fileCount), files);        for (int i = 0; i < fileCount; i++) {            final File file = files.get(i);            Runnable runnable = new Runnable(){                @Override                public void run() {                    int ret = ftpUpload(ftpUrl, fptPort, ftpUserName, ftpPassword, ftpRemotePath, path, file.getName());                    ECMLog.i_ui(CLASS_TAG, "ftpUpload ret: " + ret);                    uploadSucc = ret == FTP_UPLOAD_SUCC;                }            };            myThreadPool.execute(runnable);        }        myThreadPool.shutdown();

还有个效果是点击选择好的图片后放大显示图片,图片下方有个删除图标能删除图片,这也是通过startActivityForResult实现,在onActivityResult中删除GridView中对应图片。

图片处理

startActivityForResult要用两次,一次是添加图片,一次是点击已添加的图片然后重新启动一个activity显示图片,在这个activity中能删除已选择的图片。

图片的压缩处理:onActivityResult拿到图片uri,根据uri得到路径,通过路径加上像素压缩算法得到bitmap,再调用bitmap.compress()得到webp格式的图片文件。

protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (resultCode == RESULT_OK && requestCode == REQUEST_ADD_PIC) {            Uri uri = data.getData();            String picPath = Utils.getFilePathFromUri(getApplicationContext(), uri);            if (picPath == null){                ContentResolver cr = this.getContentResolver();                try {                    mBitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));                } catch (FileNotFoundException e) {                    e.printStackTrace();                }            }else {                mBitmap = Utils.getSmallBitmap(picPath, 480, 800);            }            //加到第一个            mGridViewUris.add(0, uri);            mGridViewDatas.add(0, mBitmap);            mGridViewAdapter=new GridViewAdapter(getApplication(), mGridViewDatas, MAX_UPLOAD_PIC);            mGridView.setAdapter(mGridViewAdapter);            mGridViewAdapter.notifyDataSetChanged();        }else if (resultCode == RESULT_OK && requestCode == REQUEST_SHOW_PIC){            int position = data.getIntExtra(PIC_POSITION, 0);            mGridViewDatas.remove(position);            mGridViewUris.remove(position);            mGridViewAdapter=new GridViewAdapter(getApplication(), mGridViewDatas, MAX_UPLOAD_PIC);            mGridView.setAdapter(mGridViewAdapter);            mGridViewAdapter.notifyDataSetChanged();        }        //包含添加图片        int totalPictures = mGridViewDatas.size();        currentPicTV.setText(String.valueOf(totalPictures - 1));    }public static String getFilePathFromUri(final Context context, final Uri uri) {//        final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;        // DocumentProvider        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {            if (DocumentsContract.isDocumentUri(context, uri)) {                // ExternalStorageProvider                if (isExternalStorageDocument(uri)) {                    final String docId = DocumentsContract.getDocumentId(uri);                    final String[] split = docId.split(":");                    final String type = split[0];                    if ("primary".equalsIgnoreCase(type)) {                        return Environment.getExternalStorageDirectory() + "/" + split[1];                    }                }                // DownloadsProvider                else if (isDownloadsDocument(uri)) {                    final String id = DocumentsContract.getDocumentId(uri);                    final Uri contentUri = ContentUris.withAppendedId(                            Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));                    return getDataColumn(context, contentUri, null, null);                }                // MediaProvider                else if (isMediaDocument(uri)) {                    final String docId = DocumentsContract.getDocumentId(uri);                    final String[] split = docId.split(":");                    final String type = split[0];                    Uri contentUri = null;                    if ("image".equals(type)) {                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;                    } else if ("video".equals(type)) {                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;                    } else if ("audio".equals(type)) {                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;                    }                    final String selection = "_id=?";                    final String[] selectionArgs = new String[] { split[1] };                    return getDataColumn(context, contentUri, selection, selectionArgs);                }            } else if ("content".equalsIgnoreCase(uri.getScheme())) {                // Return the remote address                if (isGooglePhotosUri(uri))                    return uri.getLastPathSegment();                return getDataColumn(context, uri, null, null);            } else if ("file".equalsIgnoreCase(uri.getScheme())) {                return uri.getPath();            }        }        return null;    }//根据路径获得图片并压缩,返回bitmap用于显示    public static Bitmap getSmallBitmap(String filePath, int reqWidth, int reqHeight) {        final BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = true;        BitmapFactory.decodeFile(filePath, options);//        options.inSampleSize = calculateInSampleSize(options, 480, 800);        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);        options.inJustDecodeBounds = false;        return BitmapFactory.decodeFile(filePath, options);    }    //计算图片的缩放值    private static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {        final int height = options.outHeight;        final int width = options.outWidth;        int inSampleSize = 1;        if (height > reqHeight || width > reqWidth) {            final int heightRatio = Math.round((float) height/ (float) reqHeight);            final int widthRatio = Math.round((float) width / (float) reqWidth);            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;        }        return inSampleSize;    }

通过以上方式,一个截图文件原始大小300KB,被压缩到10KB。

下面是完整代码
自定义GridView适配器:

package com.cetcs.ecmapplication.innerclass;import android.app.Application;import android.graphics.Bitmap;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.RelativeLayout;import com.cetcs.ecmapplication.R;import com.cetcs.ecmcommon.ECMLog;import com.cetcs.ecmcommon.GlobalData;import java.util.List;public class GridViewAdapter extends BaseAdapter {    private String CLASS_TAG = getClass().getCanonicalName();    private List<Bitmap> mList;    LayoutInflater mLayoutInflater;    private ImageView mImageView;    private Application mAppllication;    private int mSize;    public GridViewAdapter(Application application, List<Bitmap> list, int size){        mAppllication = application;        mList = list;        mLayoutInflater = LayoutInflater.from(application);        mSize = size;    }    @Override    public int getCount() {        return mList.size();    }    @Override    public Object getItem(int position) {        return mList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        ECMLog.i_ui(CLASS_TAG, "position: " + position + " mList size: " + mList.size());        convertView = mLayoutInflater.inflate(R.layout.gridviewlayout, null);        mImageView = (ImageView) convertView.findViewById(R.id.ItemImage);        mImageView.setImageBitmap(mList.get(position));        GlobalData globalData = (GlobalData) mAppllication;        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mImageView.getLayoutParams();        layoutParams.height = 240 * globalData.mScreenHeight / 1920;        layoutParams.width = 240 * globalData.mScreenWidth / 1080;        mImageView.setLayoutParams(layoutParams);        return convertView;    }}

gridviewlayout.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_height="wrap_content"    android:paddingBottom="4dip" android:layout_width="fill_parent">    <ImageView        android:layout_height="wrap_content"        android:id="@+id/ItemImage"        android:layout_width="wrap_content"        android:layout_centerHorizontal="true">    </ImageView></RelativeLayout>

activity的layout
activity_feedback.xml:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    xmlns:RoundCornerTextView="http://schemas.android.com/apk/res-auto"    android:id="@+id/activity_feedback"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:paddingBottom="@dimen/activity_vertical_margin"    android:paddingTop="@dimen/activity_vertical_margin"    android:background="#f0f0f0"    tools:context="com.cetcs.ecmapplication.FeedbackActivity">    <TextView        android:id="@+id/titleTV"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="反馈和意见"        android:layout_marginStart="10dp"        android:layout_marginBottom="10dp"        />    <RelativeLayout        android:id="@+id/textviewLayout"        android:layout_below="@id/titleTV"        android:layout_width="match_parent"        android:background="@color/white"        android:layout_height="wrap_content">        <EditText            android:id="@+id/feedbackET"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:hint="请填写10个以上的问题描述"            android:background="@color/white"            android:paddingStart="10dp"            android:paddingEnd="10dp" />        <TextView            android:id="@+id/allowedTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentBottom="true"            android:layout_alignParentEnd="true"            android:layout_marginEnd="10dp"            android:text="/200"/>        <TextView            android:id="@+id/currentNumberTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentBottom="true"            android:layout_toStartOf="@id/allowedTV"            android:text="0"/>    </RelativeLayout>    <RelativeLayout        android:id="@+id/pictureLayout"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="@color/white"        android:paddingTop="10dp"        android:paddingBottom="10dp"        android:layout_below="@id/textviewLayout">        <TextView            android:id="@+id/pictureTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginStart="10dp"            android:textColor="@color/black"            android:text="图片(问题截图,选填)"/>        <TextView            android:id="@+id/allowedPicTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentEnd="true"            android:layout_marginEnd="10dp"            android:text="/4"/>        <TextView            android:id="@+id/currentPicTV"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_toStartOf="@id/allowedPicTV"            android:text="0"/>        <GridView            android:id="@+id/gridview"            android:layout_marginTop="10dp"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_below="@id/pictureTV"            android:numColumns="3"            android:verticalSpacing="10dp"            android:horizontalSpacing="10dp"            android:columnWidth="90dp"            android:stretchMode="columnWidth"            android:gravity="center">        </GridView>    </RelativeLayout>    <TextView        android:id="@+id/telTV"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/pictureLayout"        android:layout_marginTop="10dp"        android:layout_marginBottom="10dp"        android:text="联系电话"        android:layout_marginStart="10dp"        />    <EditText        android:id="@+id/telET"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_below="@id/telTV"        android:background="@color/white"        android:paddingStart="10dp"        android:paddingEnd="10dp"        android:hint="选填"/>    <!--自定义控件,圆角button-->    <acxingyun.cetcs.com.roundconertextview.RoundConerTextView        android:id="@+id/submitBT"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerHorizontal="true"        android:layout_marginTop="10dp"        android:layout_marginBottom="10dp"        android:layout_marginStart="10dp"        android:layout_marginEnd="10dp"        RoundCornerTextView:Text="@string/tijiao"        RoundCornerTextView:BackgroundColor="@color/roundconerunpressed"        RoundCornerTextView:ConerRadius="5dp"        RoundCornerTextView:TextColor="@android:color/white"        RoundCornerTextView:pressedColor="@color/finish_pressed"        RoundCornerTextView:unPressedColor="@color/finish_unpressed"        /></RelativeLayout>

FeedbackActivity

package com.cetcs.ecmapplication;import android.content.ContentResolver;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.net.Uri;import android.os.Bundle;import android.os.Looper;import android.text.Editable;import android.text.TextWatcher;import android.view.KeyEvent;import android.view.View;import android.view.Window;import android.widget.AdapterView;import android.widget.EditText;import android.widget.GridView;import android.widget.RelativeLayout;import android.widget.TextView;import android.widget.Toast;import com.cetcs.ecmapplication.dialog.WaitingDialog;import com.cetcs.ecmapplication.innerclass.GridViewAdapter;import com.cetcs.ecmcommon.ECMActivity;import com.cetcs.ecmcommon.ECMLog;import com.cetcs.ecmcommon.GlobalData;import com.cetcs.ecmcommon.Utils;import com.cetcs.jniencardmanager.JniCardLoginedInfo;import com.cetcs.jniencardmanager.JniCardUnloginInfo;import com.cetcs.jniencardmanager.JniEnCardManager;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.Locale;import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import acxingyun.cetcs.com.roundconertextview.RoundConerTextView;import static android.util.TypedValue.COMPLEX_UNIT_PX;import static com.cetcs.ecmcommon.Constants.FTP_UPLOAD_SUCC;import static com.cetcs.logreport.LogcatUploaderUtils.appendStringToFile;import static com.cetcs.logreport.LogcatUploaderUtils.deleteOldLogcatFile;import static com.cetcs.logreport.LogcatUploaderUtils.ftpUpload;import static com.cetcs.logreport.LogcatUploaderUtils.writeStringToFile;public class FeedbackActivity extends ECMActivity {    private final String CLASS_TAG = this.getClass().getSimpleName();    private RelativeLayout textviewLayout;    private RelativeLayout pictureLayout;    private EditText telET;    private TextView currentPicTV;    private RoundConerTextView submitBT;    private EditText feedbackET;    private TextWatcher watcher;    private TextView currentNumberTV;    private List<Bitmap> mGridViewDatas;    private List<Uri> mGridViewUris;    private GridView mGridView;    private GridViewAdapter mGridViewAdapter;    private Bitmap mBitmap;    private static int REQUEST_ADD_PIC = 1;    private static int REQUEST_SHOW_PIC = 2;    private static int MAX_UPLOAD_PIC = 4;    private static String SHOW_PIC_URI = "show_pic_full_screen";    private static String PIC_POSITION = "picture_position";    private WaitingDialog waitingDialog;    private static final String ftpUrl = xxxxx.xxxxx.xxxxx;    private static final String fptPort = xxxx;    private static final String ftpUserName = xxxx;    private static final String ftpPassword = xxxx;    private static final String ftpRemotePath = "/aaa/bbb";    private boolean uploadSucc = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);//取消标题栏        setContentView(R.layout.activity_feedback);        initViews();        initLayoutParameters();    }    private void initViews(){        textviewLayout = (RelativeLayout) findViewById(R.id.textviewLayout);        pictureLayout = (RelativeLayout) findViewById(R.id.pictureLayout);        telET = (EditText) findViewById(R.id.telET);        submitBT = (RoundConerTextView) findViewById(R.id.submitBT);        feedbackET = (EditText) findViewById(R.id.feedbackET);        currentNumberTV = (TextView) findViewById(R.id.currentNumberTV);        //监控输入字数        watcher = new TextWatcher() {            @Override            public void onTextChanged(CharSequence s, int start, int before, int count) {                // TODO Auto-generated method stub            }            @Override            public void beforeTextChanged(CharSequence s, int start, int count,                                          int after) {                // TODO Auto-generated method stub            }            @Override            public void afterTextChanged(Editable s) {                // TODO Auto-generated method stub                int len = feedbackET.getText().length();                ECMLog.i_ui(CLASS_TAG, "onTextChanged len:" + len);                if (len >= 200){                    currentNumberTV.setText(String.valueOf(len));                    currentNumberTV.setTextColor(getResources().getColor(R.color.deep_orange));                }else {                    currentNumberTV.setTextColor(getResources().getColor(R.color.black));                    currentNumberTV.setText(String.valueOf(len));                }            }        };        feedbackET.addTextChangedListener(watcher);        mGridView=(GridView) findViewById(R.id.gridview);        mGridViewDatas = new ArrayList<>();        mGridViewUris = new ArrayList<>();        Bitmap addBitmap = Utils.getInstance().readBitmap(getApplicationContext(), R.drawable.add_pic);        mGridViewDatas.add(0, addBitmap);        mGridViewUris.add(0, new Uri.Builder().build());        mGridViewAdapter = new GridViewAdapter(getApplication(), mGridViewDatas, MAX_UPLOAD_PIC);        mGridView.setAdapter(mGridViewAdapter);        mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {            @Override            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {                int pictureNumber = mGridViewDatas.size();                ECMLog.i_ui(CLASS_TAG,"position: " + position + " pictureNumber: " + pictureNumber);                if (position == pictureNumber - 1){                    if (pictureNumber < MAX_UPLOAD_PIC + 1){                        chosePictureFromPhone();                    }                }else {                    Uri uri = mGridViewUris.get(position);                    Intent intent = new Intent(FeedbackActivity.this, PicShowerActivity.class);                    intent.putExtra(SHOW_PIC_URI, uri.toString());                    intent.putExtra(PIC_POSITION, position);                    startActivityForResult(intent, REQUEST_SHOW_PIC);                }            }        });        submitBT.setOnTouchCallback(new RoundConerTextView.onTouchCallback() {            @Override            public void onRoundTextViewTouched() {                if (feedbackET.getText().length() == 0){                    Toast.makeText(getApplicationContext(), "请输入您的建议", Toast.LENGTH_SHORT).show();                    return;                }                if (feedbackET.getText().length() > 200){                    Toast.makeText(getApplicationContext(), "请输入200字以内建议", Toast.LENGTH_SHORT).show();                    return;                }                waitingDialog = new WaitingDialog();                waitingDialog.setCancelable(false);                waitingDialog.show(getFragmentManager(), getString(R.string.zhengzaishangchaunqingshaohou));                List<File> list = creatFilesThread();                if (list == null){                    waitingDialog.dismissAllowingStateLoss();                    Toast.makeText(getApplicationContext(), "网络不可用!", Toast.LENGTH_SHORT).show();                    return;                }                ExecutorServiceThread(list);            }        });    }    private void initLayoutParameters(){        GlobalData globalDate = (GlobalData) getApplication();        RelativeLayout.LayoutParams layoutparam = (RelativeLayout.LayoutParams) textviewLayout.getLayoutParams();        layoutparam.height = 350 * globalDate.mScreenHeight / 1920;        textviewLayout.setLayoutParams(layoutparam);        //反馈和意见        TextView titleTV = (TextView) findViewById(R.id.titleTV);        titleTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        //反馈文字        feedbackET = (EditText) findViewById(R.id.feedbackET);        feedbackET.setTextSize(COMPLEX_UNIT_PX, 50 * globalDate.mScreenHeight / 1920);        //200        TextView allowedTV = (TextView) findViewById(R.id.allowedTV);        allowedTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        //字数        TextView currentNumberTV = (TextView) findViewById(R.id.currentNumberTV);        currentNumberTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        layoutparam = (RelativeLayout.LayoutParams) pictureLayout.getLayoutParams();        layoutparam.height = 430 * globalDate.mScreenHeight / 1920;        layoutparam.topMargin = 60 * globalDate.mScreenHeight / 1920;        pictureLayout.setLayoutParams(layoutparam);        TextView pictureTV = (TextView) findViewById(R.id.pictureTV);        pictureTV.setTextSize(COMPLEX_UNIT_PX, 46 * globalDate.mScreenHeight / 1920);        TextView allowedPicTV = (TextView) findViewById(R.id.allowedPicTV);        allowedPicTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        currentPicTV = (TextView) findViewById(R.id.currentPicTV);        currentPicTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        TextView telTV = (TextView) findViewById(R.id.telTV);        telTV.setTextSize(COMPLEX_UNIT_PX, 40 * globalDate.mScreenHeight / 1920);        telET = (EditText) findViewById(R.id.telET);        telET.setTextSize(COMPLEX_UNIT_PX, 50 * globalDate.mScreenHeight / 1920);        layoutparam = (RelativeLayout.LayoutParams) telET.getLayoutParams();        layoutparam.height = 128 * globalDate.mScreenHeight / 1920;        telET.setLayoutParams(layoutparam);        if (globalDate.getChannelName().equals("westone")){            submitBT.setBackgroundColor(getResources().getColor(R.color.westonewanchengzhengchang));            submitBT.setPressedColor(getResources().getColor(R.color.westonewanchengdianji));            submitBT.setUnPressedColor(getResources().getColor(R.color.westonewanchengzhengchang));        }        submitBT.setWidth(990 * globalDate.mScreenWidth / 1080);        submitBT.setHeight(135 * globalDate.mScreenHeight / 1920);        submitBT.setTextSize(60 * globalDate.mScreenHeight / 1920);        submitBT.invalidate();    }    private void chosePictureFromPhone(){        Intent intent = new Intent();        /* 开启Pictures画面Type设定为image */        intent.setType("image/*");        /* 使用Intent.ACTION_GET_CONTENT这个Action */        intent.setAction(Intent.ACTION_GET_CONTENT);        /* 取得相片后返回本画面 */        startActivityForResult(intent, REQUEST_ADD_PIC);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (resultCode == RESULT_OK && requestCode == REQUEST_ADD_PIC) {            Uri uri = data.getData();            String picPath = Utils.getFilePathFromUri(getApplicationContext(), uri);            if (picPath == null){                ContentResolver cr = this.getContentResolver();                try {                    mBitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));                } catch (FileNotFoundException e) {                    e.printStackTrace();                }            }else {                mBitmap = Utils.getSmallBitmap(picPath, 480, 800);            }            //加到第一个            mGridViewUris.add(0, uri);            mGridViewDatas.add(0, mBitmap);            mGridViewAdapter=new GridViewAdapter(getApplication(), mGridViewDatas, MAX_UPLOAD_PIC);            mGridView.setAdapter(mGridViewAdapter);            mGridViewAdapter.notifyDataSetChanged();        }else if (resultCode == RESULT_OK && requestCode == REQUEST_SHOW_PIC){            int position = data.getIntExtra(PIC_POSITION, 0);            mGridViewDatas.remove(position);            mGridViewUris.remove(position);            mGridViewAdapter=new GridViewAdapter(getApplication(), mGridViewDatas, MAX_UPLOAD_PIC);            mGridView.setAdapter(mGridViewAdapter);            mGridViewAdapter.notifyDataSetChanged();        }        //包含添加图片        int totalPictures = mGridViewDatas.size();        currentPicTV.setText(String.valueOf(totalPictures - 1));    }    private List<File> creatUploadFiles(){        //包含文本、图片        List<File> fileList = new ArrayList<>();        File suggestFile = creatSuggestionFile();        if (suggestFile != null){            String tel = telET.getText().toString();            if (tel.length() > 0){                tel = "\n" + "tel:" + tel;                appendStringToFile(getApplicationContext(), suggestFile.getName(), tel);            }            fileList.add(suggestFile);        }        //不包括添加图片        int picCount = mGridViewDatas.size() - 1;        for (int i = 0;i < picCount;i++){            //phoneNumber_tfNumber_20170101010101_1            String bitmapFileName = getFileName() + "_" + i + ".webp";            Bitmap bitmap = mGridViewDatas.get(i);            File bitmapFile = saveBitmapToFile(bitmap, bitmapFileName);            fileList.add(bitmapFile);        }        return fileList;    }    /**     * phoneNumber_tfNumber_time     * 没有后缀     * @return     */    private String getFileName(){        String fileName;        String phoneNumber = "";        String tfNumber = "";        String time = "";        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());        time = sdf.format(new Date());        ..............        fileName = phoneNumber +"_" + tfNumber +"_" + time;        return fileName;    }    private File creatSuggestionFile(){        String fileName;        fileName = getFileName() + ".txt";        String path = getApplicationContext().getFilesDir().getAbsolutePath();        File file = new File(path, fileName);        //保存String为文件        writeStringToFile(getApplication(), feedbackET.getText().toString(), file.getName());        return file;    }    private File saveBitmapToFile(Bitmap bitmap, String fileName){        String path = getApplicationContext().getFilesDir().getAbsolutePath();        File file = new File(path, fileName);        if(file.exists()){            file.delete();        }        FileOutputStream out;        try{            out = new FileOutputStream(file);            if(bitmap.compress(Bitmap.CompressFormat.WEBP, 50, out))            {                out.flush();                out.close();            }        }        catch (FileNotFoundException e)        {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }        return file;    }    private List<File> creatFilesThread(){        List<File> fileList = null;        ExecutorService cacheThreadExecutor = Executors.newSingleThreadExecutor();        Future<List<File>> future = cacheThreadExecutor.submit(new preUploadTask());        try {            fileList = future.get();        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }        return fileList;    }    private void ExecutorServiceThread(List<File> files) {        final String path = getApplicationContext().getFilesDir().getAbsolutePath();        int fileCount = files.size();        MyThreadPool myThreadPool = new MyThreadPool(2, 4, 1,                TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(fileCount), files);        for (int i = 0; i < fileCount; i++) {            final File file = files.get(i);            Runnable runnable = new Runnable(){                @Override                public void run() {                    int ret = ftpUpload(ftpUrl, fptPort, ftpUserName, ftpPassword, ftpRemotePath, path, file.getName());                    ECMLog.i_ui(CLASS_TAG, "ftpUpload ret: " + ret);                    uploadSucc = ret == FTP_UPLOAD_SUCC;                }            };            myThreadPool.execute(runnable);        }        myThreadPool.shutdown();        }    class preUploadTask implements Callable<List<File>>{        @Override        public List<File> call() throws Exception {            if (!Utils.ping()){                return null;            }            return creatUploadFiles();        }    }    class MyThreadPool extends ThreadPoolExecutor {        private List<File> fileList;        private MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,                             BlockingQueue<Runnable> workQueue, List<File> files) {            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);            fileList = files;        }        @Override        protected void beforeExecute(Thread t, Runnable r) {            super.beforeExecute(t, r);        }        @Override        protected void afterExecute(Runnable r, Throwable t) {            super.afterExecute(r, t);        }        @Override        protected void terminated() {            super.terminated();            //当调用shutDown()或者shutDownNow()时会触发该方法            waitingDialog.dismissAllowingStateLoss();            for (File file:fileList){                deleteOldLogcatFile(getApplicationContext(), file.getName());            }            //必须用looper才能在线程中用toast            Looper.prepare();            if (uploadSucc){                Toast.makeText(getApplicationContext(), "上传完成", Toast.LENGTH_LONG).show();            } else{                Toast.makeText(getApplicationContext(), "上传失败!", Toast.LENGTH_LONG).show();            }            Looper.loop();        }    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        return super.onKeyDown(keyCode, event);    }    @Override    protected void onDestroy() {        if (mBitmap != null &&!mBitmap.isRecycled()){            mBitmap.recycle();            mBitmap = null;        }        mGridView = null;        super.onDestroy();    }/**     * 通过ftp上传文件     * @param url ftp服务器地址 如: 192.168.1.110     * @param port 端口如 : 21     * @param username  登录名     * @param password   密码     * @param remotePath  上到ftp服务器的磁盘路径     * @param fileNamePath  要上传的文件路径     * @param fileName      要上传的文件名     * @return     */    public static int ftpUpload(String url, String port, String username,String password, String remotePath, String fileNamePath,String fileName) {        ECMLog.i_ecm(CLASS_TAG, "ftpUpload called,fileName: " + fileName);        FTPClient ftpClient = new FTPClient();        FileInputStream fis = null;        int result = 0;        try {            ftpClient.setConnectTimeout(5 * 1000);            ftpClient.connect(url, parseInt(port));            ECMLog.i_ecm(CLASS_TAG, "connected...");            boolean loginResult = ftpClient.login(username, password);            int returnCode = ftpClient.getReplyCode();            ECMLog.i_ecm(CLASS_TAG, "ftp returnCode: " + returnCode);            if (loginResult && FTPReply.isPositiveCompletion(returnCode)) {// 如果登录成功                ftpClient.makeDirectory(remotePath);                // 设置上传目录                ftpClient.changeWorkingDirectory(remotePath);                ftpClient.setBufferSize(1024);                if (fileName.endsWith(".png") || fileName.endsWith(".webp") || fileName.endsWith(".jpeg")){                    //上传上去的图片数据格式()一定要写这玩意,不然在服务器就打不开了                    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);                }                ftpClient.setControlEncoding("UTF-8");                ftpClient.enterLocalPassiveMode();                fis = new FileInputStream(fileNamePath + "/" + fileName);                ftpClient.storeFile(fileName, fis);                result = FTP_UPLOAD_SUCC;   //上传成功            } else {// 如果登录失败                result = FTP_LOGIN_ERR;            }        } catch (IOException e) {            ECMLog.e_ecm(CLASS_TAG, "ftp err...");            e.printStackTrace();            result = FTP_CLIENT_ERR;//            throw new RuntimeException("FTP客户端出错!", e);        } finally {            try {                ftpClient.disconnect();            } catch (IOException e) {                e.printStackTrace();            }        }        return result;    }}

展示图片的activity,PicShowerActivity:

package com.cetcs.ecmapplication;import android.content.ContentResolver;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.net.Uri;import android.os.Bundle;import android.view.View;import android.view.Window;import android.widget.ImageView;import android.widget.RelativeLayout;import com.cetcs.ecmapplication.dialog.ActionConfirmActivity;import com.cetcs.ecmcommon.Constants;import com.cetcs.ecmcommon.ECMActivity;import com.cetcs.ecmcommon.ECMLog;import com.cetcs.ecmcommon.GlobalData;import com.cetcs.ecmcommon.Utils;import java.io.FileNotFoundException;import static com.cetcs.ecmcommon.Constants.ACTIONCONFIRM_ACTIVITY_DELETE_PIC;public class PicShowerActivity extends ECMActivity {    private ImageView mShowedIV;    private ImageView mDeleteIV;    private static String SHOW_PIC_URI = "show_pic_full_screen";    private final String CLASS_TAG = this.getClass().getSimpleName();    private static String PIC_POSITION = "picture_position";    private int picPosition;    private Bitmap mBitmap;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ECMLog.i_ui(CLASS_TAG, "onCreate called...");        requestWindowFeature(Window.FEATURE_NO_TITLE);//取消标题栏        setContentView(R.layout.activity_pic_shower);        initViews();        initLayoutParameters();    }    private void initViews(){        mShowedIV = (ImageView) findViewById(R.id.mShowedIV);        mDeleteIV = (ImageView) findViewById(R.id.mDeleteIV);        Intent intent = getIntent();        if (intent != null){            //position            picPosition = intent.getIntExtra(PIC_POSITION, 0);            ECMLog.i_ui(CLASS_TAG, "picPosition: " + picPosition);            //Uri            String uriString = intent.getStringExtra(SHOW_PIC_URI);            Uri uri = Uri.parse(uriString);            mBitmap = null;            String picPath = Utils.getFilePathFromUri(getApplicationContext(), uri);            if (picPath == null){                ContentResolver cr = this.getContentResolver();                try {                    mBitmap = BitmapFactory.decodeStream(cr.openInputStream(uri));                } catch (FileNotFoundException e) {                    e.printStackTrace();                }            }else {                mBitmap = Utils.getSmallBitmap(picPath, 480, 800);            }            mShowedIV.setImageBitmap(mBitmap);        }        mDeleteIV.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent1 = new Intent(PicShowerActivity.this, ActionConfirmActivity.class);                intent1.putExtra(Constants.KEY_INFORMATIONTYPE, ACTIONCONFIRM_ACTIVITY_DELETE_PIC);                intent1.putExtra(Constants.KEY_INFORMATION, getString(R.string.quedingshanchutupian));                startActivityForResult(intent1, ACTIONCONFIRM_ACTIVITY_DELETE_PIC);            }        });        mShowedIV.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                setResult(RESULT_CANCELED);                finish();            }        });    }    private void initLayoutParameters(){        GlobalData globalData = (GlobalData) getApplication();        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mShowedIV.getLayoutParams();        layoutParams.width = 800 * globalData.mScreenWidth / 1080;        layoutParams.height = 1400 * globalData.mScreenHeight / 1920;        mShowedIV.setLayoutParams(layoutParams);        layoutParams = (RelativeLayout.LayoutParams) mDeleteIV.getLayoutParams();        layoutParams.height = 68 * globalData.mScreenHeight / 1920;        layoutParams.width = 68 * globalData.mScreenWidth / 1080;        mDeleteIV.setLayoutParams(layoutParams);    }    @Override    protected void onActivityResult(int requestCode, int resultCode, Intent data) {        if (requestCode == ACTIONCONFIRM_ACTIVITY_DELETE_PIC && resultCode == RESULT_OK){            Intent intent = new Intent();            intent.putExtra(PIC_POSITION, picPosition);            setResult(RESULT_OK, intent);            finish();        }    }    @Override    protected void onDestroy() {        if (!mBitmap.isRecycled()){            mBitmap.recycle();            mBitmap = null;        }        mShowedIV.setImageBitmap(null);        mDeleteIV.setImageBitmap(null);        super.onDestroy();    }}

最终效果

用户反馈页面:
这里写图片描述
查看图片:
这里写图片描述

写这篇文章主要目的还是记录和总结一些开发经验,争取以后每开发一个功能写一篇博客。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信申诉没有好友怎么办 四川电信多余的话费怎么办 四川电信话费多了怎么办 固话冲q币要密码怎么办 手机卡怎么突然没了怎么办 联通话费冲错了怎么办 王卡高额半停机 怎么办 计算机报考在手机上网上支付怎么办 建行app充话费不到账怎么办 币乎账号被骗了怎么办? q币充了想返还怎么办 q币账号充值错了怎么办 淘宝乐充话费没到账怎么办 微信信用卡还款未到账怎么办 登不上qq怎么改qq密码怎么办 qq改不了以前的密码怎么办 qq微信密码都被改了怎么办 qq账号被盗一直改密码怎么办? 2018qq密码忘了怎么办 我qq密码忘记了怎么办 微信怎么办该改密码 微信改密码收不到验证码怎么办 微信不能改密码怎么办 qq钱包被限额了怎么办? 注册战网手机号被使用怎么办 电信充值卡密码刮花了怎么办 油卡充值卡密码刮花了怎么办 电费充值卡密码刮花了怎么办 手机充值卡密码刮坏了怎么办 办中石化油卡怎么办 移动代充q币没到怎么办 电信手机话费充多了怎么办 微信钱包提现提错银行卡怎么办 qq余额提现不了怎么办 qq钱包充错话费了怎么办 苹果账户扣了钱怎么办 苹果平板冲不进去电怎么办 qq红包输了钱怎么办 qq红包实名认证没有银行卡怎么办 扣扣红包发不了怎么办 qb充错账号了怎么办