I'm making a custom demo for a project that am part of, this is in order to contain the rules of work for this particular client.
So far useful links
http://stackoverflow.com/questions/14729630/sqlite-provider-in-visual-studio-2012
http://munnaondotnet.blogspot.mx/2011/07/edit-sqlite-database-using-visual.html
http://stackoverflow.com/questions/11291423/sqlite-with-visual-studio-2012-and-net-4-5
http://sqlserversamples.codeplex.com/
http://stackoverflow.com/questions/15084753/dbcontext-entityset-null-when-entities-are-set-to-internal-access/20652225#20652225
Translate
martes, 17 de diciembre de 2013
domingo, 1 de diciembre de 2013
Creando un sitio web ASP .Net. Parte 5
Para
continuar con la creación de nuestro sitio web vamos a crear una conexión con
la base de datos la cual nos va a permitir obtener información de la base que
creamos.
Crear un usuario en la base de datos
-- Create user for SQL Authentication
CREATE LOGIN clothesUsr WITH
PASSWORD = 'HolaMundo'
,DEFAULT_DATABASE = LuisClothes
GO
-- Add User to first database
USE
LuisClothes;
CREATE USER clothesUsr FOR
LOGIN clothesUsr;
EXEC sp_addrolemember 'db_datareader', 'clothesUsr'
EXEC sp_addrolemember 'db_datawriter', 'clothesUsr'
GO
Crear un rol para ejecución de procedimientos almacenados.
-- 1 - db_executestoredprocedures
-- 1a - Create role
CREATE ROLE db_produccion
GO
Una vez que terminemos la creación de nuestros
procedimientos y funciones almacenadas ejecutaremos las siguientes sentencias.
-- 1b - Grant permissions
GRANT EXECUTE TO
db_produccion
GO
También vamos a crear el rol para la selección de funciones.
-- 2 - db_selecttablevaluedfunctions
-- 2a - Create role
CREATE ROLE db_select_funtions
GO
Para dar permisos de
seleccion a nuestras funciones se ejecutara el siguiente script una vez que
terminemos la creacion de las funciones.
-- 2 - Create permissions
DECLARE
@Function_Name nvarchar(250);
DECLARE @CMDEXEC1 nvarchar(2000);
DECLARE db_cursor CURSOR FOR
SELECT [name]
FROM sys.objects
WHERE Type = 'TF'
OPEN
db_cursor
FETCH NEXT FROM db_cursor INTO @Function_Name
WHILE @@FETCH_STATUS =
0
BEGIN
SET @CMDEXEC1 = 'GRANT SELECT ON [' +
@Function_Name + '] TO
db_select_funtions;'
--- SELECT @CMDEXEC1
EXEC(@CMDEXEC1)
FETCH NEXT FROM db_cursor INTO
@Function_Name
END
CLOSE
db_cursor
DEALLOCATE
db_cursor
GO
Ahora vamos a crear algunos procedimientos almacenados como
por ejemplo la creación de un producto. Para esto en nuestro Object Explorer
vamos a dar clic derecho en stored procedures.
Con lo que nos a generar una plantilla para nuestro
procedimiento almacenado.
-- ================================================
-- Template generated from Template Explorer using:
-- Create Procedure (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- This block of comments will not be included in
-- the definition of the procedure.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE <Procedure_Name, sysname,
ProcedureName>
-- Add the parameters for the stored procedure here
<@Param1, sysname, @p1> <Datatype_For_Param1, , int> = <Default_Value_For_Param1, , 0>,
<@Param2, sysname, @p2> <Datatype_For_Param2, , int> = <Default_Value_For_Param2, , 0>
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
SELECT <@Param1, sysname, @p1>, <@Param2, sysname, @p2>
END
GO
Ahora solo tenemos que dar la definición de nuestro
procedimiento.
-- ================================================
-- Project Luis Clothes.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Roque
Rueda.
-- Create date: 24/11/2013
-- Description: Creates
a new product record in
--
the database. If you need to inser
-- a
new row you should give a -1
-- product
id(this is the default value)
-- =============================================
CREATE PROCEDURE Insert_Product (
-- stored procedure params
@product_id int
= -1,
@product_name nvarchar(150),
@product_price decimal(10, 2) = 1,
@product_photo nvarchar(2083),
@product_type int
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Update information or insert if not exists
UPDATE Product SET
Name = @product_name,
Price =
@product_price,
Photo =
@product_photo,
IdType =
@product_type
WHERE Id =
@product_id;
IF @@ROWCOUNT = 0 -- Check if the row was
updated.
INSERT INTO Product (Name,
Price,
Photo,
IdType,
CreationDate)
VALUES (@product_name, -- Name
@product_price, -- Price
@product_photo, -- Photo
@product_type, -- Typeid from
ProductType
GETDATE()); -- Gets the current date
-- Reset SET NONCOUNT
SET NOCOUNT OFF;
END
GO
Por que hacer store procedure para hacer los llamados a base
de datos. Supongamos que por algún motivo necesitamos saber qué fecha fue
modificado un producto. Por desgracia la tabla ya fue creada y nuestro programa
ya está utilizando. Algo como
lo siguiente:
string connectionString = "connection
Settings";
using (var conn = new SqlConnection(connectionString))
using (var command = new SqlCommand("InsertProduct", conn)
{
CommandType = System.Data.CommandType.StoredProcedure
})
{
conn.Open();
command.Parameters.AddWithValue("@product_id", 1);
...
command.Parameters.AddWithValue("@@product_type", 1);
command.ExecuteNonQuery();
conn.Close();
}
Para nuestra aplicación que está usando el procedimiento
almacenado lo que se debe hacer es nada... así es ya que solo se proporciona el
nombre y parámetros mientras la interfaz y el numero de parámetros se mantengan
igual no hay necesidad de cambiar.
-- Roque Rueda add a column to know when the produc
-- was modified.
ALTER TABLE Product
ADD
LastModified DATETIME
Si se agrega la columna lo único que debemos realizar es
agregar las sentencias necesarias en nuestro store procedure.
-- ================================================
-- Project Luis Clothes.
-- ================================================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Roque
Rueda.
-- Create date: 24/11/2013
-- Description: Creates
a new product record in
--
the database. If you need to inser
-- a
new row you should give a -1
-- product
id(this is the default value)
-- =============================================
ALTER PROCEDURE InsertProduct (
-- stored procedure params
@product_id int
= -1,
@product_name nvarchar(150),
@product_price decimal(10, 2) = 1,
@product_photo nvarchar(2083),
@product_type int
)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Update information or insert if not exists
UPDATE Product SET
Name = @product_name,
Price =
@product_price,
Photo =
@product_photo,
IdType =
@product_type,
LastModified =
GETDATE()
WHERE Id =
@product_id;
IF @@ROWCOUNT = 0 -- Check if the row was
updated.
INSERT INTO Product (Name,
Price,
Photo,
IdType,
CreationDate)
VALUES (@product_name, -- Name
@product_price, -- Price
@product_photo, -- Photo
@product_type, -- Typeid from
ProductType
GETDATE()); -- Gets the current date
-- Reset SET NONCOUNT
SET NOCOUNT OFF;
END
GO
Si se dan cuenta no se afectaría en ningún momento el código
de la aplicación. Es por eso que en este proyecto vamos a seguir este modelo,
aunque en algunos casos no utilicemos un store procedure, tratare de explicarle
el por qué no de uso.
jueves, 26 de septiembre de 2013
Creando una aplicación de libreta en Android (parte 2).
Vamos a continuar con la creación de la aplicación libreta usando AndroidStudio.
Pueden ver la publicación anterior (http://progrmrmalasmanas.blogspot.mx/2013/07/creando-una-aplicacion-de-libreta-en.html). En la ultima publicación se logro la creación de un archivo de texto
así como la lectura del mismo mostrando su contenido en una actividad.
Vamos a crear un método para crear el archivo en la tarjeta sd en lugar
de la memoria del teléfono y cambiar el nombre de los métodos que hemos creado;
para esto vamos a modificar la clase TextFile agregando esas nuevos metodos.
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
import
android.content.Context;
import
java.io.BufferedReader;
import java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.OutputStreamWriter;
/**
* Save a file using a text input also gets the
text of a file
* and presents as a string.
* Created by Roque Rueda on 25/06/13.
*/
public
class TextFile {
private Context mContext;
private static final String ENCODING =
"utf8";
public TextFile(Context ctx) {
mContext = ctx;
}
/**
* Create a file in the device file system.
* @param path Path where a new text file
is going to be created.
* @param content Text content of the file.
* @return True if the file can be created.
* @throws IOException if there's a problem
creating the new file.
*/
public boolean createFile(String path,
String content)
throws IOException {
FileOutputStream fileOutputStream =
mContext.openFileOutput(path, Context.MODE_PRIVATE);
OutputStreamWriter osw = new
OutputStreamWriter(fileOutputStream, ENCODING);
osw.write(content);
osw.flush();
osw.close();
return true;
}
/**
* Read the contents of the file and
returns as a string.
* @param path Path of the file that is
going to be read.
* @return Content of the file.
* @throws IOException if the file can't be
found or if there's a problem
* reading the content of he file.
*/
public String getFileContent(String path)
throws IOException{
StringBuilder content = new
StringBuilder(350);
FileInputStream fileInputStream =
mContext.openFileInput(path);
InputStreamReader isr = new
InputStreamReader(fileInputStream, ENCODING);
BufferedReader br = new
BufferedReader(isr);
String line;
while ((line = br.readLine()) != null){
content.append(line).append("\n");
}
fileInputStream.close();
return content.toString();
}
}
Vamos a editar nuestra clase para conseguir algo como lo
siguiente:
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
import
android.content.Context;
import
android.os.Environment;
import
android.util.Log;
import
java.io.BufferedReader;
import
java.io.File;
import
java.io.FileInputStream;
import
java.io.FileOutputStream;
import
java.io.FileReader;
import
java.io.IOException;
import
java.io.InputStreamReader;
import
java.io.OutputStreamWriter;
/**
* Save a file using a text input also gets the
text of a file
* and presents as a string.
* Created by Roque Rueda on 25/06/13.
*/
public
class TextFile {
private Context mContext;
private static final String ENCODING =
"utf8";
private static final String TAG =
"TextFile";
private static final String DIR =
"/textFiles";
private boolean mExternalStorageAvailable;
private boolean mExternalStorageWriteable;
public TextFile(Context ctx) {
mContext = ctx;
String state =
Environment.getExternalStorageState();
// We need to know if we can write to
external storage
if
(Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
mExternalStorageAvailable =
mExternalStorageWriteable = true;
} else if
(Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// Something else is wrong. It may
be one of many other states, but all we need
//
to know is we can neither read nor write
mExternalStorageAvailable =
mExternalStorageWriteable = false;
}
}
/**
* Create a file in the device file system.
* @param name Path where a new text file
is going to be created.
* @param content Text content of the file.
* @return True if the file can be created.
* @throws IOException if there's a problem
creating the new file.
*/
public boolean createFile(String name,
String content)
throws IOException {
OutputStreamWriter osw = null;
try
{
FileOutputStream fileOutputStream =
mContext.openFileOutput(name, Context.MODE_PRIVATE);
osw = new
OutputStreamWriter(fileOutputStream, ENCODING);
osw.write(content);
osw.flush();
Log.w(TAG, String.format("A
new file is created named:%s", name));
return true;
} finally {
osw.close();
}
}
/**
* Creates a file if can in the sd card of
this device, otherwise
* creates the file in the the internal
storage.
* @param name name of the file.
* @param content content of the file.
* @return true if the file can be created.
* @throws IOException if the file can't be
created.
*/
public boolean createSDFile(String name,
String content)
throws IOException {
// We can write in the sd storage.
if (mExternalStorageAvailable
&& mExternalStorageWriteable) {
OutputStreamWriter osw = null;
try
{
File sdCard =
Environment.getExternalStorageDirectory();
File dir = new File
(sdCard.getAbsolutePath() + DIR);
// Creates a new folder.
dir.mkdir();
File file = new File(dir,
name);
FileOutputStream
fileOutputStream = new FileOutputStream(file);
osw = new
OutputStreamWriter(fileOutputStream, ENCODING);
osw.write(content);
osw.flush();
Log.w(TAG,
String.format("A new file is created named:%s", name));
return true;
}
finally {
if (osw != null)
osw.close();
}
} else {
return createFile(name, content);
}
}
/**
* Reads the contents of a sd card file.
* @param name name of the file that is
going to be read.
* @return Contents of the file as string.
* @throws IOException if the file can't be
found.
*/
public String getSDFileContent(String name)
throws IOException
{
if (mExternalStorageAvailable) {
BufferedReader br = null;
try {
File sdCard =
Environment.getExternalStorageDirectory();
File dir = new File
(sdCard.getAbsolutePath() + DIR);
File file = new File(dir,
name);
// This object contains the
text will store the content of the file.
StringBuilder text = new
StringBuilder(400);
br = new BufferedReader(new
FileReader(file));
String line;
while((line = br.readLine()) !=
null) {
text.append(line).append('\n');
}
Log.w(TAG,
String.format("File %s is read", name));
return text.toString();
} finally {
if (br != null)
br.close();
}
}
else {
return getFileContent(name);
}
}
/**
* Read the contents of the file and
returns as a string.
* @param name Path of the file that is
going to be read.
* @return Content of the file.
* @throws IOException if the file can't be
found or if there's a problem
* reading the content of he file.
*/
public String getFileContent(String name)
throws IOException{
BufferedReader br = null;
try {
StringBuilder content = new
StringBuilder(350);
FileInputStream fileInputStream =
mContext.openFileInput(name);
InputStreamReader isr = new
InputStreamReader(fileInputStream, ENCODING);
br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) !=
null){
content.append(line).append("\n");
}
Log.w(TAG, String.format("File
%s is read", name));
return content.toString();
} finally {
if (br != null)
br.close();
}
}
}
Ahora vamos a editar nuestro
diseño de interfaz de usuario para permitir crear un nuevo archivo nombrarlo y
guardarlo. Una cuestión extra seria poder abrir y visualizar el contenido para
su edición si se desea. Vamos a crear un nuevo archivo layout.
Vamos a crear un nuevo elemento
al cual vamos a nombrar edit_text.xml en donde vamos a colocar el diseño básico
para editar y visualizar el texto.
<?xml
version="1.0" encoding="utf-8"?>
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/text"
android:inputType="textMultiLine"
android:layout_gravity="center"
android:text="@string/app_name"
android:gravity="left|top"/>
</GridLayout>
Así es como definimos el
fragmento. Ahora vamos a indicar las funciones para ese fragmento el cual solo
contiene el Widget EditText para que se vea el texto y este pueda ser editado.
Ahora ya tenemos la parte visual tenemos que generar la clase que será la que
dé el funcionamiento del fragmento de nuestra aplicación.
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import android.view.ViewGroup;
import
android.widget.EditText;
/**
* This fragment is used to show, edit and save
text into a txt file.
*
* Created by Roque on 28/07/13.
*/
public
class EditTextFragment extends android.support.v4.app.Fragment {
public static final String ARG_TEXT_FILE =
"myTextFile";
@Override
public View onCreateView(LayoutInflater
inflater, ViewGroup container,
Bundle
savedInstanceState) {
View rootView =
inflater.inflate(R.layout.edit_text, container, false);
EditText editText = (EditText)
rootView.findViewById(R.id.text);
if
(getArguments().containsKey(ARG_TEXT_FILE)){
editText.setText(getArguments().getString(ARG_TEXT_FILE));
}
return
rootView;
}
}
Vamos a modificar el método onNavigationItemSelected
de nuestra actividad principal NoteActivity.java para que sea algo como lo
siguiente:
@Override
public boolean onNavigationItemSelected(int
position, long id) {
// When the given dropdown item is
selected, show its contents in the
// container view.
Fragment fragment;
Bundle args = new Bundle();
switch (position){
case 0:{
fragment = new EditTextFragment();
String content = null;
try {
content =
mTextFile.getFileContent("test.txt");
} catch (IOException e) {
Log.w(TAG, e.getMessage());
}
args.putString(DummySectionFragment.ARG_TEXT_FILE, content);
break;
}
default:{
fragment = new
DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER,
position + 1);
break;
}
}
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container,
fragment)
.commit();
return
true;
}
Ejecutamos y en nuestro emulador veremos lo siguiente:
Como pueden ver ya se muestra un
Widget para editar el texto del documento ahora en la siguiente parte vamos a
ver como almacenar los cambios a nuestro documento de texto y la invocación de
los métodos para la escritura del archivo en la tarjeta sd.
En primer lugar vamos a generar
una clase con las constantes que estamos utilizando esto con el fin de evitar
tener dos veces la misma constante como en el caso de la clase DummySectionFragment
y EditTextFragment para evitar acoplamiento entre las clases. Vamos modificar
las llamadas a la constante con el siguiente codigo Constants.ARG_TEXT_FILE y nuestra clase quedara como la siguiente:
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
/**
* Contains the constants used in this
application.
*
* Created by Roque on 19/09/13.
*/
public
final class Constants {
/**
* This is the constant used to send data
between the fragments.
*/
public static final String ARG_TEXT_FILE =
"myTextFile";
private
Constants ()
{
// This is empty.
}
}
Ahora vamos a proceder a almacenar el texto que edite el
usuario cuando presione el menú deseamos que aparezca la opción de guardar.
Para esto vamos a navegar a nuestra NoteActivity para poder agregar el elemento
al menú. Nuestro menu se encuentra en el archivo res\menu\menu.xml, en este archivo vamos a agregar los elementos
que deseamos se muestren cuando se presione el botón de menú. Primero vamos a
agregar un nuevo string en nuestro archivo strings.xml
<string
name="action_save">Save</string>
Y posteriormente en nuestro archivo menu.xml
vamos a cambiar el texto de nuestro elemento en el menu como lo siguiente:
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/action_save"
android:title="@string/action_save"
android:orderInCategory="100"
android:showAsAction="never"
/>
</menu>
En nuestra activity vamos a manejar el evento que se dispara
cuando un elemento del menu es seleccionado para esto vamos a agregar el
siguiente método a nuestra clase:
@Override
public boolean onOptionsItemSelected(MenuItem
item){
switch(item.getItemId()){
}
return true;
}
Lo que vamos a hacer en este
metodo es del elemento del menu que es seleccionado vamos a obtener su id y
dependiendo del id es que vamos a realizar alguna acción en este caso guarda
los cambios de texto en el archivo. Para esto vamos a generar una interfaz la
cual va a ser nuestro contrato para recibir la información desde nuestros
fragmentos de la interfaz. Esto implica algunos cambios en nuestras clases DummySectionFragment
y EditTextFragment.
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
/**
* This interface defines behaviour to get user
text input.
*
* Created by Roque on 19/09/13.
*/
public
interface TextInput {
/**
* Returns the input of the user as text.
* @return user input.
*/
CharSequence getText();
}
En este caso la única
funcionalidad que se define es un método que retorna el texto que ingresa el
usuario. Este método debe ser implementado por los fragmentos de los que
deseamos obtener texto para almacenarlo en el archivo de texto. Quedando
nuestras clases de la siguiente manera:
/**
* A dummy
fragment representing a section of the app, but that simply
* displays
dummy text.
*/
public static class DummySectionFragment
extends Fragment implements TextInput {
/**
* The fragment argument representing
the section number for this
* fragment.
*/
public static final String
ARG_SECTION_NUMBER = "section_number";
private TextView mDummyTextView;
public DummySectionFragment() {
}
@Override
public View onCreateView(LayoutInflater
inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView =
inflater.inflate(R.layout.fragment_note_dummy, container, false);
mDummyTextView = (TextView)
rootView.findViewById(R.id.section_label);
if
(getArguments().containsKey(Constants.ARG_TEXT_FILE)){
mDummyTextView.setText(getArguments().getString(Constants.ARG_TEXT_FILE));
}
else {
mDummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
}
return rootView;
}
@Override
public CharSequence getText() {
return mDummyTextView.getText();
}
}
/*
* Copyright 2013 Roque Rueda.
*
* Licensed under the Apache License, Version
2.0 (the "License");
* you may not use this file except in
compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed
to in writing, software
* distributed under the License is distributed
on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.
* See the License for the specific language
governing permissions and
* limitations under the License.
*/
package
com.roque.rueda.notepad;
import
android.os.Bundle;
import
android.view.LayoutInflater;
import
android.view.View;
import android.view.ViewGroup;
import
android.widget.EditText;
/**
* This fragment is used to show, edit and save
text into a txt file.
*
* Created by Roque on 28/07/13.
*/
public
class EditTextFragment extends android.support.v4.app.Fragment implements TextInput
{
private EditText mEditText;
@Override
public View onCreateView(LayoutInflater
inflater, ViewGroup container,
Bundle
savedInstanceState) {
View rootView =
inflater.inflate(R.layout.edit_text, container, false);
mEditText = (EditText)
rootView.findViewById(R.id.text);
if
(getArguments().containsKey(Constants.ARG_TEXT_FILE)){
mEditText.setText(getArguments().getString(Constants.ARG_TEXT_FILE));
}
return rootView;
}
@Override
public CharSequence getText() {
return mEditText.toString();
}
}
Y nuestra actividad quedara como se muestra a continuación,
noten que se llama a la interfaz para obtener el texto del usuario no se llama
directamente a la actividad lo cual es posible pero no optamos seguir ese
camino.
public
class NoteActivity extends FragmentActivity implements
ActionBar.OnNavigationListener {
/**
* The serialization (saved instance state)
Bundle key representing the
* current dropdown position.
*/
private static final String
STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item";
private TextFile mTextFile;
private TextInput mTextInput;
private final static String TAG =
"NotePadRoque";
@Override
protected void onCreate(Bundle
savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note);
// Set up the action bar to show a
dropdown list.
final ActionBar actionBar =
getActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
// Set up the dropdown list navigation
in the action bar.
actionBar.setListNavigationCallbacks(
// Specify a SpinnerAdapter to
populate the dropdown list.
new ArrayAdapter<String>(
getActionBarThemedContextCompat(),
android.R.layout.simple_list_item_1,
android.R.id.text1,
new String[] {
getString(R.string.title_section1),
getString(R.string.title_section2),
getString(R.string.title_section3),
}),
this);
mTextFile = new TextFile(this);
try {
mTextFile.createSDFile("test.txt", "Hello World");
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Backward-compatible version of {@link
ActionBar#getThemedContext()} that
* simply returns the {@link
android.app.Activity} if
*
<code>getThemedContext</code> is unavailable.
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private Context
getActionBarThemedContextCompat() {
if (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return
getActionBar().getThemedContext();
} else {
return this;
}
}
@Override
public void onRestoreInstanceState(Bundle
savedInstanceState) {
// Restore the previously serialized
current dropdown position.
if
(savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) {
getActionBar().setSelectedNavigationItem(
savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM));
}
}
@Override
public void onSaveInstanceState(Bundle
outState) {
// Serialize the current dropdown
position.
outState.putInt(STATE_SELECTED_NAVIGATION_ITEM,
getActionBar().getSelectedNavigationIndex());
}
@Override
public boolean onCreateOptionsMenu(Menu
menu) {
// Inflate the menu; this adds items to
the action bar if it is present.
getMenuInflater().inflate(R.menu.note,
menu);
return true;
}
@Override
public boolean
onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case R.id.action_save:
try
{
mTextFile.createSDFile("test.txt",
mTextInput.getText().toString());
}
catch (IOException ioex)
{
Toast.makeText(this,
ioex.getMessage(), Toast.LENGTH_SHORT).show();
}
return true;
}
return false;
}
@Override
public boolean onNavigationItemSelected(int
position, long id) {
// When the given dropdown item is
selected, show its contents in the
// container view.
Fragment fragment;
Bundle args = new Bundle();
switch (position){
case 0:{
fragment = new EditTextFragment();
String content = null;
try {
content =
mTextFile.getSDFileContent("test.txt");
} catch (IOException e) {
Log.w(TAG, e.getMessage());
}
args.putString(Constants.ARG_TEXT_FILE, content);
break;
}
default:{
fragment = new
DummySectionFragment();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
break;
}
}
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container,
fragment)
.commit();
mTextInput = (TextInput) fragment;
return true;
}
Asi mismo hay que agregar el permiso de escritura externa en
nuestro Android manifest
<?xml
version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.roque.rueda.notepad"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14"
/>
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".NoteActivity"
android:label="@string/app_name" >
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Y ahora vamos a ejecutar nuestra aplicacion.
Suscribirse a:
Entradas (Atom)