Android - SharedPreferences между 2 приложениями не работает эффективно - PullRequest
0 голосов
/ 01 июня 2018

Я использую SharedPreferences в Android для обмена простыми данными между 2 приложениями в одном проекте.Моя цель - иметь «приложение конфигурации» (приложение A), чтобы сохранить некоторые значения и сделать их доступными для приложения B через общий файл, который используется классом SharedPreferences.Приложение A должно позволять пользователю обновлять значения при повторном запуске приложения, и приложение B должно видеть эти изменения.

Все мои приложения работают как одно и то же, объявив в обоих приложениях следующее:

android:sharedUserLabel="@string/user_id"
android:sharedUserId="sos.app"

Это позволяет моим приложениям использовать одни и те же данные.Итак, сначала я запускаю приложение A, затем я ввожу значения и фиксирую данные в файле.Затем я запускаю приложение B, получаю доступ к SharedPreferences через packageContent и правильно получаю свои значения.

Моя проблема возникает, когда я снова запускаю приложение A и приложение B для обновления значений.Все изменения сделаны правильно в приложении A (я видел изменения в sharedPreferences), но когда я снова запускаю приложение B, оно получает доступ к предыдущим значениям вместо новых.

Это довольно странно.Похоже, Android хранит мою ссылку на экземпляр sharedPreferences, и когда приложение B запускается снова, оно не переходит снова к общему файлу с помощью метода getSharedPreferences.

Это связанный код в приложении A:

//Instance of SharedPreferences made in onCreate method
sharedPreferences = getSharedPreferences("my.configuration.file", Context.MODE_PRIVATE)
//Function to insert values in sharedPreferences
fun addConfigItemToSharedPreferences(itemToBeSaved: String){

            with (sharedPreferences.edit()) {
                putString(keyItemsList[configItemToBeAddedCounter], itemToBeSaved)
                commit()
            }
        }

И это связанный код в приложении B (внутри метода onCreate):

val packageContext = createPackageContext("com.televes.angrod.configurationapp", 0)
val sharedPreferences = packageContext.getSharedPreferences("my.configuration.file", Context.MODE_PRIVATE)
val mapOfPreferences: Map<String, *> = sharedPreferences.all

Правильн ли мой подход или я буду использовать другой механизм для обмена данными между приложениями?

Ответы [ 3 ]

0 голосов
/ 01 июня 2018

Пожалуйста, используйте контент-провайдеры для обмена данными между приложениями.Это рекомендуемый шаблон Android: https://developer.android.com/guide/topics/providers/content-providers

0 голосов
/ 07 июня 2018

Я нашел свое собственное решение!

Наконец-то я решил объединить все свои приложения в одном.Я просто объявил каждое действие в одном и том же манифесте, а затем все они совместно используют один и тот же каталог файлов и разрешения.Я также использовал прямой доступ к файлам вместо общих настроек из-за моей проблемы с кэшированными значениями.Я также реализовал File Observer, чтобы получать уведомления в каждом приложении об изменениях файлов:

class FileObserver(val context: MyWatchFaceSOSApp.Engine, absolutePath: String) : FileObserver(absolutePath, FileObserver.MODIFY) {

    val TAG = "FileObserver"

    override fun onEvent(event: Int, path: String?) {

        //data was written to a file
        if (FileObserver.MODIFY and event != 0) {
            Log.i(TAG, "Wohoo. El archivo se ha actualizado!")
            Log.i(TAG, "Iniciando actualización de parámetros del WATCHFACE")
            context.cancelAndPurgePresenceReportService()
            context.updateConfigurationParams()
            context.setUpTimeBetweenPresenceReportMsgs()
            context.startPresenceReportService()
        }
    }
}

Так что теперь я использую File Manager с функциями чтения / записи.Я нашел это в переполнении стека и сделал свои собственные изменения.Просто для обмена:

public class FileManagerUtility {

    private static String TAG = "FileManagerUtility";

    public static void writeSettings(Context context, Map<String, String> watchSettings) {

        File appDirectory = new File(context.getFilesDir(), "watchsettings");
        String file = "settings.txt";

        if (!appDirectory.exists()) {
            appDirectory.mkdirs();
        }

        File fileName = new File(appDirectory, file);

        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        try {
            Log.i(TAG, "Escribiendo en fichero: " + fileName.getAbsolutePath());

            fos = new FileOutputStream(fileName);
            out = new ObjectOutputStream(fos);
            out.writeObject(watchSettings);
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                if (fos != null)
                    fos.flush();
                fos.close();
                if (out != null)
                    out.flush();
                out.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(TAG, "Se ha escrito correctamente en el fichero: " + fileName.getAbsolutePath());
            Log.i(TAG, "Contenido del fichero: " + watchSettings.toString());
        }
    }

    @SuppressWarnings("unchecked")
    public static Map<String, String> readSettings(Context context) {

        Map<String, String> watchSettings;

        File appDirectory = new File(context.getFilesDir(), "watchsettings");
        String file = "settings.txt";

        if (!appDirectory.exists()) return null; // File does not exist

        File fileName = new File(appDirectory, file);

        FileInputStream fis = null;
        ObjectInputStream in = null;
        try {
            Log.i(TAG, "Leyendo de fichero: " + fileName.getAbsolutePath());
            fis = new FileInputStream(fileName);
            in = new ObjectInputStream(fis);
            Map<String, String> myHashMap = (Map<String, String> ) in.readObject();
            watchSettings = myHashMap;
            return watchSettings;

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (StreamCorruptedException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {

            try {
                if(fis != null) {
                    fis.close();
                }
                if(in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

И это все!Я сохраняю каждое значение конфигурации на карте для быстрого доступа к данным, которые также легко читать / записывать из файлов.

Надеюсь, это поможет!

0 голосов
/ 01 июня 2018

Раньше вы могли решить эту проблему, изменив MODE_PRIVATE на MODE_WORLD_READABLE или MODE_WORLD_WRITABLE, но сейчас это устарело.

Из официальной документации (https://developer.android.com/training/data-storage/shared-preferences#GetSharedPreferences):

Внимание: MODE_WORLD_READABLE_ MODE_RADE_ MODE_RADE_ MODE_RADABLE_ MODE_RABE_ MODEрежимы устарели, начиная с уровня API 17. Начиная с Android 7.0 (уровень API 24), Android выдает исключение SecurityException, если вы их используете.Если вашему приложению требуется предоставить доступ к личным файлам другим приложениям, оно может использовать FileProvider с FLAG_GRANT_READ_URI_PERMISSION. Длядополнительную информацию см. также в разделе «Общий доступ к файлам».

Итак, вы должны использовать FileProvider сейчас.

Подробнее о FileProvider можно узнать здесь:

https://developer.android.com/reference/android/support/v4/content/FileProvider

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...