Страницы

Поиск по вопросам

Показаны сообщения с ярлыком android-fragment. Показать все сообщения
Показаны сообщения с ярлыком android-fragment. Показать все сообщения

суббота, 11 апреля 2020 г.

Переход во фрагмент при нажатии на кнопку

#android_fragment #java #android

                    
Всем добрый вечер, уже какой день мучаюсь с этими фрагментами, все никак не могу
реализовать, например, у нас есть активити, на нем расположена кнопка, и при нажатии
на нее, сразу же открывается новое окно фрагмент.
Вот в этом приложении так реализовано.
https://play.google.com/store/apps/details?id=com.formul.fizik&hl=ru
Нажимаем и открывается.
Обновление
Дело в том, что реализовать переход из одного активити в другое активити, проблем
нет, но я никак не пойму, как с помощью фрагментов можно сделать быстрый переход, возьмем
тот же справочник, который выше. При нажатии на кнопку, мгновенно открывается содержание
определенной темы.
К сожалению ошибка http://joxi.ru/GrqBoweHQnpGmz
Ошибку исправил, но у меня получается при нажатии на фрагмент появляется фрагмент,
и кнопки остаются, и я могу нажать еще раз и еще раз на кнопку и так кол-во раз, появится
фрагмент.
Обновление 2
Я исправил импорт с import android.support.v4.app.Fragment; на import android.app.Fragment;
- ошибка пропала.
Я создал
layout: activity_main и fragment.
Fragment1.class и MainActivity
В Fragment.class я прописал 
public class Fragment1 extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
        return inflater.inflate(R.layout.fragment1, null);
    }
}

А в MainActivity заскринил http://joxi.ru/1A5J4n9tn0BprE.
Так же
fragment.xml http://joxi.ru/Y2LDVWqH9wyJ26
activity_main http://joxi.ru/l2ZYByVHwDKGmJ    


Ответы

Ответ 1



Принцип тут такой: 1) В разметке активити есть контейнер (FrameLayout, например) с id="yours_id". 2) В активити, при нажатии на кнопку, добавляем фрагмент в контейнер: Fragment yoursFragment=new YoursFragment(); FragmentTransaction trans=getFragmentManager().beginTransaction(); trans.add(R.id.yours_id, yoursFragment); trans.commit(); 3) Чтобы всё это работало, вам скорее всего придётся переделать всю логику активити под фрагменты (т.е. кнопка, запускающая открытие фрагмента тоже должна быть во фрагменте, и оба фрагмента должны быть в одном контейнере); Обновление Если же вы хотите, чтобы на экране "исчезали" все кнопки и 1-й фрагмент появлялся поверх всего, то вам надо сами кнопки встроить в другой фрагмент. Далее при старте активити добавлять фрагмент с кнопками (в FrameLayout), а при нажатии на одну из них делать trans.replace(R.id.yours_id, frag1); trans.addToBackStack(null); trans.commit(); Так у вас будет всё содержимое с экрана по нажатию кнопки заменяться на frag1, а при нажатии на кнопку "назад" показываться опять фрагмент с кнопками.

Ответ 2



Добрый вечер, @Verteletsky! Я понял Ваш вопрос и могу посоветовать почитать следующие статьи: Android 3. Fragments. Lifecycle Android 3. Fragments. Динамическая работа Android 3. Fragments. Взаимодействие с Activity и это: Android 3. Fragments. ListFragment - список Android 3. Fragments. DialogFragment - диалог Думаю, если Вам нужно вывести небольшое окно на экран, то Вам нужна ссылка №5. Если фрагмент на весь экран, то ознакомьтесь со ссылками №1-3. Ссылки ведут на уроки с сайта startandroid.ru. Рекомендую добавить данный сайт себе в закладки, в будущем пригодится. P.S.: рекомендую из личного опыта работы с сайтом. Иногда, конечно, материал подан как-то сжато, но для введения в вопрос и его достаточно.

Activity has been destroyed во время FragmentTransaction.commit()

#android #activity #android_fragment

                    
Пишу небольшую программку для андроида. Мне нужно создать программно фрагменты. Для
этого я написал отдельный класс с функциями
FragmentWorkHelper.java:

public class FragmentWorkHelper extends FragmentActivity {

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft;
public MainTopCompositeFragment mtcf = new MainTopCompositeFragment();
public MainCentralCompositeFragment mccf = new MainCentralCompositeFragment();
public MainBottomCompositeFragment mbcf = new MainBottomCompositeFragment();


public void ReplaceFrag(Fragment f, int container){
    ft = fragmentManager.beginTransaction();
    ft.replace(container, f);
    ft.commit();
}

public void RemoveFrag(Fragment f){
    ft = fragmentManager.beginTransaction();
    ft.remove(f);
    ft.commit();
}

public void AddFrag(Fragment f, int container){
    ft = fragmentManager.beginTransaction();
    ft.add(container, f);
    ft.commit();
}

public void CreateFrag(){
    ft = fragmentManager.beginTransaction();
    ft.add(R.id.main_top_fragment, mtcf);
    ft.add(R.id.main_central_fragment, mccf);
    ft.add(R.id.main_bottom_fragment, mbcf);
    ft.commit();
} }


Вызываю функции этого класса из различных мест программы, например в OnCreate() в
MainActivity.java:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    FragmentWorkHelper fwh = new FragmentWorkHelper();
    fwh.CreateFrag(); }


Но в итоге получаю вот что:

Process: developers.com.polygon, PID: 27767
java.lang.RuntimeException: Unable to start activity ComponentInfo{developers.com.polygon/developers.com.polygon.MainActivity}:
java.lang.IllegalStateException: Activity has been destroyed
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2693)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2758)
        at android.app.ActivityThread.access$900(ActivityThread.java:177)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1448)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:5942)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
 Caused by: java.lang.IllegalStateException: Activity has been destroyed
        at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1399)
        at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637)
        at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616)
        at developers.com.polygon.FragmentWorkHelper.CreateFrag(FragmentWorkHelper.java:43)
        at developers.com.polygon.MainActivity.onCreate(MainActivity.java:51)
        at android.app.Activity.performCreate(Activity.java:6289)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2646)


          
В чем беда? Почему активити уничтожается? Я пытался засунуть функции в MainActivity,
но выходит та же самая ошибка. Очень нужна помощь.
    


Ответы

Ответ 1



getSupportFragmentManager возвращает менеджер для взаимодействия фрагментов с activity из которой он вызван. Соответственно ваш хелпер бесполезен т.к. он может управлять фрагментами только внутри своей activity, а не во всех activity вашего приложения. Если хелпер вам так нужен то сделайте так public class FragmentWorkHelper{ private final FragmentActivity activity; public FragmentWorkHelper(FragmentActivity activity) { this.activity = activity; } public void replaceFrag(Fragment f, int container){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work } public void removeFrag(Fragment f){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work } public void addFrag(Fragment f, int container){ FragmentTransacion ft = activity.getSupportFragmentManager().beginTransaction(); //some work } } И тогда в activity в методе onCreate() создавайте экземпляр этого хелпера FragmentWorkHelper helper = new FragmentWorkHelper(this).

четверг, 9 апреля 2020 г.

Отображение ExpandedListView в Fragment

#java #android #android_fragment

                    
При добавлении списка типа ExpandedListView в фрагмент цвет текста элементов этого
списка устанавливается белым и, естественно, на белом фоне список почти не видно:

 

Попробовал добавить этот же список в активити, все отобразилось как надо:



Единственный выход(пока что) - смена цвета бекграунда списка(или лейаута,в котором
находится список). Но все же хотелось бы добиться отображения как на втором скриншоте.
Заранее спасибо!

Код лейаута, в котором находится список:

    
    
    
        
        
    



Код фрагмента:

public class ExercisesFragment extends Fragment{

    ExpandableListView elvMain;
    ExercisesAdapter EA;
    SimpleExpandableListAdapter adapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
        final View rootView = inflater.inflate(R.layout.exercises_fragment, container,
false);

        EA = new ExercisesAdapter(getActivity());
        adapter = EA.getAdapter();

        elvMain = (ExpandableListView) rootView.findViewById(R.id.elvMain);

        //elvMain.setBackgroundColor(getResources().getColor(R.color.black));
        elvMain.setAdapter(adapter);

        return rootView;
    }
}


Код ExercisesAdapter:

public class ExercisesAdapter {

    final String ATTR_GROUP_NAME= "groupName";
    final String ATTR_EXERC_NAME= "exerName";


    // названия групп упражнений
    String[] groups = new String[] {"Group 1", "Group 2", "Group 3", "Group 4","Group
5", "Group 6", "Group 7", "Group 8", "Group 9"};

    // названия упражнений
    String[] Group1 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group2 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group3 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group4 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group5 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group6 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group7 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group8 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};
    String[] Group9 = new String[] {"Exercise 1", "Exercise 2", "Exercise 3", "Exercise
4", "Exercise 5"};

    // коллекция для групп
    ArrayList> groupData;

    // коллекция для элементов одной группы
    ArrayList> childDataItem;

    // общая коллекция для коллекций элементов
    ArrayList>> childData;
    // в итоге получится childData = ArrayList

    // список аттрибутов группы или элемента
    Map m;

    Context ctx;

    ExercisesAdapter(Context _ctx) {ctx = _ctx;}

    SimpleExpandableListAdapter adapter;

    SimpleExpandableListAdapter getAdapter() {

        // заполняем коллекцию групп из массива с названиями групп
        groupData = new ArrayList>();
        for (String group : groups) {
            // заполняем список аттрибутов для каждой группы
            m = new HashMap();
            m.put(ATTR_GROUP_NAME, group); // имя группы
            groupData.add(m);
        }

        // список атрибутов групп для чтения
        String groupFrom[] = new String[] {ATTR_GROUP_NAME};
        // список ID view-элементов, в которые будет помещены аттрибуты групп
        int groupTo[] = new int[] {android.R.id.text1};

        // создаем коллекцию для коллекций элементов
        childData = new ArrayList>>();

        add(childData, Group1);
        add(childData, Group2);
        add(childData, Group3);
        add(childData, Group4);
        add(childData, Group5);
        add(childData, Group6);
        add(childData, Group7);
        add(childData, Group8);
        add(childData, Group9);

        // список аттрибутов элементов для чтения
        String childFrom[] = new String[] {ATTR_EXERC_NAME};
        // список ID view-элементов, в которые будет помещены аттрибуты элементов
        int childTo[] = new int[] {android.R.id.text1};

        adapter = new SimpleExpandableListAdapter(
                ctx,
                groupData,
                android.R.layout.simple_expandable_list_item_1,
                groupFrom,
                groupTo,
                childData,
                android.R.layout.simple_list_item_1,
                childFrom,
                childTo);

        return adapter;
    }

    public ArrayList>> add(ArrayList>> childData, String[] Group ){

        // создаем коллекцию элементов для первой группы
        childDataItem = new ArrayList>();
        // заполняем список аттрибутов для каждого элемента
        for (String exercise : Group) {
            m = new HashMap();
            m.put(ATTR_EXERC_NAME, exercise); // название упражнения
            childDataItem.add(m);
        }
        // добавляем в коллекцию коллекций
        childData.add(childDataItem);

        return childData;
    }
}

    


Ответы

Ответ 1



Задайте стиль для эелементов списка. У вас видимо textColorPrimary задан белым, вот и элементы списка с белым текстом. Как задать - стоит уже погуглить. По-другому вы не научитесь решать подобные проблемы

Ответ 2



Цвет текста по всей видимости наследуется от стиля, который у Вас определен в styles.xml Как вариант решения могу посоветовать указать в адаптере свою разметку adapter = new SimpleExpandableListAdapter( ctx, groupData, R.layout.my_expandable_list_item_1, groupFrom, groupTo, childData, R.layout.my_list_item_1, childFrom, childTo); А в ней уже менять все что душе угодно.

Ответ 3



У меня при добавлении ExpandedListView в Активити экстендс эктионБар, тоже цвет шрифта начинал сливатся с белым фоном, просто сменил разметку как советует ermak0ff Добавил my_expandable_list_item_1 и my_list_item_1 в папку layout, Там очень внимательным надо быть, во первых разметка как то не хотела через ctrl-v ctrl-c вставать, пришлось потихоньку со встреной разметки android.R.layout.simple_expandable_list_item_1 брать вьюшку и строить свои и как то все встало. Во вторых все ссылки правильно задать android.R.layout менять на R.layout там в коде эти ссылки не единыжды встречаются. В общем разметка заработала, цвет шрифта поменял.

Android/Java. Как отобразить активити в форме Диалога?

#android #android_fragment #activity #style #dialogfragment

                    
Необходимо отобразить активити в форме Диалога.. чтобы задний фон расплывчат был..
А у самой активити должны быть скругленные углы. 

Вот как на рисунке:



Как это делается? Что и В каких методах или файлах прописывать?
    


Ответы

Ответ 1



В манифесте пропиши у активити: Или просто сделай прозрачный фон, а на самой активити рисуй что хочешь. Для этого в манифесте пропиши:

Ответ 2



Создай layout для диалог-фрагмента. public class AddList extends DialogFragment implements Далее тебе нужно будет создать такой класс: public class extends DialogFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { AlertDialog.Builder adb = new AlertDialog.Builder(getActivity()); rootView = inflater.inflate(R.layout., container); adb.setView(rootView); return rootView; } } И внутри прописать всё, что нужно. А внутри нужного активити прописать: dialog = new (); dialog.show(getSupportFragmentManager(), "");

понедельник, 30 марта 2020 г.

Проблема с разметкой xml. Появляется непонятная белая полоска

#java #android #android_fragment




Подскажите что с этим делать.

Разметка Activity:

        
    

        

            

                
            

        

        

    


Разметка fragment:

    


    


        

            

            

            

        
    

    

    



    


Ответы

Ответ 1



Эта полоса представляет собой отступ и равняется высоте статус бара. Отвечает за это следующая строка: android:fitsSystemWindows="true" в разметке фрагмента. Решение - удалить данную строчку из разметки фрагмента.

вторник, 17 марта 2020 г.

Android orientation & DialogFragment

#java #android #android_fragment #android_edittext


Добрый день!
Проблема: при открытом DialogFragment при смене ориентации вылетает исключение. Сталкивался
ли кто-нибудь с подобным и есть ли методы решения? 
Также интересует: как отследить изменения в EditText не через TextWatcher? (Требуется
отловить лишь события набора текста, без события программного изменения.)
С уважением, Игорь.    


Ответы

Ответ 1



По поводу того, что вылетает exception при смене ориентации. Какое именно исключение? Покажите stacktrace. Попробуйте сделать следующее: добавьте setRetainInstance(true) в методе onCreateDialog(). Насчет того как отловить изменения в EditText, есть несколько способов. Можно сделать класс адаптер, который будет просто оберткой (заглушкой) методов интерфейса TextWatcher, соответственно вы сможете просто переопределить нужный Вам метод. Вообще вам нужно все равно будет использовать какой-то интерфейс слушателя. Возможен еще такой вариант с OnFocusChangeListener. Данный интерфейс имеет только один метод onFocusChange(View v, boolean hasFocus), сюда передается булевая переменная, которая показывает, был ли измен фокус данного View.

воскресенье, 15 марта 2020 г.

Обновление ListView после удаления item

#java #android #база_данных #listview #android_fragment


Здравствуйте. Никак не получается обновить ListView.

Он находится во фрагментах.

При добавлении записи все отлично, ListView обновляется.

Но после удаления приходится листать фрагменты влево, вправо, чтобы удаленные записи
пропали.

Надеюсь тут достаточно информации...

помогите пожалуйста!

Программист я так себе... Не ругайте сильно если че...

int currentPosition;
ListView lvSimple;
View view = inflater.inflate(R.layout.fragment, null);
Cursor c;

static PageFragment newInstance(int page) {
        currentPosition = page;
        PageFragment pageFragment = new PageFragment();
        Bundle arguments = new Bundle();
        arguments.putInt(ARGUMENT_PAGE_NUMBER, page);
        pageFragment.setArguments(arguments);
        return pageFragment;
    }

public void populateListView(int i) {
        c = myDB.getMonthRows();
        switch (i){
            case 0:
                c = myDB.getMonthRows();
                Log.d("ME", "0 block");
                break;
            case 1:
                Log.d("ME", "1 block");
                c = myDB.getAllRows();
                break;
            case 2:
                c = myDB.getMonthRows();
                Log.d("ME", "2 block");
                break;
            case 3:
                c = myDB.getMonthRows();
                Log.d("ME", "3 block");
                break;
        }
        String[] fromFieldNames = new String[]{DBAdapter.KEY_DATE, DBAdapter.KEY_AREA,
DBAdapter.KEY_PASSENGER};
        int[] toViewsID = new int[]{R.id.tvItemDate, R.id.tvItemArea, R.id.tvItemPassenger};
        SimpleCursorAdapter myC = new SimpleCursorAdapter(view.getContext(), R.layout.item,
c, fromFieldNames, toViewsID, 0);
        myC.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
            @Override
            public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
                if (columnIndex == 1) {
                    String createDate = cursor.getString(columnIndex);
                    textView = (TextView) view;
                    textView.setText(dateFormat(createDate));
                    return true;
                }
                return false;
            }
        });
        if(c!=null){
            c.requery();
        }
        lvSimple = (ListView)view.findViewById(R.id.lvSimple);
        myC.notifyDataSetChanged();
        lvSimple.setAdapter(myC);
        lvSimple.invalidateViews();
        registerForContextMenu(lvSimple);
    }

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo
menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        menu.add(0, CM_DELETE_ID, 0, R.string.delete_record);
    }

public boolean onContextItemSelected(MenuItem item) {
        if (item.getItemId() == CM_DELETE_ID) {
            // получаем из пункта контекстного меню данные по пункту списка
            AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
            // извлекаем id записи и удаляем соответствующую запись в БД
            myDB.deleteRow(acmi.id);
            myC.notifyDataSetChanged();
            populateListView(currentPosition);
            return true;
        }
        return super.onContextItemSelected(item);
    }

    


Ответы

Ответ 1



Пересоздавать адаптер не нужно. Т.е. вызов populateListView() лишний. notifyDataSetChanged() достаточно для обновления списка. Смысла в вызове invalidateViews() нет. Этот метод предназначен для обновления вьюшек, может быть вызван если меняются сами view (например, при переходе в action mode решите поменять фон или шрифты, отступы и т.д.), а не данные. Остальное правильное поведение при изменении данных осуществляется через notifyDataSetChanged(). В общем много лишнего, но даже решив проблему с обновлением, все равно придется переписывать. А именно, касаемо requery и прочего кода в олдскульном стиле, то правильная работа с курсорами и адаптерами нынче реализуется через Loader'ы (см. статья на StartAndroid'е). В частности комментарий к устаревшему методу requery говорит, что правильно пересоздавать курсор (в другом потоке) и вызывать adapter.changeCursor(newCursor). Выполняя requery (а изначально получив и передав в адаптер курсор) в основном потоке, вы можете получить ANR (скорее всего на новых api оно скоро просто не будет собираться)... Loader'ы помогают с этим делом.

Android Google Map v2 нарисовать маршрут

#java #android #google_maps_api #android_fragment #google_maps


У меня есть Google Map fragment:




Мое местоположение получаю вот так:

private void getMyLocation() {
    LatLng latLng = new LatLng(mMap.getMyLocation().getLatitude(), mMap.getMyLocation().getLongitude());
    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 16);
    mMap.animateCamera(cameraUpdate);
}


Нужно показать маршрут к заданным координатам, как на фото:

    


Ответы

Ответ 1



Помогла данная библиотека. Мой код: Route supportRoute = new Route(); LatLng source = new LatLng(mMap.getMyLocation().getLatitude(), mMap.getMyLocation().getLongitude()); LatLng dest= new LatLng(destLat, destLog); supportRoute.drawRoute(mMap, MapsActivity.this, source, dest, true, "en");

Ответ 2



Как вариант использовать библиотеку Google-Directions-Android

пятница, 13 марта 2020 г.

Как отключить отображение кнопки назад (DisplayHomeAsUpEnabled) в главном активити?

#android #activity #android_fragment


Есть активити и фрагмент в фрагменте стоит DisplayHomeAsUpEnabled. При переходе с
активити в фрагмент кнопка назад появляется все хорошо, но при нажатии и перехода назад
в активити стрелочка остается отображаеться? Как убрать?

Пробывал не помогло:

getSupportActionBar().setHomeButtonEnabled(false);

getSupportActionBar().setDisplayHomeAsUpEnabled(false);

getSupportActionBar().setHomeAsUpIndicator(null);


Код кнопки в фрагменте DisplayHomeAsUpEnabled:

@Override
    public void onResume()
    {
        super.onResume();
        ((ActionBarActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }


Код активити:

public class MainActivity extends ActionBarActivity implements ExpandableListView.OnChildClickListener,
View.OnClickListener {
    private static FragmentManager mManager;
    Button button1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        button1 = (Button) findViewById(R.id.button1);
        mManager = getSupportFragmentManager();

        getSupportActionBar().setIcon(R.drawable.ic_launcher);

        getSupportActionBar().setDisplayHomeAsUpEnabled(false);

       /* FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });*/

       // button1.setOnClickListener(this);
            button1.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Fragment fragment = null;


                mManager.findFragmentById(R.id.fragmentContainer);
                    if (fragment == null) {
                        fragment = new sovety_Fragment();
                        mManager.beginTransaction()
                                .add(R.id.fragmentContainer, fragment)
                                .replace(R.id.fragmentContainer, fragment)
                                .addToBackStack(null)
                                .commit();
                    }

            }


    });
    }



    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }
        if (id == android.R.id.home) { onBackPressed(); return true; }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {

        return false;
    }

    @Override
    public void onClick(View v) {

    }
}

    


Ответы

Ответ 1



Вы вызываете код, убирающий стрелку до того, как её показываете. Т.к. вы убираете фрагмент нажатием кнопки "назад" именно в слушателе её нажатия надо убирать стрелку. Засим попробуйте добавить обработчик нажатия кнопки назад в активити и именно в нём убрать стрелку: @Override onBackPressed() { getSupportActionBar().setDisplayHomeAsUpEnabled(false); super.onBackPressed(); }

Ответ 2



Вы вызываете getSupportActionBar().setDisplayHomeAsUpEnabled(false); (прячете кнопку назад) при создании активити, затем добавляете на активити фрагмент, в котором показываете эту кнопку, но вы не прячете её снова при удалении фрагмента. Так с чего бы она должна пропасть. Добавьте вот такой метод в активити: public void onBackPressed() { if (getSupportFragmentManager().getBackStackEntryCount() > 0) { getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount() > 1); getSupportFragmentManager().popBackStack(); } else { super.onBackPressed(); } }

Рамка (обводка) вокруг фрагмента

#java #android #android_fragment #android_layout


На первом скриншоте - то что я вижу в android studio. На втором - то что появляется
при запуске программы. Текст находится в layout-е фрагмента.
Как избавиться от белой рамки как на втором скрине? Layout имеет свойства match_parent.
Заранее спасибо.


    


Ответы

Ответ 1



Никогда не пользуйтесь предпросмоторщиком, встроенным в IDE - он полон багов и править их, скорее всего, никогда не будут, ибо им никто не пользуется, ибо он не нужен. Отступы, кои вы видите, где-то у вас в разметке. Ищите в коде/разметке активити/фрагмента margin и/или padding. Уберите их и отступы пропадут.

Android: правильное использование фрагментов и Navigation Drawer

#android #android_fragment #dialogfragment #android_navigation_drawer


Я использую в приложении шаблон Navigation Drawer Activity и у меня возникли несколько
вопросов по поводу правильного использования его и фрагментов в целом.


Т.к. все страницы (назову фрагменты, открываемые из бокового меню так) приложения
- фрагменты в одной активити, то я лишаюсь возможности использовать Intent для переключения
активиностей?
Как реализовать открытие фрагмента (какой-то страницы) по какому-то действию из другого
фрагмента? Сделать интерфейс, напримерIFragmentAction, со всеми событиями, которые
могут послать фрагменты, реализовать его у активити и вызывать эти методы из фрагментов?
А в них уже делать транзакции? Это правильно?
Аналогично, если нужно по действию во фрагменте показать фрагмент, не явлюящийся
"страницей" - надо делать аналогично, через активити? Или можно сделать транзакцию
прямо из фрагмента (в настоящий момент сделал так, но кажется это немного неправильно)
Если нужен режим для планшета, где некоторые фрагменты не открываются поверх старых,
а расположены рядом - надо создать новый layouyt еще одну активити, реализующую интерфейс,
но с другим поведением? Или это не самый правильный подход?
Как правильно вернуть результат из DialogFragment? Я реализовывал интерфейс у фрагмента,
который вызывал этот диалог, через который диалог устанавливал нужные значения. Кажется,
не лучший подход.
Столкнулся с такой проблемой: 
Если после нескольких смен фрагментов пользователь переходит через боковое меню на
другую страницу - он видит несколько наложившихся активностей. Если просто сделать
белый фон - задняя активность все равно останется кликабельной. 


Как правильно сделать переходы между активностями, чтобы не возникало таких проблем
и чтобы это было правильно?
    


Ответы

Ответ 1



Отвечу на всю историю примерным кодом. Пусть Ваш NavigationDrawer содержит кастомный адаптер для списка. При нажатии в списке на элемент вы к примеру получите йд нужного фрагмента, пусть это будет int, Но лучше строка. Получаем TAG Фрагмента. private String getTagById(int tagId) { String tag = null; if (Frag1.TAG_ID == tagId) { tag = Frag1.TAG; } else if (Frag2.TAG_ID == tagId) { tag = Frag2.TAG; } return tag; } Дальше в роль вступает участок кода для работы с фрагментами. В нем мы узнаем совпадает ли активный фрагмент с выбранным, если не совпадает мы сделаем detach активного, проверим открывали ли ранее выбранный и выполним replace или attach private void showFragment(String tag) { String oldTag = mSelectedTag; mSelectedTag = tag; final FragmentManager fm = getSupportFragmentManager(); final FragmentTransaction ft = fm.beginTransaction(); final Fragment oldFragment = fm.findFragmentByTag(oldTag); final Fragment fragment = fm.findFragmentByTag(tag); if (oldFragment != null && !tag.equals(oldTag)) { ft.detach(oldFragment); } if (fragment == null) { ft.replace(R.id.container, getContentFragment(tag), tag); } else { if (fragment.isDetached()) { ft.attach(fragment); } } ft.commit(); } Этот кусок кода отдает нужный фрагмент по тагу. private Fragment getContentFragment(String tag) { Fragment fragment = null; if (Frag1.TAG.equals(tag)) { fragment = new Frag1(); } else if (Frag2.TAG.equals(tag)) { fragment = new Frag2(); } return fragment; } А вот так все запускаем: @SuppressWarnings("StatementWithEmptyBody") @Override public boolean onNavigationItemSelected(MenuItem item) { showFragment(getTagById(item.getItemId())); DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer.closeDrawer(GravityCompat.START); return true; }

понедельник, 9 марта 2020 г.

Свой toolbar для каждого Fragment'a

#android #android_fragment


Использую несколько фрагментов, для которых есть отдельный тулбар. При добавлении
тулбара подсвечивается в студии ошибка "activity.getSupportActionBar.setTitle() may
produce java.nullpointerexeption". При этом фрагмент грузится, но все действия залипают,
на другие фрагменты он не переходит. Прошу подсказать в чем ошибка? 

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_three,container,false);
    Toolbar profile_toolbar = (Toolbar)view.findViewById(R.id.profile_toolbar);
    AppCompatActivity activity = (AppCompatActivity)getActivity();
    activity.getSupportActionBar().setTitle("dgdfg");
return view;
}


UPD. Ошибка крылась в использовании FragmentTabHost, почему-то вид с фрагментом залипал
на фрагменте с использование тулбара. Пришлось заменить FragmentTabHost на TabHost
    


Ответы

Ответ 1



Это не ошибка, а предупреждение Android Studio т.к. при определенных условиях метод getSupportActionBar() может вернуть null и вот тогда уже случится NullPointerException в вашем приложении. Чтобы это исключить, достаточно выполнить проверку на null. Тогда и студия перестанет пугать этим сообщением. ActionBar actionBar = activity.getSupportActionBar(); if(actionBar!= null) { //какой то код } Из-за этого скорей всего и залипают ваши фрагменты, т.к. вы только нашли ToolBar, но не установили его, потому getSupportActionBar() возвращает null. Попробуйте сделать так: @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_three,container,false); Toolbar profile_toolbar = (Toolbar)view.findViewById(R.id.profile_toolbar); AppCompatActivity activity = (AppCompatActivity)getActivity(); activity.setSupportActionBar(profile_toolbar); ActionBar actionBar = activity.getSupportActionBar(); if(actionBar!= null) { actionBar.setTitle("dgdfg"); } return view; }

воскресенье, 8 марта 2020 г.

Библиотека совместимости фрагментов

#android #android_fragment #android_support_library


Вопрос уточняющий. Фрагменты появились в 3й версии Андроид API 11, ориентируюсь я
на пользователей начиная с API 15 и выше. Значит не нужно использовать android.support.v4.app.Fragment?
Эта либа для поддержки фрагментов в версиях ниже 3, так же ведь?)
    


Ответы

Ответ 1



Если хотите использовать все современные возможности фрагментов, исправления и максимально одинаковое поведение на разных версиях андройда, то лучше использовать фрагменты и библиотеки поддержки. Смысл использовать родные фрагменты есть, только если у вас довольно маленькое приложение и вы хотите сделать его макимально маленьким). Нынче даже сама Android Studio по умолчанию при создании нового проекта с активити и фрагментами использует таковые из сапорт либы.

Ответ 2



Да всё верно. Получается так, что если вы хотите использовать фрагменты и покрывать устройства версии ниже чем API11, то необходимо использовать android.support.v4.app.Fragment. Если в этом нет нужды, используйте android.app.Fragment

понедельник, 24 февраля 2020 г.

java.lang.NullPointerException: Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim' on a null object reference [дубликат]

#java #android #android_fragment #fragment_transaction #fragment_manager


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Что такое Null Pointer Exception и как его исправить?
                                
                                    (4 ответа)
                                
                        
                                Закрыт 3 года назад.
            
                    
На Nexus 7 c Android 5.0(не 4.4) происходит крах с Exception из заголовка. После
непродолжительных поисков был найден следующий ответ. Меня он не устраивает, так как
в силу обстоятельств не могу отказаться от android.support.v4.app.  

Возможность операции над фрагментом, равным null, я тоже рассматривал, но такого
быть не должно. Отрывок кода под подозрением:  

String tag = FRAGMENT_STATE;
FragmentManager fragmentManager = getSupportFragmentManager();
...
stateFragment = new Fragment();
...
if (stateFragment != null) {
...
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();//.support.v4
transaction.replace(R.id.content_frame, stateFragment, tag);
...          
transaction.commitAllowingStateLoss();  


Еще есть следующий отрывок:

  //Типо подключаю фрагменты
  if(onerFragment == null) Logi.d("OneFragment is Null");
  //if (oneFragment == null || twoeFragment == null) {
  Logi.d("блок подключения фрагментов");
  fragmentTransaction = fragmentManager.beginTransaction();
  Logi.d("oneGragment constructer before");
  oneFragment = new OneGragment();
  fragmentTransaction.add(R.id.one_fragment, oneFragment);
  Logi.d("TwoFragment constructer before");
  twoFragment = new TwoFragment();
  fragmentTransaction.add(R.id.two_fragment, twoFragment);

  fragmentTransaction.commitAllowingStateLoss();  


Логи:


  FATAL EXCEPTION: main
   Process: название пакета, PID: 7755
   java.lang.NullPointerException: Attempt to write to field 'int android.support.v4.app.Fragment.mNextAnim'
on a null object reference
      at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:709)
      at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1501)
      at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:458)
      at android.os.Handler.handleCallback(Handler.java:739)
      at android.os.Handler.dispatchMessage(Handler.java:95)
      at android.os.Looper.loop(Looper.java:135)
      at android.app.ActivityThread.main(ActivityThread.java:5221)
      at java.lang.reflect.Method.invoke(Native Method)
      at java.lang.reflect.Method.invoke(Method.java:372)
      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)  


P.S Устройства у меня нет, логи взяты из GoogleTestLab, тестирование на эмуляторе
тоже не смогу. есть ли у кого-нибудь идеи что делать с этим "эксепшеном"?
    


Ответы

Ответ 1



Вот здесь сказано: Это происходит из-за того, что Вы вызываете методы remove(), add() и т.п. со значением null. Поразумевается, что replace() - это remove() и за ним add().

Смещение кнопок

#android #android_sdk #android_fragment


Есть панель, на которой находятся 3 кнопки, после какого-то события вторая кнопка
должна стать невидимой setVisibly(View.INVISIBLE), как сделать, чтобы после скрытия
второй кнопки, 3 кнопка стала на место второй, т.е. произошел сдвиг? Если есть, то
можно фрагмент кода
    


Ответы

Ответ 1



Попробуй вместо View.INVISIBLE использовать View.GONE, он в отличие от INVISIBLE обнуляет размер невидимой вьюхи.

Не работает onAttach

#java #android #android_fragment


Я создал ListFragment (знаю, что есть RecyclerView, просто книгу читаю). В методе
onAttach я пытаюсь получить ссылку на активность, чтобы вызывать ее метод. После первого
запуска — мое приложение не работало. После 10ти минут раздумий я нашел ошибку! onAttach(Context
context) не вызывается, а onAttach(Activity activity) (deprecated) — вызывается! Вот
методы:

@Override //РАБОТАЕТ
public void onAttach(Activity activity) {
    super.onAttach(activity);
    listener = (WorkoutListListener) activity;
}

@Override //НЕ РАБОТАЕТ
public void onAttach(Context context) {
    super.onAttach(context);
    listener = (WorkoutListListener) context;
}


Так в чем же разница этих двух методов? Почему устаревший работает, а обычный нет? 
    


Ответы

Ответ 1



Подробно на англо-саксонсом тут Кратко: ListFragment есть только в пакете android.app и добавляется в активити через FragmentManager вместо SupportFragmentManager. Из-за этого не используется метод onAttach(Context context) на устройствах с API<23, а используется onAttach(Activity activity) Решением может быть помечание обоих методов соответствующими аннотациями для вызова нужной версии на определённых уровнях API и делегирование продолжения логики в общий для всех API собственный метод, в коем вы уже можете кастовать контекст к активити (помня, что класс итоговой активити разнится в зависимости от уровня API (решение - кастовать к интерфейсу, реализуемому активити): /* * onAttach(Context) не вызовется до API 23 версии вместо этого будет вызван onAttach(Activity), коий устарел с 23 API * Так что вызовем onAttachToContext */ @TargetApi(23) @Override public void onAttach(Context context) { super.onAttach(context); onAttachToContext(context); } /* * устарел с 23 API * Так что вызовем onAttachToContext */ @SuppressWarnings("deprecation") @Override public void onAttach(Activity activity) { super.onAttach(activity); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { onAttachToContext(activity); } } /* * Вызовется в момент присоединения фрагмента к активити */ protected void onAttachToContext(Context context) { //здесь всегда есть контекст и метод всегда вызовется. //тут можно кастовать контест к активити. //но лучше к реализуемому ею интерфейсу //чтоб не проверять из какого пакета активити в каждом из случаев }

вторник, 18 февраля 2020 г.

Как правильно запустить SurfaceView в Fragment?

#android #android_fragment


Совсем недавно начал осваивать фрагменты и графику и не до конца понимаю их логику.

У меня есть фрагмент, во фрагменте должен запускаться DrawView extends SurfaceView
implements SurfaceHolder.Callback. Сейчас это какие-то там фигуры.

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by promoscow on 14.05.17.
 * Main activity for timer frame.
 */

public class Timer extends Fragment {

    DrawView drawView;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        DrawView drawView = new DrawView(getActivity());
//        getActivity().setContentView(drawView);
        Log.d("Timer.onCreate", String.valueOf(getActivity()));
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
        Log.d("Timer.onCreateView", String.valueOf(inflater));
        drawView = new DrawView(getActivity());
        return drawView;
    }

    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d("onActivityCreated", "okay");
    }

    private class DrawView extends SurfaceView implements SurfaceHolder.Callback {

        private DrawThread drawThread;

        public DrawView(Activity timer) {
            super(timer);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int
height) {
            Log.d("DrawView.surfaceChanged", "okay");
            drawThread = new DrawThread(getHolder());
            drawThread.setRunning(true);
            drawThread.start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            drawThread.setRunning(false);
            while (retry) {
                try {
                    drawThread.join();
                    retry = false;
                    Log.d("DrawView.surfDestroyed", "okay");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private class DrawThread extends Thread {
        private boolean running = false;
        private SurfaceHolder surfaceHolder;
        Paint paint;
        Rect rect;
        RectF rectF;
        Path path;

        public DrawThread(SurfaceHolder holder) {
            this.surfaceHolder = holder;
            paint = new Paint();
            rect = new Rect();
            path = new Path();
        }

        public void setRunning(boolean running) {
            this.running = running;
            Log.d("DrawThread.setRunning", "okay");
        }

        @Override
        public void run() {
            Log.d("DrawThread.run", "okay");
            Canvas canvas;
            while (running) {
            canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas(null);
                    if (canvas == null) continue;
                canvas.drawRGB(0, 100, 55);
                paint.setARGB(50, 56, 90, 124);
                paint.setStrokeWidth(10);
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawRect(rectF, paint);
                paint.setColor(Color.GREEN);
                canvas.drawArc(rectF, 10, 10, false, paint);
                Log.d("DrawThread.run", "onWork");
            } finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
            }
        }
    }
}


Логи вот такие:

05-14 22:26:02.158 14610-14610/ru.xpendence.development.gimstopwatch D/Timer.onCreate:
ru.xpendence.development.gimstopwatch.StopWatchActivity@2928c3c3
05-14 22:26:02.158 14610-14610/ru.xpendence.development.gimstopwatch D/Timer.onCreateView:
com.android.internal.policy.impl.PhoneLayoutInflater@15998504
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/resX: 1440
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/resY: 2392
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/calcDP: 350.0
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/density: 3.5
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/heightPixels: 2392
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/widthPixels: 1440
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/dpHeight: 683.4286
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/dpWidth: 411.42856
05-14 22:26:02.161 14610-14610/ru.xpendence.development.gimstopwatch D/onActivityCreated: okay


То есть, отрабатываются методы onCreate и onCreateView, потом отрабатываются методы
активити, в котором находится фрагмент (высчеты dp и проч), потом отрабатывает onActivityCreated
и всё...

Помогите, пожалуйста, желательно кодом.
    


Ответы

Ответ 1



Вообще если присмотреться, то Вы не проинициализировали переменную RectF rectF, но активно используете её в блоке try-finally. Я бы сделал ставку на то, что у Вас выпадает NullPointerException, но оно перехватывается этим блоком. А вообще пока не понятно зачем столько сложностей. Зачем использовать SurfaceView вместе со всеми вытекающими проблемами? Вот пример кода прямого наследника View, с тем же функционалом (были убраны неиспользуемые переменные) + регулировкой FPS: public class DrawView extends View { private static final long FPS = 25; private static final long TIME_DELAY = 1000 / FPS; private final Runnable mInvalidator = new Runnable() { @Override public final void run() { invalidate(); } }; private final Paint mPaint = new Paint(); { mPaint.setStrokeWidth(10); mPaint.setStyle(Paint.Style.STROKE); } private final RectF mRectF = new RectF(); public DrawView(Context context) { super(context); } public DrawView(Context context, AttributeSet attrs) { super(context, attrs); } public DrawView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public DrawView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected final void onDraw(final Canvas canvas) { super.onDraw(canvas); canvas.drawRGB(0, 100, 55); mPaint.setARGB(50, 56, 90, 124); canvas.drawRect(mRectF, mPaint); mPaint.setColor(Color.GREEN); canvas.drawArc(mRectF, 10, 10, false, mPaint); postDelayed(mInvalidator, TIME_DELAY); } } FPS в данном случае, это предпочитаемое FPS, совпадение с которым зависит от нагруженности UI. Если что-то более тяжелое планируется, то лучше использовать Bitmap, который будет подготавливаться в другом потоке, после чего выполнять отрисовку методомcanvas.drawBitmap(...).

воскресенье, 16 февраля 2020 г.

Как правильно запустить SurfaceView в Fragment?

#android #android_fragment


Совсем недавно начал осваивать фрагменты и графику и не до конца понимаю их логику.

У меня есть фрагмент, во фрагменте должен запускаться DrawView extends SurfaceView
implements SurfaceHolder.Callback. Сейчас это какие-то там фигуры.

import android.app.Activity;
import android.app.Fragment;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by promoscow on 14.05.17.
 * Main activity for timer frame.
 */

public class Timer extends Fragment {

    DrawView drawView;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        DrawView drawView = new DrawView(getActivity());
//        getActivity().setContentView(drawView);
        Log.d("Timer.onCreate", String.valueOf(getActivity()));
    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
        Log.d("Timer.onCreateView", String.valueOf(inflater));
        drawView = new DrawView(getActivity());
        return drawView;
    }

    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d("onActivityCreated", "okay");
    }

    private class DrawView extends SurfaceView implements SurfaceHolder.Callback {

        private DrawThread drawThread;

        public DrawView(Activity timer) {
            super(timer);
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int
height) {
            Log.d("DrawView.surfaceChanged", "okay");
            drawThread = new DrawThread(getHolder());
            drawThread.setRunning(true);
            drawThread.start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            drawThread.setRunning(false);
            while (retry) {
                try {
                    drawThread.join();
                    retry = false;
                    Log.d("DrawView.surfDestroyed", "okay");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private class DrawThread extends Thread {
        private boolean running = false;
        private SurfaceHolder surfaceHolder;
        Paint paint;
        Rect rect;
        RectF rectF;
        Path path;

        public DrawThread(SurfaceHolder holder) {
            this.surfaceHolder = holder;
            paint = new Paint();
            rect = new Rect();
            path = new Path();
        }

        public void setRunning(boolean running) {
            this.running = running;
            Log.d("DrawThread.setRunning", "okay");
        }

        @Override
        public void run() {
            Log.d("DrawThread.run", "okay");
            Canvas canvas;
            while (running) {
            canvas = null;
            try {
                canvas = surfaceHolder.lockCanvas(null);
                    if (canvas == null) continue;
                canvas.drawRGB(0, 100, 55);
                paint.setARGB(50, 56, 90, 124);
                paint.setStrokeWidth(10);
                paint.setStyle(Paint.Style.STROKE);
                canvas.drawRect(rectF, paint);
                paint.setColor(Color.GREEN);
                canvas.drawArc(rectF, 10, 10, false, paint);
                Log.d("DrawThread.run", "onWork");
            } finally {
                if (canvas != null) {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
            }
        }
    }
}


Логи вот такие:

05-14 22:26:02.158 14610-14610/ru.xpendence.development.gimstopwatch D/Timer.onCreate:
ru.xpendence.development.gimstopwatch.StopWatchActivity@2928c3c3
05-14 22:26:02.158 14610-14610/ru.xpendence.development.gimstopwatch D/Timer.onCreateView:
com.android.internal.policy.impl.PhoneLayoutInflater@15998504
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/resX: 1440
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/resY: 2392
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/calcDP: 350.0
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/density: 3.5
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/heightPixels: 2392
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/widthPixels: 1440
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/dpHeight: 683.4286
05-14 22:26:02.160 14610-14610/ru.xpendence.development.gimstopwatch D/dpWidth: 411.42856
05-14 22:26:02.161 14610-14610/ru.xpendence.development.gimstopwatch D/onActivityCreated: okay


То есть, отрабатываются методы onCreate и onCreateView, потом отрабатываются методы
активити, в котором находится фрагмент (высчеты dp и проч), потом отрабатывает onActivityCreated
и всё...

Помогите, пожалуйста, желательно кодом.
    


Ответы

Ответ 1



Вообще если присмотреться, то Вы не проинициализировали переменную RectF rectF, но активно используете её в блоке try-finally. Я бы сделал ставку на то, что у Вас выпадает NullPointerException, но оно перехватывается этим блоком. А вообще пока не понятно зачем столько сложностей. Зачем использовать SurfaceView вместе со всеми вытекающими проблемами? Вот пример кода прямого наследника View, с тем же функционалом (были убраны неиспользуемые переменные) + регулировкой FPS: public class DrawView extends View { private static final long FPS = 25; private static final long TIME_DELAY = 1000 / FPS; private final Runnable mInvalidator = new Runnable() { @Override public final void run() { invalidate(); } }; private final Paint mPaint = new Paint(); { mPaint.setStrokeWidth(10); mPaint.setStyle(Paint.Style.STROKE); } private final RectF mRectF = new RectF(); public DrawView(Context context) { super(context); } public DrawView(Context context, AttributeSet attrs) { super(context, attrs); } public DrawView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public DrawView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override protected final void onDraw(final Canvas canvas) { super.onDraw(canvas); canvas.drawRGB(0, 100, 55); mPaint.setARGB(50, 56, 90, 124); canvas.drawRect(mRectF, mPaint); mPaint.setColor(Color.GREEN); canvas.drawArc(mRectF, 10, 10, false, mPaint); postDelayed(mInvalidator, TIME_DELAY); } } FPS в данном случае, это предпочитаемое FPS, совпадение с которым зависит от нагруженности UI. Если что-то более тяжелое планируется, то лучше использовать Bitmap, который будет подготавливаться в другом потоке, после чего выполнять отрисовку методомcanvas.drawBitmap(...).

четверг, 13 февраля 2020 г.

Передать значение переменной из Activity в Fragment

#java #android #android_fragment




Пытаюсь сделать расписание занятий, но не очень получается. 
Есть два Java Class-а: MainActivity и ContentFragment(содержащий фрагмент), сделал
выпадающее меню в котором есть два значения "Первая неделя" и "Вторая неделя", при
нажатии на которые текст во фрагментах должен меняться соответственно.

Я пытался просто передать значение переменной itemPosition 

public boolean onNavigationItemSelected(int itemPosition, long itemId) {
    pos = itemPosition;
    Intent intent = new Intent(MainActivity.this, ContentFragment.class);
    intent.putExtra("pos", pos);
    return true; 


разными способами или просто получить её в ContentFragment классе 

MainActivity Main = new MainActivity(); 
int item = Main.pos;


Чтобы потом сравнивать её и писать соответствующий текст, если item = 0 - первой
недели, если = 1 - второй, но значение переменной так и не удалось получить. Оно постоянно
было = 0;

Вот и вопрос: как это реализовать? Или может есть до неприличия иной простой метод
решения моей задачи?
    


Ответы

Ответ 1



Предложу такой вариант решения Вашей задачи. В MainActivity Создаем интерфейс: interface MainActivityCommunicator{ void onWeekChanged(int numberOfWeek); } MainActivityCommunicator mSendToFragment; В методе onNavigationItemSelected добавляем строчку: public boolean onNavigationItemSelected(int itemPosition, long itemId) { ... mSendToFragment.onWeekChanged(itemPosition); ... } В ContentFragment Реализуем интерфейс MainActivityCommunicator public class ContentFragment extends ... implements MainActivity.MainActivityCommunicator{ ... @Override public void onWeekChanged(int numberOfWeek) { //Если выбранная неделя уже отображается, то return if(numberOfWeek == mCurrentSelectedWeek){ return; } //Тут меняем отображение недели } ... UPD: Указываем что данный фрагмент реализует данный интерфейс: @Override public void onAttach(Activity activity) { super.onAttach(activity); Context context = getActivity(); ((MainActivity) context).mSendToFragment = this; } Обnullяем ссылку на фрагмент когда он становится Detach: @Override public void onDetach() { super.onDetach(); Context context = getActivity(); ((MainActivity) context).mSendToFragment = null; }

Ответ 2



Можно использовать библиотеку EventBus и высылать событие смены недели из активити во фрагмент. В MainActivity просто высылаем соответствующий Event когда изменилась неделя public class MainActivity extends Activity { private void onWeekChange(int weekIndex) { EventBus().getDefault().post(new ChangeWeekEvent(weekIndex)); } } Во фрагменте обрабатываем следующим образом public class ContentFragment extends Fragment { public void onStart(){ EventBus.getDefault().register(this); //some code } public void onStop(){ EventBus.getDefault().unregister(this); //some code } //вызывается, когда из активити послали ивент public void onEvent(ChangeWeekEvent event){ //обрабатываем ивент } } Класс Event может выглядеть так: public class ChangeWeekEvent { private final int newWeek; //Другие поля public ChangeWeekEvent(int newWeek) { this.newWeek = newWeek; } }

Ответ 3



Я обычно использую для таких вещей адаптер FragmentPagerAdapter. public class MyActivity extends Activity { private MyAdapter myAdapter; private FragmentManager fm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.fragment_activity); pager = (ViewPager) findViewById(R.id.fragmentPager); fm = getSupportFragmentManager(); // Обработчик переключения между фрагментами ViewPager.SimpleOnPageChangeListener viewPagerListener = new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { super.onPageSelected(position); } }; pager.setOnPageChangeListener(viewPagerListener); // Класс, управляющий фрагментами myAdapter = new MyAdapter(fm); pager.setOffscreenPageLimit(2); pager.setAdapter(myAdapter ); } // Выбор пункта меню public boolean onNavigationItemSelected(int itemPosition, long itemId) { // В зависимости от выбранного пункта меню, мы можем передать любые свои данные в заданный фрагмент if (itemPosition == 0) { myAdapter.updateFragment(0); // Передаем данные в первый фрагмент (лучше завести именованные константы) } // и так далее... return true; } } В коде адаптера создаю нужное количество фрагментов. public class MyAdapter extends FragmentPagerAdapter { private Fragment[] fragments; public MyAdapter(FragmentManager fm) { super(fm); // Создаем нужное количество фрагментов (для индексации и доступа снаружи лучше завести публичные константы, чтобы не путаться в дальнейшем) fragments = new Fragment[2]; fragments[0] = new Fragment(); fragments[1] = new Fragment(); } @Override public Fragment getItem(int num) { if (num >= 0 && num < fragments.length) return fragments[num]; else return null; } @Override public int getCount() { return fragments.length; } /** * Обновить фрагмент * Дополнительными параметрами можно передать любые данные из активити */ public void updateFragment(int index) { fragments[index].updateData(); } } В дальнейшем любые данные можно передавать через новые методы адаптера. Но не стоит забывать о том, что в процессе работы фрагменты могут выгружаться из памяти, причем независимо от активити, поэтому надо предусмотреть случаи, когда фрагменты пересоздаются заново.

Android. Кнопка “назад” при использовании fragments

#android #android_fragment


Есть небольшое приложение, одно активити и штук 7 фрагментов, которые в нем располагаются,
для перехода к предыдущему фрагменту использую addToBackStack, все работает прекрасно
по аппаратной кнопке back. Но не понимаю как в action bar добавить кнопку назад, что
бы по клику возвращала на предыдущей фрагмент.
    


Ответы

Ответ 1



Добавить кнопку Назад: actionBar.setHomeButtonEnabled(true); Метод, возвращающий к предыдущему фрагменту: import android.support.v4.app.FragmentManager; public void onBackPressed() { FragmentManager fm = getActivity().getSupportFragmentManager(); if (fm.getBackStackEntryCount() > 0) fm.popBackStack(); else finish(); } Обработчик кнопки Назад: import android.view.MenuItem; @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; default: return super.onOptionsItemSelected(item); } }