для работы в сети Я предлагаю вам использовать Retrofit2: Retrofit
В любом случае, чтобы выполнить сетевую операцию в другом потоке, вам нужно запустить новый AsyncTask из вашей деятельности и выполнить сетевые операции внутриЭто.В модификации все это намного проще!
(Извините, но у меня нет примера Kotlin для этого ниже!)
Пример Java без модификации:
(Это былоМой старый проект, так что он не так хорош ^^)
/* Really Simple Class I made to do networking operations (so use Retrofit or make a better one (: (I suggest you, again, to use Retrofit!) */
public class DBConnection {
public String performPostCall(String requestURL, HashMap<String, String> postDataParams )
{
URL url;
String response = "";
try {
url = new URL(requestURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(15000);
conn.setConnectTimeout(15000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
conn.setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
conn.connect();
DataOutputStream dStream = new DataOutputStream(conn.getOutputStream());
dStream.writeBytes(getPostDataString(postDataParams));
dStream.flush();
dStream.close();
int responseCode = conn.getResponseCode();
if (responseCode == HttpsURLConnection.HTTP_OK) {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line=br.readLine()) != null) {
response += line;
}
} else {
response = "";
}
conn.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return response;
}
private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException
{
StringBuilder result = new StringBuilder();
boolean first = true;
for(Map.Entry<String, String> entry : params.entrySet()){
if (first) {
first = false;
} else {
result.append("&");
}
result.append(entry.getKey());
result.append("=");
result.append(entry.getValue());
}
return result.toString();
}
}
// AsyncTask to do Async Networking operations:
public class YourTask extends AsyncTask<String, Void, String> {
private String yourData...;
public YourTask(String token){
// Set Your Data
}
// "String..." is an array of arguments so you get the arguments usign: params[i]
@Override
protected String doInBackground(String... params)
{
DBConnection dbConn = new DBConnection();
String stampAnswer;
try{
Integer param1 = Integer.parseInt(params[0]);
Integer param2 = Integer.parseInt(params[1]);
answer = dbConn.netwokirngOperation([..]);
}catch(NumberFormatException nfe){
nfe.getStackTrace();
stampAnswer = "";
Log.e("YourTask", " NumberFormatException:");
}
return answer;
}
protected void onPostExecute(String result) {
Log.e("YourTask => ", " Result:" + result);
}
}
// To call the task do in your activity and do async networking operation without wait for result (this mean you need to save the data inside Realm DB [REALM][2] or using SQLite DB and then get them when the networking operations ended (you can use an Observable and set it when the networking operation end, send a broadcast message and set a receiver in you activity, or any other method):
new YourTask(<put_here_your_asynctask_constructor_args>).execute(params);
// To call the task and do async networking operation but wait to get the result returned by the "doInBackground" method of the AsyncTask:
new YourTask(<put_here_your_asynctask_constructor_args>).execute(params).get();
Но лучше, если вы используете интерфейс и обратный вызов для возврата результата из AsyncTask, когда он закончился, пример:
/** in You Activity. Because in the Interface you use generic types (the 'T') you can specific the type of object returned by the interface inside the '<T>' if the interface WILL ALWAYS RETURN THE SAME OBJECT TYPE!
If it WILL RETURN DIFFERENT OBJECT TYPES you MUST don't specific the type inside the '<T>', but you have to cast the return inside a switch statement to know which object is returned (to do that you can add a 'int requestCase' to the interface so you know which case returned!) **/
public class YourActivity extends AppCompatActivity
implements IYourCallback<YourObjectTypesReturned>{
public interface IYourCallback<T>{
onNetOperationSuccess(List<T> answer)
onNetOperationError(Throwable t)
}
/** IMPLEMENTS HERE YOUR ACTIVITY BODY WITH THE INTERFACE METHODS ! **/
// Then call your AsyncTask where you want and pass it your context which implements the interface ( because you are in activity your context with the interface is "this"!
new YourTask(this).execute(params);
// Then inside your AsyncTask:
public class YourTask extends AsyncTask<String, Void, String> {
private IYourCallback mCallback;
public YourTask(Context context){
try{
mCallback = (IYourCallback) mCallback;
} catch(ClassCastException e){
onException(e); // Manage the exception and stop the operation
}
}
/** THEN IMPLEMENT YOU IN BACKGROUND... AND WHEN THE NETWORKING OPERATION IS FINISHED USE THE CALLBACK TO RETURN BACK YOUR RESULT, SO THE METHOD IN YOUR ACTIVITY WILL GET TRIGGERED AND YOU CAN CONTINUE TO DO YOUR OPERATIONS! So do: **/
if(success)
mCallback.onNetOperationSuccess(myListAnswer)
else
mCallback.onNetOperationError(error) // Throwable or exception
(Kotlin для реализации Retrofit! Я начал использовать Kotlin 5 дней назад, поэтому я не знаю, является ли это лучшим использованием (:)
Пример с Retrofit:
/* This is a RetrofitHelper which init the Retrofit instance and where you should put your networking methods. Then to do a networking operation you have to get this instance using (RetrofitHelper.getInstance().yourNetworkingOperation(...) ).
Anyway here there isn't the asynchronous part, you can get it in the link of my other comment below!
У меня еще нет этого класса! * / Class RetrofitHelper (baseUrl: String) {
private val TAG = this.javaClass.name
// Timeouts
private val CONNECT_TIMEOUT = "CONNECT_TIMEOUT"
private val READ_TIMEOUT = "READ_TIMEOUT"
private val WRITE_TIMEOUT = "WRITE_TIMEOUT"
// Header Names
private val BASE_REQ_HEADER_NAME = "BLEDataBinder"
private val REQ_HEADER_NAME = "$BASE_REQ_HEADER_NAME.Request"
private val REQ_HEADER_VERSION_NAME = "$BASE_REQ_HEADER_NAME.VersionName"
private val REQ_HEADER_VERSION_CODE = "$BASE_REQ_HEADER_NAME.VersionCode"
private val REQ_HEADER_DEVICE_IMEI = "$BASE_REQ_HEADER_NAME.DeviceIMEI"
private val REQ_HEADER_DEVICE_UNIQUE_ID = "$BASE_REQ_HEADER_NAME.DeviceUniqueID"
private val REQ_HEADER_DEVICE_MODEL = "$BASE_REQ_HEADER_NAME.DeviceModel"
private val REQ_HEADER_ANDROID_RELEASE = "$BASE_REQ_HEADER_NAME.AndroidRelease"
// Header Values
private val REQ_HEADER_VALUE = "emax"
// Labels
private val LABEL_INIT = "Init RetrofitHelper"
private var mBaseUrl: String
private var mGson: Gson
private var mRetrofit: Retrofit
companion object {
@Volatile private var mInstance: RetrofitHelper? = null
fun getInstance() = mInstance
fun initInstance(baseUrl: String): RetrofitHelper =
mInstance ?: synchronized(this){
mInstance ?: newInstance(baseUrl).also { mInstance = it }
}
private fun newInstance(baseUrl: String) = RetrofitHelper(baseUrl)
}
init {
LogUtils.iLog(TAG, "START $LABEL_INIT")
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor( getInterceptor() )
httpClient.addInterceptor( getLoggingInterceptor() )
this.mBaseUrl = baseUrl
mGson = getGson()
mRetrofit = getRetrofit(httpClient.build())
LogUtils.iLog(TAG, "END $LABEL_INIT")
}
/* START Private Methods */
private fun getRetrofit(httpClient: OkHttpClient): Retrofit{
return Retrofit.Builder()
.baseUrl(mBaseUrl)
.addConverterFactory(GsonConverterFactory.create(mGson))
.client(httpClient)
.build()
}
private fun getGson(): Gson{
return GsonBuilder()
.setDateFormat(Constants.DATETIME_FORMAT_DB)
.registerTypeAdapter(Boolean::class.javaObjectType, BooleanDeserializer())
.create()
}
private fun getLoggingInterceptor() =
HttpLoggingInterceptor {
getLoggingInterceptorLogger()
}.also { it.level = HttpLoggingInterceptor.Level.BODY }
private fun getLoggingInterceptorLogger() =
HttpLoggingInterceptor.Logger {
message -> HyperLog.v(TAG, message)
}
private fun getInterceptor(): Interceptor =
Interceptor {
buildInterceptorResponse(it)
}
private fun buildInterceptorResponse(chain: Interceptor.Chain): Response {
val builder: Request.Builder = chain.request().newBuilder().addHeader(REQ_HEADER_NAME, REQ_HEADER_VALUE)
setRequestHeaderVersionName(builder)
setRequestHeaderVersionCode(builder)
setRequestHeaderDeviceIMEI(builder)
setRequestHeaderDeviceUniqueID(builder)
setRequestHeaderDeviceModel(builder)
setRequestHeaderAndroidRelease(builder)
/* This part let you set custom timeout for different api call inside the "RetrofitAPI" interface using that labels: (example inside the RetrofitAPI interface)
public interface RetrofitAPI {
@Headers({RetrofitHelper.CONNECT_TIMEOUT + ":100000", RetrofitHelper.READ_TIMEOUT + ":100000"})
@FormUrlEncoded
@POST
Call<JsonObject> doBaseJsonRequest(@Url String url, @Field("params") String params);
}
*/
var connectTimeout = chain.connectTimeoutMillis()
var readTimeout = chain.readTimeoutMillis()
var writeTimeout = chain.writeTimeoutMillis()
val request = chain.request()
if(!TextUtils.isEmpty(request.header(CONNECT_TIMEOUT))){
connectTimeout = request.header(CONNECT_TIMEOUT)!!.toInt()
}
if(!TextUtils.isEmpty(request.header(READ_TIMEOUT))){
readTimeout = request.header(READ_TIMEOUT)!!.toInt()
}
if(!TextUtils.isEmpty(request.header(WRITE_TIMEOUT))){
writeTimeout = request.header(WRITE_TIMEOUT)!!.toInt()
}
builder.removeHeader(CONNECT_TIMEOUT)
builder.removeHeader(READ_TIMEOUT)
builder.removeHeader(WRITE_TIMEOUT)
return chain
.withConnectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.withReadTimeout(readTimeout, TimeUnit.MILLISECONDS)
.withWriteTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.proceed(builder.build())
}
/*private fun setRequestHeaders(builder: Request.Builder): Request.Builder{
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionName)){
builder.addHeader(REQ_HEADER_VERSION_NAME, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionCode.toString())){
builder.addHeader(REQ_HEADER_VERSION_CODE, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceIMEI)){
builder.addHeader(REQ_HEADER_DEVICE_IMEI, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceUniqueID)){
builder.addHeader(REQ_HEADER_DEVICE_UNIQUE_ID, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceModel)){
builder.addHeader(REQ_HEADER_DEVICE_MODEL, AppEnvironment.getInstance()!!.mVersionName!!)
}
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mAndroidRelease)){
builder.addHeader(REQ_HEADER_ANDROID_RELEASE, AppEnvironment.getInstance()!!.mVersionName!!)
}
return builder
}*/
private fun setRequestHeaderVersionName(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionName)){
builder.addHeader(REQ_HEADER_VERSION_NAME, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderVersionCode(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mVersionCode.toString())){
builder.addHeader(REQ_HEADER_VERSION_CODE, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceIMEI(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceIMEI)){
builder.addHeader(REQ_HEADER_DEVICE_IMEI, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceUniqueID(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceUniqueID)){
builder.addHeader(REQ_HEADER_DEVICE_UNIQUE_ID, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderDeviceModel(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mDeviceModel)){
builder.addHeader(REQ_HEADER_DEVICE_MODEL, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
private fun setRequestHeaderAndroidRelease(builder: Request.Builder){
if(!TextUtils.isEmpty(AppEnvironment.getInstance()!!.mAndroidRelease)){
builder.addHeader(REQ_HEADER_ANDROID_RELEASE, AppEnvironment.getInstance()!!.mVersionName!!)
}
}
/* END Private Methods */
}
ССЫЛКА НА МОЙ КОММЕНТАРИЙ ДЛЯ ИСПОЛЬЗОВАНИЯ ASYNC RETROFIT С МЕТОДАМИ ОБЩИХ ТИПОВ И ИНТЕРФЕЙСАМИ ВЫЗОВА:
RETROFIT ASYNC С ОБЩИМИ ТИПАМИ (Это на языке Java, но вы можете легко перевести его на Kotlin! Также я предлагаю вам изучить Java, потому что Kotlin - это язык сценариев, построенный на Java, так чтопереводит код в операциях Java, чьиometimes действительно больше (а иногда и медленнее), чем если бы вы писали код на Java!Итак, теперь я изучаю Kotlin после изучения Java для приложений Android, Kotlin - действительно хороший, умный, красивый и быстрый язык программирования для приложений, и я буду использовать его для создания быстрых и умных сценариев внутри моих приложений или для простых приложений, но ятакже будет использовать Java, потому что с его помощью вы сможете генерировать более быстрый код
Надеюсь, это полезно, пока и хорошего кодирования!(