Skocz do zawartości
Coders Lab

Nowy widget i przekazanie mu danych z activity

    Rekomendowane odpowiedzi

    Do stworzenia tego poradnika użyłem

    1. Android Studio 3.1.3
    2. Java w wersji  8
    3.  Min SKD 22
    4. Kotlin
    5. Kotlin Android Extensions

    Pokazuje on w jaki sposób użyć SharedPreferences aby przekazać dane z activity do klasy konfigurującej widget.

    Na początku mamy stworzony projekt z pustą aktywnością. Klikamy prawym przyciskiem na nazwę naszego pakietu i wybieramy: New -> Widget -> App Widget
    image.png.24a0ce5c7c753c0f8f0ff96e09836f93.png

    W nowym oknie wybieramy nazwę widgetu i  podstawowe informacje na jego temat.

    image.png.673c1757cd15d292c5e4efa0f336ac49.png

    Zaznaczamy Configuration Screen, a resztę opcji możemy pozostawić bez zmian. Po kliknięciu Finish doda kilka nowych plików do projektu. W tym przypadku będą to klasy: NewAppWidget.kt i NewAppWidgetConfigureActivity.kt oraz dwa odpowiadające im pliki w layout: new_app_widget.xml i new_app_widget_configure.xml

    Struktura projektu w tej chwili wygląda następująco:
    image.png.48e830cfe3ac4aa65abca1f40c3031b5.png

    Jeżeli wybraliśmy język kotlin to w klasie NewAppWidgetConfigureActivity będzie pokazywało nam błąd Property must be initialized or be abstract:

    image.png.070cc21c38235566d7bc5c23a66f05d5.png

    Jest to problem z konwersją kodu javy na kotlin. Niestety to narzędzie nie działa idealnie. Aby szybko poradzić sobie z tym błędem tą linię zmieniamy na:

    internal lateinit var mAppWidgetText: EditText

    W tej chwili powinniśmy być w stanie uruchomić nasz widget na emulatorze lub na prawdziwym urządzeniu.

    Po instalacji apk otworzy nam się aplikacja z napisem "Hello World" (jeżeli wybraliśmy empty activity przy tworzeniu projektu)  - możemy ją zamknąć. Przechodzimy na ekran główny. Przytrzymujemy palec lub kliknięcie (w przypadku emulatora ) na głównym ekranie. Pojawia nam się menu do wyboru tapety, widgetu,  lub ustawień.

    image.png.702cf720195f90643fb08847bebedf6a.png

    Wybieramy Widgets, zjeżdżamy na sam dół i widzimy nasz widget:

    image.png.94ad93571e1cac9ebf688dfc70a75fa7.png

    Po przytrzymaniu możemy go przenieść na ekran główny i skonfigurować za pomocą activity NewAppWidgetConfigureActivity.

    No i właśnie, aby przekazać dane z naszej aplikacji, a konkretnie z MainActivity musimy:
    W activity_main.xml utworzyć layout z EditText i Button:
     

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
    
        <TextView
            android:id="@+id/textView2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Dodaj do konfiguracji" />
    
        <EditText
            android:id="@+id/config_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:inputType="text"
            app:layout_constraintTop_toBottomOf="@+id/textView2"/>
    
        <Button
            android:id="@+id/add_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Dodaj"
            app:layout_constraintTop_toBottomOf="@+id/config_text" />
    
    
    </android.support.constraint.ConstraintLayout>

    Następnie w samej MainActivity:

    
    import android.content.Context
    import android.content.SharedPreferences
    import android.os.Bundle
    import android.support.v7.app.AppCompatActivity
    import kotlinx.android.synthetic.main.activity_main.*
    
    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            add_button.setOnClickListener { save(this) }
        }
    
        val PREFS_FROM_MAIN = "OPEN_IN_CONFIG_WIDGET"
        val PREFS_MAIN_KEY = "PREFS_String"
    
         fun save(context: Context) {
            val configText = config_text.text
            val settings  = context.getSharedPreferences(PREFS_FROM_MAIN, Context.MODE_PRIVATE)
            val editor: SharedPreferences.Editor
    
            editor = settings.edit()
    
            editor.putString(PREFS_MAIN_KEY, configText.toString())
            editor.apply()
        }
    }

    za pomocą metody save(context: Context) uruchamianej po kliknięciu na add_button (ma ustawionego listenera w onCreate: add_button.setOnClickListener { save(this) } ) do SharedPreferences dodawany jest text z EditText o nazwie config_text.

    Kolejnym krokiem jest odebranie tego tekstu w NewAppWidgetConfigureActivity. Tutaj wystarczy zmodyfikować metodę OnCreate:

     //pola pozwalające dobrać się do zapisanego stringa
        val PREFS_FROM_MAIN = "OPEN_IN_CONFIG_WIDGET"
        val PREFS_MAIN_KEY = "PREFS_String"
    
        public override fun onCreate(icicle: Bundle?) {
            super.onCreate(icicle)
    
            // Set the result to CANCELED.  This will cause the widget host to cancel
            // out of the widget placement if the user presses the back button.
            setResult(Activity.RESULT_CANCELED)
    
            setContentView(R.layout.new_app_widget_configure)
            mAppWidgetText = findViewById<View>(R.id.appwidget_text) as EditText
            findViewById<View>(R.id.add_button).setOnClickListener(mOnClickListener)
    
            // Find the widget id from the intent.
            val intent = intent
            val extras = intent.extras
            if (extras != null) {
                mAppWidgetId = extras.getInt(
                        AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID)
            }
    
            // If this activity was started with an intent without an app widget ID, finish with an error.
            if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
                finish()
                return
            }
            
            //Pobranie zapisanej wartości
            val settings: SharedPreferences = this.getSharedPreferences(PREFS_FROM_MAIN, Context.MODE_PRIVATE)
            val textFromMain: String?
    
            textFromMain = settings.getString(PREFS_MAIN_KEY, null)
            
            if (textFromMain.isNullOrEmpty())
                mAppWidgetText.setText(loadTitlePref(this@NewAppWidgetConfigureActivity, mAppWidgetId))
            else
                mAppWidgetText.setText(textFromMain)
        }

    Gotowe! Teraz po odpaleniu aplikacji widzimy (wpisałem już tekst: ANDROID.COM.PL 😞
    image.png.de135c5dacae5e8b14fdeb70a7e3cbb1.png

    Po kliknięciu dodaj przechodzimy do wyboru widgetu. Przeciągamy go na ekran główny i widzimy:

    image.png.03f4d11a868f630f58a05440a9d6dd7a.png

    Nasz tekst został przekazany do activity konfigurującej widget! Klikamy ADD WIDGET i na ekranie głównym dodaje nam się widget z naszym tekstem:
    image.png.f79d634e816a0b6d1d4eb71fc449fcb6.png

     

    dodana zawartość

    Ten tutorial pokazał w jaki sposób przekazywać za pomocą SharedPreferences typ prosty jakim jest String. Aby przekazywać bardziej złożone obiekty należy posłużyć się biblioteką Gson aby zamienić object na json: 

      val settings = context.getSharedPreferences(PREFS_FROM_MAIN, Context.MODE_PRIVATE)
            val editor: SharedPreferences.Editor
            val myObject = MyObject()
            editor = settings.edit()
            val gson = Gson()
            val json = gson.toJson(MyObject)
    
            editor.putString(PREFS_MAIN_KEY, json)
            editor.apply()

    Odbieranie obiektu w analogiczny sposób:

            val gson = Gson()
            val json = editor.getString(PREFS_MAIN_KEY, "")
            val obj = gson.fromJson(json, MyObject::class.java)

     

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach
    wAJT43

    W jaki sposób mogę zamienić List<MyObject> na ArrayList<String> aby wyświetlić ją w LIstView. Na stack-u np.  List<MyObject> zamieniają na String[] a potem na ArrayList ale coś u mnie się nie zgadza. Teraz gdy w listView wyświetlam List<MyObject> w każdym z itemów pojawia się mój_package+model+MyObject@... zamiast odpowiedniego stringu. List<MyObject> jest zapisana w Jsonie.

     

    Piękna sprawa😅😅 Po małej przerwie od monitora udało mi się ogarnąc samemu :) i w dodatku znalazłem temat na forum https://stackoverflow.com/questions/41350269/my-listview-is-showing-the-object-and-not-the-contents-of-each-object

    Napisał mój adapter do listy:

    public class ListWidgetAdapter extends ArrayAdapter<MyClass> {
    
        private List<MyClass> myList;
        public ListWidgetAdapter(@NonNull Context context, int resource, List<MyClass> myList) {
            super(context, resource);
            this.myList = myList;
        }
    
    
        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            MyClass item = myList.get(position);
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.widget_list_items, parent, false);
            }
    
            TextView itemTextView = convertView.findViewById(R.id.textView_list);
            itemTextView.setText(item.getTask());
    
            return convertView;
        }
    
    
        @Override
        public int getCount() {
            return myList.size();
        }
    
    }
    Edytowane przez wAJT43

    Udostępnij tę odpowiedź


    Odnośnik do odpowiedzi
    Udostępnij na innych stronach

    Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

    Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

    Zarejestruj nowe konto

    Załóż nowe konto. To bardzo proste!

    Zarejestruj się

    Zaloguj się

    Posiadasz już konto? Zaloguj się poniżej.

    Zaloguj się

    • Przeglądający   0 użytkowników

      Brak zarejestrowanych użytkowników przeglądających tę stronę.