欢迎、登录和主页面间的跳转(2018.10.16)

1. WelcomeActivity

package comi.example.liy.firstbasicproject.ui.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import comi.example.liy.firstbasicproject.R;
import comi.example.liy.firstbasicproject.persist.Settings;

/**
 * Created by liy on 2018-03-12.
 */

public class WelcomeActivity extends Activity {
    private static final String TAG = WelcomeActivity.class.getName();
    private Intent intent;
    private Settings settings;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.v("lfeCycle",TAG+"***"+"onCreate");
        super.onCreate(savedInstanceState);
//        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_welcome);
        settings = Settings.getInstance(this);
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                if(settings.getUserId().equals("")){
                    intent = new Intent(WelcomeActivity.this, LoginActivity.class);
                }else {
                    intent = new Intent(WelcomeActivity.this, MainActivity.class);
                }
                startActivity(intent);
                finish();
            }
        }, 1500);
    }

}

1.1 activity_welcome.xml




1.2 Settings类

package comi.example.liy.firstbasicproject.persist;
import android.content.Context;
import android.content.SharedPreferences;

/**
 * Created by liy on 2017-09-22.
 *1、SharedPreferences只能保存简单类型的数据,例如四种基本类型(int,float,long,boolean)+String。
 *          如果需要存取比较复杂的数据类型比如类或者图像,则需要对这些数据进行编码,通常将其转换成Base64编码,然后将转换后的数据以字符串的形式保存在XML文件中。
 *2、存储对象:
 *      方法一:fastJson/Gson/Jackson将对象转换成字符串,然后再保存。
 *      方法二:ObjectOutputStream将对象转化成流,base64将流转成字符串,然后再保存。
 */

public class Settings {
    private static Settings preferences;
    private static SharedPreferences sharedPreferences;//SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置

    private static final String PREFERENCE = "settings";
    private static final String USER_ID="user_id";//用户工号

    public static Settings getInstance(Context context){
        if(preferences==null){
            preferences=new Settings(context);
        }
        return preferences;
    }

    public Settings(Context context){
        sharedPreferences=context.getSharedPreferences(PREFERENCE,Context.MODE_PRIVATE);
    }

    public synchronized void setUserId(String userId){
        SharedPreferences.Editor editor=sharedPreferences.edit();
        editor.putString(USER_ID,userId);
        editor.commit();
    }
    public synchronized String getUserId(){
        return sharedPreferences.getString(USER_ID,"");
    }

}

2. LoginActivity

package comi.example.liy.firstbasicproject.ui.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.Window;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import comi.example.liy.firstbasicproject.R;
import comi.example.liy.firstbasicproject.management.DataManagement;
import comi.example.liy.firstbasicproject.persist.Settings;
import comi.example.liy.firstbasicproject.tool.ToastUtil;

import static comi.example.liy.firstbasicproject.util.GlobalConstant.CLOSED;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.CONNECT_EXCEPTION;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.EXCEPTION_RESULT_CODE;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.LOGIN_SUCCESS;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.SOCKET_TIMEOUT;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_ERROR;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_HOST;


/**
 * Created by liy on 2018-03-12.
 */
public class LoginActivity extends Activity {
    private static final String TAG = LoginActivity.class.getName();
    private LoginActivity activity;
    private Settings settings;
    public DataManagement dataManagement;
    private Handler handler;

    private ImageView ivSetting;
    private TextView tvUserId;
    private Button btnLogin;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_login);
        initViews();
        initData();
        initHandler();
        initListeners();
    }

    @Override
    public void onBackPressed() {
        //返回手机的主屏幕
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addCategory(Intent.CATEGORY_HOME);
        startActivity(intent);
    }

    private void initViews(){
        ivSetting = (ImageView) findViewById(R.id.activity_login_ivSetting);
        tvUserId= (AutoCompleteTextView)findViewById(R.id.activity_login_tvUserId);
        btnLogin = (Button)findViewById(R.id.activity_login_btnLogin);
    }

    private void initData(){
        activity = this;
        settings = Settings.getInstance(this);
        dataManagement = DataManagement.getFyDataManagement(this);

        tvUserId.setText(settings.getUserId());
    }

    private void initHandler(){
        handler = new Handler(){
            public void handleMessage(Message message) {
                switch (message.what) {
                    case LOGIN_SUCCESS:    //登录成功
                        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                        startActivity(intent);
                        break;
                    case EXCEPTION_RESULT_CODE:    //登录异常结果码
                        Toast.makeText(activity,activity.getString(R.string.error_result_code), Toast.LENGTH_SHORT).show();
                        break;
                    case CLOSED:
                        Toast.makeText(activity,activity.getString(R.string.closed), Toast.LENGTH_SHORT).show();
                        break;
                    case SOCKET_TIMEOUT:
                        Toast.makeText(activity,activity.getString(R.string.SocketTimeoutException), Toast.LENGTH_SHORT).show();
                        break;
                    case CONNECT_EXCEPTION:
                        Toast.makeText(activity,activity.getString(R.string.ConnectException), Toast.LENGTH_SHORT).show();
                        break;
                    case UNKNOWN_HOST:
                        Toast.makeText(activity,activity.getString(R.string.UnknownHostException), Toast.LENGTH_SHORT).show();
                        break;
                    case UNKNOWN_ERROR:
                        Toast.makeText(activity,activity.getString(R.string.UnknownError), Toast.LENGTH_SHORT).show();
                        break;
                    default:
                        break;
                }
                super.handleMessage(message);
            }
        };
    }

    private void initListeners(){
        ivSetting.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(LoginActivity.this,SettingActivity.class);
                startActivity(intent);
            }
        });
        btnLogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String userId = tvUserId.getText().toString();
                if(userId.equals("")){
                    ToastUtil.show(activity,getString(R.string.please_input_userId));
                }else {
                    dataManagement.UserLoginVerify(userId,handler,settings);
                }
            }
        });
    }

    public Handler getHandler() {
        return handler;
    }

}

2.1 activity_login.xml



    
        
    

    

        

            

        

        

            

        

        

2.2 background_shape.xml



    //设置边框内角弧度
    
    //设置边框以内颜色
    
    //设置组件边框
    
    //设置组件里内容距离组件内边缘的间距
    
    

2.3 colors.xml




    #3F51B5
    #303F9F
    #FF4081


    #ffffff
    #77ffffff
    #11ffffff
    #222222
    #99222222
    #cccccc
    #149FEB
    #99149FEB
    #C9D5EB
    #E5EBF5
    #2fba2f


    #ff0000
    #00ff00
    #0000ff
    #000001
    #222222
    #808080
    #f00
    #f5f
    #f44
    #aff
    #ff0
    #077874
    #77ffffff

    #77ffffff

   
    #FFFFFF 
    #FFFFF0 
    #FFFFE0 
    #FFFF00 
    #FFFAFA 
    #FFFAF0 
    #FFFACD 
    #FFF8DC 
    #FFF5EE 
    #FFF0F5 
    #FFEFD5 
    #FFEBCD 
    #FFE4E1 
    #FFE4C4 
    #FFE4B5 
    #FFDEAD 
    #FFDAB9 
    #FFD700 
    #FFC0CB 
    #FFB6C1 
    #FFA500 
    #FFA07A 
    #FF8C00 
    #FF7F50 
    #FF69B4 
    #FF6347 
    #FF4500 
    #FF1493 
    #FF00FF 
    #FF00FF 
    #FF0000 
    #FDF5E6 
    #FAFAD2 
    #FAF0E6 
    #FAEBD7 
    #FA8072 
    #F8F8FF 
    #F5FFFA 
    #F5F5F5 
    #F5F5DC 
    #F5DEB3 
    #F4A460 
    #F0FFFF 
    #F0FFF0 
    #F0F8FF 
    #F0E68C 
    #F08080 
    #EEE8AA 
    #EE82EE 
    #E9967A 
    #E6E6FA 
    #E0FFFF 
    #DEB887 
    #DDA0DD 
    #DCDCDC 
    #DC143C 
    #DB7093 
    #DAA520 
    #DA70D6 
    #D8BFD8 
    #D3D3D3 
    #D3D3D3 
    #D2B48C 
    #D2691E 
    #CD853F 
    #CD5C5C 
    #C71585 
    #C0C0C0 
    #BDB76B 
    #BC8F8F 
    #BA55D3 
    #B8860B 
    #B22222 
    #B0E0E6 
    #B0C4DE 
    #AFEEEE 
    #ADFF2F 
    #ADD8E6 
    #A9A9A9 
    #A9A9A9 
    #A52A2A 
    #A0522D 
    #9932CC 
    #98FB98 
    #9400D3 
    #9370DB 
    #90EE90 
    #8FBC8F 
    #8B4513 
    #8B008B 
    #8B0000 
    #8A2BE2 
    #87CEFA 
    #87CEEB 
    #808080 
    #808080 
    #808000 
    #800080 
    #800000 
    #7FFFD4 
    #7FFF00 
    #7CFC00 
    #7B68EE 
    #778899 
    #778899 
    #708090 
    #708090 
    #6B8E23 
    #6A5ACD 
    #696969 
    #696969 
    #66CDAA 
    #6495ED 
    #5F9EA0 
    #556B2F 
    #4B0082 
    #48D1CC 
    #483D8B 
    #4682B4 
    #4169E1 
    #40E0D0 
    #3CB371 
    #32CD32 
    #2F4F4F 
    #2F4F4F 
    #2E8B57 
    #228B22 
    #20B2AA 
    #1E90FF 
    #191970 
    #00FFFF 
    #00FFFF 
    #00FF7F 
    #00FF00 
    #00FA9A 
    #00CED1 
    #00BFFF 
    #008B8B 
    #008080 
    #008000 
    #006400 
    #0000FF 
    #0000CD 
    #00008B 
    #000080 
    #000000 

    #a8cf8d
    #f7caac
    #bebebe
    #fdd866
    #fd3301

 
    #fdfdfe
    #000001
    #ec1c24
    #fdec01
    #7e7e7f
    #00afef
    #22c4ec
    #5180b9
    #00a1e7
    #00fd01
    #22b04c

    #77ffffff
    #4BAE4F
    #FFCD41
    #6A5ACD
    #DAA520

    #808080



3. MainActivity

package comi.example.liy.firstbasicproject.ui.activity;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import comi.example.liy.firstbasicproject.R;
import comi.example.liy.firstbasicproject.entityClass.TestDate;
import comi.example.liy.firstbasicproject.management.DataManagement;
import comi.example.liy.firstbasicproject.persist.Settings;
import comi.example.liy.firstbasicproject.tool.ToastUtil;
import comi.example.liy.firstbasicproject.ui.fragment.ReworkFragment;
import comi.example.liy.firstbasicproject.ui.fragment.SixSFragment;
import comi.example.liy.firstbasicproject.ui.fragment.WorkFragment;
import comi.example.liy.firstbasicproject.ui.fragment.YieldFragment;

import static comi.example.liy.firstbasicproject.util.GlobalConstant.CLOSED;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.CONNECT_EXCEPTION;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.EXCEPTION_RESULT_CODE;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.LOGOUT_SUCCESS;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.SOCKET_TIMEOUT;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_ERROR;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_HOST;


public class MainActivity extends FragmentActivity {
    private MainActivity activity;
    public DataManagement dataManagement;
    private Settings settings;
    private Handler handler;

    private Button btnOthers;
    private TextView topTitle;
    private Button btnCancellation;

    private boolean activityActive = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
        initData();
        initHandler();
        initListeners();
    }

    @Override
    protected void onRestart() {
        super.onRestart();
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        activityActive = true;
        super.onResume();
    }

    @Override
    protected void onPause() {
        activityActive = false;
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        //返回手机的主屏幕
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addCategory(Intent.CATEGORY_HOME);
        startActivity(intent);
    }

    /**
     * 初始化组件
     */
    private void initViews(){
        btnOthers = (Button)findViewById(R.id.main_top_btnOthers);
        topTitle = (TextView)findViewById(R.id.main_top_tvTitle);
        btnCancellation = (Button)findViewById(R.id.main_top_btnCancellation);
    }

    /**
     * 初始化数据
     */
    private void initData(){
        activity = this;
        settings = Settings.getInstance(this);
        dataManagement = DataManagement.getFyDataManagement(this);
    }

    private void initHandler(){
        handler = new Handler() {
            public void handleMessage(Message msg) {
                if (activityActive) {
                    switch (msg.what) {
                        case SOCKET_TIMEOUT:
                            //连接超时警告框
                            warningDialog(activity.getString(R.string.SocketTimeoutException),activity.getString(R.string.SocketTimeoutException_des));
                            break;
                        case CONNECT_EXCEPTION:
                            //连接失败警告框
                            warningDialog(activity.getString(R.string.ConnectException),activity.getString(R.string.ConnectException_des));
                            break;
                        case UNKNOWN_HOST:
                            //无法解析主机警告框
                            warningDialog(activity.getString(R.string.UnknownHostException),activity.getString(R.string.UnknownHostException_des));
                            break;
                        case UNKNOWN_ERROR:
                            //未知错误警告框
                            warningDialog(activity.getString(R.string.UnknownError),activity.getString(R.string.UnknownError_eds));
                            break;
                        case CLOSED:
                            //主动取消警告框
                            warningDialog(activity.getString(R.string.closed),activity.getString(R.string.closed_des));
                            break;
                        case EXCEPTION_RESULT_CODE:
                            ToastUtil.show(activity,activity.getString(R.string.error_result_code));
                            break;
                        case LOGOUT_SUCCESS:
                            settings.setUserId("");
                            Intent intent =  new Intent(MainActivity.this, LoginActivity.class);
                            intent.putExtra("lastActivityName","MainActivity");
                            startActivity(intent);
                            break;
                        default:
                            break;
                    }
                }

            }
        };
    }

    private void initListeners(){
        btnOthers.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,HomeActivity.class);
                startActivity(intent);
            }
        });

        btnCancellation.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showAccountCancelationDialog();
            }
        });
    }

    public Handler getHandler() {
        return handler;
    }

    /**
     * 账号注销
     */
    private void showAccountCancelationDialog(){
        final AlertDialog.Builder accountCancelationDialog = new AlertDialog.Builder(MainActivity.this);
        accountCancelationDialog.setIcon(R.drawable.ic_acccount);
        accountCancelationDialog.setTitle(R.string.account_cancellation_title);
        accountCancelationDialog.setMessage(R.string.account_cancellation_message);
        accountCancelationDialog.setPositiveButton(R.string.btn_sure,new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dataManagement.UserLogoutVerify(handler);
                    }
                });
        accountCancelationDialog.setNegativeButton(R.string.btn_cancel,new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                });
        accountCancelationDialog.show();// 显示
    }

    /*********************警告或提示类型的弹窗,只起提示作用不做数据处理***************/
    private AlertDialog alertDialog = null;
    public void warningDialog(String title, String message) {
        if(alertDialog == null){
            alertDialog = new AlertDialog.Builder(this,R.style.Theme_AppCompat_Light_Dialog_Alert)
                    .setTitle(title)
                    .setMessage(message)
                    .setPositiveButton(R.string.btn_sure, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {

                        }
                    }).show();
        }else{
            if(alertDialog.isShowing()){

            }else{
                alertDialog.show();
            }
        }
    }

}

3.1 activity_main.xml




    

    
    

    



3.2 activity_main.xml




    

    

3.3 ic_cancellation.xml


    


3.3 activity_main.xml



    主动取消!
    Network request active shutdown
    连接超时!
    Network request connection timeout
    服务器连接失败!
    Network request connection failed
    无法解析主机!
    The network request cannot resolve the host
    未知错误!
    Network request unknown error

4. DataManagement管理类

package comi.example.liy.firstbasicproject.management;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;

import comi.example.liy.firstbasicproject.entityClass.ResponseResult;
import comi.example.liy.firstbasicproject.entityClass.User;
import comi.example.liy.firstbasicproject.persist.Settings;
import comi.example.liy.firstbasicproject.remote.HttpUrl;
import comi.example.liy.firstbasicproject.tool.LoggerUtil;
import comi.example.liy.firstbasicproject.util.GlobalConstant;
import comi.example.liy.firstbasicproject.util.Okhttp;
import okhttp3.FormBody;

import static comi.example.liy.firstbasicproject.util.GlobalConstant.EXCEPTION_RESULT_CODE;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.LOGIN_SUCCESS;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.LOGOUT_SUCCESS;

/**
 * Created by liy on 2018-10-16 8:40
 */
public class DataManagement {
    private static Activity activity;
    private HttpUrl httpUrl;
    private LoggerUtil loggerUtil;
    private GlobalConstant globalConstant;

    private String userId = "";
    private String userName = "";
    private String userDept = "";
    private Settings settings;

    private boolean isTest = true;

    private DataManagement(Context context){
        httpUrl = HttpUrl.getHttpUrl();
        loggerUtil = LoggerUtil.getLoggerUtil();
        globalConstant = GlobalConstant.getGlobalConstant();
        settings = Settings.getInstance(context);
    }

    private static DataManagement dataManagement;
    public static DataManagement getFyDataManagement(final Context context){
        if(dataManagement==null){
            dataManagement = new DataManagement(context);
        }
        activity = (Activity)context;
        return dataManagement;
    }

    /**
     * 用户登录:
     * @param userId
     * @param handler
     * @param settings
     */
    public void UserLoginVerify(final String userId,final Handler handler, final Settings settings){
        if(isTest){
            Message message = new Message();
            message.what = LOGIN_SUCCESS;//登录成功
            handler.sendMessage(message);
            return;
        }
        String loginUrl = httpUrl.fyLoginUrl;
        loggerUtil.v("login_loginUrl",loginUrl);
        Okhttp okhttp = Okhttp.getOkhttp(activity);
        Okhttp.HttpBuilder builder = new Okhttp.HttpBuilder() {
            @Override
            public FormBody.Builder getBuilder() {
                FormBody.Builder builder = new FormBody.Builder();
                builder.add("userId", userId);
                return builder;
            }
        };

        Okhttp.HttpResponse response = new Okhttp.HttpResponse() {
            @Override
            public void onPostFinishedResponse(String response) {
                loggerUtil.v("login_response",response);
            }

            @Override
            public void onPostFinished(Object object) {
                try{
                    User user = (User) object;
                    String result = user.getResult();
                    loggerUtil.v("login_code","结果码"+result);
                    Message message = new Message();
                    if(result.equals("10")){
                        setLoginUserInfo(user,settings);
                        message.what = LOGIN_SUCCESS;//登录成功
                    }else{
                        message.what = EXCEPTION_RESULT_CODE;
                    }
                    handler.sendMessage(message);
                }catch (Exception e){
                    e.printStackTrace();
                    loggerUtil.v("login_error", e.getMessage().toString());
                }
            }
        };
        okhttp.OkhttpPost(loginUrl,builder,User.class,response);

    }

    private void setLoginUserInfo(User user,Settings settings){
        userId = user.getUserId();
        userName = user.getUserName();
        userDept = user.getDepartmentNumber();
        settings.setUserId(user.getUserId());
    }

    /**
     * 用户退出
     * @param handler
     */
    public void UserLogoutVerify(final Handler handler){
        if(isTest){
            Message message = new Message();
            message.what = LOGOUT_SUCCESS;
            handler.sendMessage(message);
            return;
        }
        String fyLogoutUrl = httpUrl.fyLogoutUrl;
        Okhttp okhttp = Okhttp.getOkhttp(activity);
        Okhttp.HttpBuilder builder = new Okhttp.HttpBuilder() {
            @Override
            public FormBody.Builder getBuilder() {
                FormBody.Builder builder = new FormBody.Builder();
                builder.add("userId",userId);
                return builder;
            }
        };

        Okhttp.HttpResponse response = new Okhttp.HttpResponse() {
            @Override
            public void onPostFinishedResponse(String response) {
                loggerUtil.v("logout_response",response);
            }

            @Override
            public void onPostFinished(Object object) {
                ResponseResult responseResult = (ResponseResult)object;
                String result = "";
                if(responseResult!=null){
                    result = responseResult.result;
                }
                loggerUtil.v("logout_result",result);
                if(result.equals("1")){
                    Message message = new Message();
                    message.what = LOGOUT_SUCCESS;
                    handler.sendMessage(message);
                }else {
                    Message message = new Message();
                    message.what = EXCEPTION_RESULT_CODE;
                    handler.sendMessage(message);
                }

            }
        };
        okhttp.OkhttpPost(fyLogoutUrl,builder,ResponseResult.class,response);
    }
}

5. Okhttp封装类

package comi.example.liy.firstbasicproject.util;

import android.content.Context;
import android.os.Message;
import android.util.Log;

import com.google.gson.Gson;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;

import comi.example.liy.firstbasicproject.ui.activity.LoginActivity;
import comi.example.liy.firstbasicproject.ui.activity.MainActivity;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static comi.example.liy.firstbasicproject.util.GlobalConstant.CLOSED;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.CONNECT_EXCEPTION;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.SOCKET_TIMEOUT;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_ERROR;
import static comi.example.liy.firstbasicproject.util.GlobalConstant.UNKNOWN_HOST;

/**
 * Created by liy on 2018-10-16 9:04
 * 网络请求框架:Apache提供的HttpClient、HttpURLConnection(被OkHttp替换)、google推出的Volley框架、android-async-http框架、Xutils、Retrofit
 *
 * json字符串->实体对象
 * 1、Http Get
 * 2、Http Post 携带参数:封装onFailure()和onResponse()方法
 * 3、基于Http的文件上传:支持大文件下载,通过IO的方式写文件
 *
 * OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题
 *OkHttp的一个高效之处在于OkHttp的任务队列在内部维护了一个线程池(线程池最大的好处在于通过线程复用减少非核心任务的损耗),方便高效地执行异步请求
 *特点一:OkHttp采用Dispatcher(作为任务的派发器)技术,类似于Nginx(使用了与Nginx类似的反向代理与分发技术,这是典型的单生产者多消费者问题),与线程池配合实现了高并发,低阻塞的运行
 *特点二:Okhttp采用Deque作为缓存,按照入队的顺序先进先出
 *特点三:OkHttp最出彩的地方就是在try/finally中调用了finished函数,可以主动控制等待队列的移动,而不是采用锁或者wait/notify,极大减少了编码复杂性
 *缺点:OkHttp不支持优先级请求、OkHttp不支持自签名证书、OkHttp header中不能传中文
 */
public class Okhttp {
    private String aa ="";//服务器返回的字符串,如json字符串
    private Object BB = new Object();//服务器回复信息转为类
    private Context activity;
    
    private final OkHttpClient mClinet = new OkHttpClient();
    final ByteArrayOutputStream bos = new ByteArrayOutputStream();

    /**
     * 单例模式
     */
    private static Okhttp mOkhttp;
    private Okhttp(Context activity){
        this.activity = activity;
    }
    //大多数程序只需要调用一次new OkHttp()
    public static Okhttp getOkhttp(Context activity){
        if (mOkhttp==null){
            mOkhttp = new Okhttp(activity);
        }
        mOkhttp.activity = activity;
        return mOkhttp;
    }

    public T OkhttpPost(String path, HttpBuilder HttpBuilder, final Class clazz , final HttpResponse httpRespone){
        //创建okHttpClient对象,OkHttpClient配置包括代理设置、超时设置(连接、读取和写入超时)、缓存设置等
        final OkHttpClient mOkHttpClient=mClinet
                .newBuilder()
                .readTimeout(5000,TimeUnit.MILLISECONDS)
                .connectTimeout(5000,TimeUnit.MILLISECONDS)
                .writeTimeout(5000,TimeUnit.MILLISECONDS)
                .build();
        //创建一个Request:通过Request.Builder设置url(参数最起码有个url)、method、header等参数
        RequestBody formBody = HttpBuilder.getBuilder().build();//MultipartBuilder可以构建复杂的请求体,即RequestBody requestBody = new MultipartBody.Builder()
        final Request request = new Request.Builder().url(path).post(formBody).build();
        //通过request的对象去构造得到一个Call对象(类似于将请求封装成了任务),可调用execute()和cancel()等方法
        Call call = mOkHttpClient.newCall(request);
        //请求加入调度队列,任务执行完成在Callback中即可得到结果:调用call.enqueue以异步的方式去执行请求(调用call.execute以同步阻塞的方式在主线程去执行请求)
        //注意:onFailure()和onResponse()是在异步线程里执行的,所以如果把更新UI的操作写在这两个方法里会报错,这个时候可以用runOnUiThread这个方法
        call.enqueue(new Callback() {
            @Override
            //当取消一个请求(调用cancel()),网络连接错误,或者超时都会回调
            public void onFailure(Call call, IOException e) {
                Log.v("Okhttp_onFailure",call.toString()+","+e.getMessage()+"");
                /*mOkHttpClient.dispatcher().cancelAll();//使用Call.cancel()可以立即停止掉一个正在执行的call*/
                mOkHttpClient.connectionPool().evictAll();//清除并关闭连接池
                try {
                    if(Okhttp.this.activity instanceof MainActivity){
                        MainActivity activity = (MainActivity) Okhttp.this.activity;
                        Message message = new Message();
                        if(e.getMessage().toString().contains("UnknownHostException")||e.getMessage().toString().contains("resolve")){//无法解析主机(1、IP越界)
                            message.what = UNKNOWN_HOST;
                        }else if(e.getMessage().toString().contains("SocketTimeoutException")||e.getMessage().toString().contains("after")){//连接超时(2、IP不越界且服务器已启动)
                            message.what = SOCKET_TIMEOUT;
                        }else if(e.getMessage().toString().contains("ConnectException")||e.getMessage().toString().contains("Failed")){//服务器连接出错(3、IP不越界且服务器未启动)
                            message.what = CONNECT_EXCEPTION;
                        }else if(e.getMessage().toString().contains("closed")||e.getMessage().toString().contains("Canceled")) {//主动取消(测试未遇到到该情况)
                            message.what = CLOSED;
                        }else {
                            message.what = UNKNOWN_ERROR;//其他情况
                        }
                        activity.getHandler().sendMessage(message);
                    }else if(Okhttp.this.activity instanceof LoginActivity){
                        LoginActivity activity = (LoginActivity)Okhttp.this.activity;
                        Message message = new Message();
                        if(e.getMessage().toString().contains("UnknownHostException")||e.getMessage().toString().contains("resolve")){//无法解析主机(1、IP越界)
                            message.what = UNKNOWN_HOST;
                        }else if(e.getMessage().toString().contains("SocketTimeoutException")||e.getMessage().toString().contains("after")){//连接超时(2、IP不越界且服务器已启动)
                            message.what = SOCKET_TIMEOUT;
                        }else if(e.getMessage().toString().contains("ConnectException")||e.getMessage().toString().contains("Failed")){//服务器连接出错(3、IP不越界且服务器未启动)
                            message.what = CONNECT_EXCEPTION;
                        }else if(e.getMessage().toString().contains("closed")||e.getMessage().toString().contains("Canceled")) {//主动取消
                            message.what = CLOSED;
                        }else {
                            message.what = UNKNOWN_ERROR;//其他情况
                        }
                        activity.getHandler().sendMessage(message);
                    }else {
                        Log.v("Okhttp_elseFailure",call.toString()+" "+e.getMessage()+"");
                    }
                }catch (Exception e1){
                    e1.printStackTrace();
                }
            }

            @Override
            //请求成功时回调方法,response就是从服务器得到的参数
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){

                    //response.body()函数获得服务器返回的数据
                    // string()函数用来处理文本数据(传递文本数据),bytes()函数用来处理字节数组(收到小型文件数据,先以字节数据的形式保存在内存中,然后再将其一次性写入文件),byteStream()函数用来处理字节流(下载文件较大时,通过流的形式,将数据保存在文件中)
                    //由于OkHttp封装了okio,所以可以将响应数据通过BufferedSource的形式返回(断点续传功能),即response.body().source()
                    aa = response.body().string();
                    Log.v("Okhttp_response",call.toString()+" "+aa+"");
                    try{
                        httpRespone.onPostFinishedResponse(aa);
                        Gson gson = new Gson();
                        BB = gson.fromJson(aa,clazz);
                        httpRespone.onPostFinished(BB);
                    }catch (Exception e){
                        Log.v("Okhttp_onResponseErr",e.getMessage()+"");
                    }
                }else {
                    Log.v("Okhttp_UnexpectedCode",response+"");
                    throw new IOException("Unexpected code " + response);
                }
                response.close();//无论任何情况都要关闭该对象
            }
        });
        /*Log.v("Okhttp_call.equne",call.toString()+"");*/
        return (T)BB;
    }

    public T OkhttpPost(String path, HttpBuilder httpBuilder, final Type type, final HttpResponse httpRespone, final HttpRequestFail httpRequestFail){
        //创建okHttpClient对象,OkHttpClient配置包括代理设置、超时设置(连接、读取和写入超时)、缓存设置等
        final OkHttpClient mOkHttpClient=mClinet
                .newBuilder()
                .readTimeout(5000,TimeUnit.MILLISECONDS)
                .connectTimeout(5000,TimeUnit.MILLISECONDS)
                .writeTimeout(5000,TimeUnit.MILLISECONDS)
                /*.addInterceptor(new RetryInterceptor(1))*/
                .build();
        //创建一个Request:通过Request.Builder设置url(参数最起码有个url)、method、header等参数
        RequestBody formBody = httpBuilder.getBuilder().build();//MultipartBuilder可以构建复杂的请求体,即RequestBody requestBody = new MultipartBody.Builder()
        final Request request = new Request.Builder().url(path).post(formBody).build();
        //通过request的对象去构造得到一个Call对象(类似于将请求封装成了任务),可调用execute()和cancel()等方法
        Call call = mOkHttpClient.newCall(request);
        //请求加入调度队列,任务执行完成在Callback中即可得到结果:调用call.enqueue以异步的方式去执行请求(调用call.execute以同步阻塞的方式在主线程去执行请求)
        //注意:onFailure()和onResponse()是在异步线程里执行的,所以如果把更新UI的操作写在这两个方法里会报错,这个时候可以用runOnUiThread这个方法
        call.enqueue(new Callback() {
            @Override
            //当取消一个请求(调用cancel()),网络连接错误,或者超时都会回调
            public void onFailure(Call call, IOException e) {
                Log.v("Okhttp_onFailure",call.toString()+","+e.getMessage()+"");
                /*mOkHttpClient.dispatcher().cancelAll();//使用Call.cancel()可以立即停止掉一个正在执行的call*/
                mOkHttpClient.connectionPool().evictAll();//清除并关闭连接池
                httpRequestFail.onRequestFail(e);
                try {
                    if(Okhttp.this.activity instanceof LoginActivity){
                        LoginActivity activity = (LoginActivity)Okhttp.this.activity;
                        Message message = new Message();
                        if(e.getMessage().toString().contains("UnknownHostException")||e.getMessage().toString().contains("resolve")){//无法解析主机(1、IP越界)
                            message.what = UNKNOWN_HOST;
                        }else if(e.getMessage().toString().contains("SocketTimeoutException")||e.getMessage().toString().contains("after")){//连接超时(2、IP不越界且服务器已启动)
                            message.what = SOCKET_TIMEOUT;
                        }else if(e.getMessage().toString().contains("ConnectException")||e.getMessage().toString().contains("Failed")){//服务器连接出错(3、IP不越界且服务器未启动)
                            message.what = CONNECT_EXCEPTION;
                        }else if(e.getMessage().toString().contains("closed")||e.getMessage().toString().contains("Canceled")) {//主动取消
                            message.what = CLOSED;
                        }else {
                            message.what = UNKNOWN_ERROR;//其他情况
                        }
                        activity.getHandler().sendMessage(message);
                    }else if(Okhttp.this.activity instanceof MainActivity){
                        MainActivity activity = (MainActivity) Okhttp.this.activity;
                        Message message = new Message();
                        if(e.getMessage().toString().contains("UnknownHostException")||e.getMessage().toString().contains("resolve")){//无法解析主机(1、IP越界)
                            message.what = UNKNOWN_HOST;
                        }else if(e.getMessage().toString().contains("SocketTimeoutException")||e.getMessage().toString().contains("after")){//连接超时(2、IP不越界且服务器已启动)
                            message.what = SOCKET_TIMEOUT;
                        }else if(e.getMessage().toString().contains("ConnectException")||e.getMessage().toString().contains("Failed")){//服务器连接出错(3、IP不越界且服务器未启动)
                            message.what = CONNECT_EXCEPTION;
                        }else if(e.getMessage().toString().contains("closed")||e.getMessage().toString().contains("Canceled")) {//主动取消(测试未遇到到该情况)
                            message.what = CLOSED;
                        }else {
                            message.what = UNKNOWN_ERROR;//其他情况
                        }
                        activity.getHandler().sendMessage(message);
                    }else {
                        Log.v("Okhttp_elseFailure",call.toString()+" "+e.getMessage()+"");
                    }
                }catch (Exception e1){
                    e1.printStackTrace();
                }
            }

            @Override
            //请求成功时回调方法,response就是从服务器得到的参数
            public void onResponse(Call call, Response response) throws IOException {
                if(response.isSuccessful()){
                    //response.body()函数获得服务器返回的数据
                    // string()函数用来处理文本数据(传递文本数据),bytes()函数用来处理字节数组(收到小型文件数据,先以字节数据的形式保存在内存中,然后再将其一次性写入文件),byteStream()函数用来处理字节流(下载文件较大时,通过流的形式,将数据保存在文件中)
                    //由于OkHttp封装了okio,所以可以将响应数据通过BufferedSource的形式返回(断点续传功能),即response.body().source()
                    aa = response.body().string();
                    Log.v("Okhttp_response",call.toString()+" "+aa+"");
                    try{
                        httpRespone.onPostFinishedResponse(aa);

                        Gson gson = new Gson();
                        BB = gson.fromJson(aa,type);
                        httpRespone.onPostFinished(BB);
                    }catch (Exception e){
                        Log.v("Okhttp_onResponseErr",e.getMessage()+"");
                    }
                }else {
                    Log.v("Okhttp_UnexpectedCode",response+"");
                    throw new IOException("Unexpected code " + response);
                }
                response.close();//无论任何情况都要关闭该对象
            }
        });
        /*Log.v("Okhttp_call.equne",call.toString()+"");*/
        return (T)BB;
    }
    
    public interface HttpBuilder {
        FormBody.Builder getBuilder();
    }
    
    public interface HttpResponse {
        void onPostFinishedResponse(String response);
        void onPostFinished(Object object);
    }
    
    public interface HttpRequestFail{
        void onRequestFail(Exception e);
    }
   
}

备注:

因为是从已有的项目中拉出来的代码,可能有些资源文件没有上传,一般问题不大。有疑问的可随时留言,我会进行答复和补充代码。

你可能感兴趣的:(欢迎、登录和主页面间的跳转(2018.10.16))