Звоните в сеть api, так как активность заканчивается - PullRequest
0 голосов
/ 16 октября 2018

У меня есть экран настроек в моем приложении, и я хочу сохранить пользовательские настройки на сервере, но мне не нужна кнопка обновления в настройках, я надеялся сделать это обновление API-вызовом, когда действие заканчивается, может быть, я могу вызвать API в onPause (), проблема в том, что если API возвращает больше времени, чем ожидалось, чтобы вернуться, то у меня будет сетевой вызов без активности, которая, как я знаю, является утечкой памяти.Если я попытаюсь сделать этот сетевой вызов в основном потоке, и этот вызов займет слишком много времени, я получу ANR.Как я могу добиться такого поведения в моем приложении.Я использую retrofit2 с rxjava2 для выполнения вызовов API.

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Если вам нужен ответ (например, тост, чтобы сообщить пользователю, что настройки успешно сохранены), используйте IntentService, в противном случае Service.Для подробного описания различий см .: Сервис против IntentService .Для реализации (с хорошим примером) взгляните на: https://developer.android.com/guide/components/services и https://developer.android.com/guide/components/broadcasts (для реализации широковещательного приемника для обработки результата)

Вот простое приложение,В основной деятельности мы переходим к SecondActivity.Там мы устанавливаем некоторые значения, запускаем сервис для их обработки и завершаем действие.Когда все готово, MainActivity обновляется автоматически.

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="net.sytes.csongi.servicetest">

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".SecondActivity">
        </activity>

        <service
                android:name="services.MyIntentService"
                android:exported="false"
                >
        </service>
    </application>

</manifest>

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
        <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/main_result_txt"
                android:text="Test"/>
        <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:id="@+id/main_open_intent_btn"
                android:text="start"
                android:layout_gravity="center"/>
    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>

activity_second.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".SecondActivity">
<EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/second_edit_01_txt"
        android:hint="Enter some text here"/>
    <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/second_edit_02_txt"
            android:hint="another text here"/>
    <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/second_start_process_btn"
            android:text="start processing"
            android:layout_gravity="center"/>
</LinearLayout>

MainActivity.java:

package net.sytes.csongi.servicetest;

import android.content.*;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;

public class MainActivity extends AppCompatActivity {
 private static final String TAG=MainActivity.class.getSimpleName();

 private BroadcastReceiver mBroadcastReceiver;
 private IntentFilter mIntentFilter;
 @BindView(R.id.main_open_intent_btn)
 Button mOpenIntentBtn;
 @BindView(R.id.main_result_txt)
    TextView mResultTxt;

 public static final String ACTION_MAIN_ACTIVITY = "ACTION_MAIN_ACTIVITY";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        mIntentFilter=new IntentFilter();
        mIntentFilter.addAction(ACTION_MAIN_ACTIVITY);

        mBroadcastReceiver=new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d(TAG, "onReceive:::: called");
                String action=intent.getAction();
                if(action!=null&& ACTION_MAIN_ACTIVITY.equals(action)){
                    processReceivedIntent(intent);
                }
            }
        };
        registerReceiver(mBroadcastReceiver,mIntentFilter);

        mOpenIntentBtn.setOnClickListener(v->
        {
            Intent startSecondActivity=new Intent(this,SecondActivity.class);
            startActivity(startSecondActivity);
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy:::: called, unregistering Receiver");
        unregisterReceiver(mBroadcastReceiver);
    }

    private void processReceivedIntent(Intent intent) {
        Log.d(TAG, "processReceivedIntent:::: called");
        StringBuilder builder=new StringBuilder("The values recieved: \n");
        String returnedString=intent.getStringExtra(MyIntentService.EXTRA_TO_PROCESS);
        builder.append(returnedString);
        mResultTxt.setText(builder.toString());
    }
}

SecondActivity.java:

package net.sytes.csongi.servicetest;

import android.content.ContentValues;
import android.os.Bundle;
import android.support.annotation.StringDef;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import butterknife.BindView;
import butterknife.ButterKnife;
import services.MyIntentService;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_ONE;
import static net.sytes.csongi.servicetest.SecondActivity.ValuesToSend.EDIT_TEXT_TWO;

public class SecondActivity extends AppCompatActivity {

    private static final String TAG=SecondActivity.class.getSimpleName();

    @BindView(R.id.second_edit_01_txt)
    EditText mSecondEditOne;
    @BindView(R.id.second_edit_02_txt)
    EditText mSecondEditTwo;
    @BindView(R.id.second_start_process_btn)
    Button mStartProcess;

    @Retention(RetentionPolicy.SOURCE)
    @StringDef({EDIT_TEXT_ONE,
            EDIT_TEXT_TWO})
    public @interface ValuesToSend {
        /**
         * edit text key for textField_01
         */
        String EDIT_TEXT_ONE = "EDIT_TEXT_ONE";
        /**
         * edit text key for textField_02;
         */
        String EDIT_TEXT_TWO = "EDIT_TEXT_TWO";
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        ButterKnife.bind(this);

        mStartProcess.setOnClickListener(v -> {
            startProcess();
        });
    }

    private void startProcess() {
        Log.d(TAG, "startProcess:::: called");
        finish();
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.d(TAG, "onStop:::: called");
        ContentValues valuesToSend=new ContentValues();
        valuesToSend.put(EDIT_TEXT_ONE,mSecondEditOne.getText().toString());
        valuesToSend.put(EDIT_TEXT_TWO,mSecondEditTwo.getText().toString());
        Log.d(TAG, "onStop:::: contentValues size="+valuesToSend.size());
        Bundle toSend=new Bundle();
        toSend.putParcelable(MyIntentService.BUNDLE_CONTENT_VALUES_KEY,valuesToSend);
        MyIntentService.startActionProcess(this,toSend);
    }
}

MyIntentService.java:

package services;

import android.app.IntentService;
import android.content.ContentValues;
import android.content.Intent;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import net.sytes.csongi.servicetest.MainActivity;

import java.util.Iterator;
import java.util.Set;

/**
 * An {@link IntentService} subclass for handling asynchronous task requests in
 * a service on a separate handler thread.
 * <p>
 * helper methods.
 */
public class MyIntentService extends IntentService {

    private static final String TAG=MyIntentService.class.getSimpleName();

    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    public static final String ACTION_PROCESS = "services.action.PROCESS";

    public static final String BUNDLE_TO_PROCESS="BUNDLE_TO_PROCESS";
    public static final String BUNDLE_CONTENT_VALUES_KEY = "BUNDLE_CONTENT_VALUES_KEY";
    public static final String EXTRA_TO_PROCESS = "EXTRA_TO_PROCESS";

    public MyIntentService() {
        super("MyIntentService");
        Log.d(TAG, "MyIntentService:::: instantiated");
    }

    /**
     * Starts this service to perform action Foo with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    public static void startActionProcess(Context context, Bundle bundle) {
        Log.d(TAG, "startActionProcess:::: called");
        Intent intent = new Intent(context, MyIntentService.class);
        intent.setAction(ACTION_PROCESS);
        intent.putExtra(BUNDLE_TO_PROCESS, bundle);
        context.startService(intent);
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        Log.d(TAG, "onHandleIntent:::: called");
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_PROCESS.equals(action)) {
                final Bundle bundleToProcess = intent.getBundleExtra(BUNDLE_TO_PROCESS);
                handleAction(bundleToProcess);
            }
        }
    }

    private void handleAction(Bundle bundleToProcess) {
        // here we run the long process

        Log.d(TAG, "handleAction:::: called");
        ContentValues contentValues= bundleToProcess.getParcelable(BUNDLE_CONTENT_VALUES_KEY);
        StringBuilder builder=new StringBuilder("Processed values are:\n");
        int numberOfValues=contentValues.size();
        Set<String> valuesKeySet=contentValues.keySet();
        Iterator<String> iterator=valuesKeySet.iterator();
        while(iterator.hasNext()){
            builder.append(contentValues.getAsString(iterator.next())+"\n");
            try{  // simulating latency
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // send result to appropriate activity
        Intent resultIntent=new Intent();
        resultIntent.setAction(MainActivity.ACTION_MAIN_ACTIVITY);
        resultIntent.putExtra(EXTRA_TO_PROCESS,builder.toString());
        sendBroadcast(resultIntent);
    }
}

Надеюсь, я смогу вам помочь.

0 голосов
/ 16 октября 2018

Вы можете создать AsyncTask для работы в сети, так как doInBackground() создает фоновый поток, который вам нужен, чтобы избежать работы в сети на MainThread.Кроме того, остановка активности не останавливает AsyncTask.

...